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 SkillFern v1.4.0
SkillFern.dll
Decompiled a month agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using ExitGames.Client.Photon; using HarmonyLib; using Newtonsoft.Json; using Photon.Pun; using Photon.Realtime; using REPOLib; using REPOLib.Modules; using SkillFern.Custom; using SkillFern.Networking; using SkillFern.UI; using SkillFern.Unity; using SkillFern.Utilities; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("SkillFern")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("SkillFern")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("2317c45d-9d42-4c50-aeed-5f05c5bf5865")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace SkillFern { [BepInPlugin("com.dajadeninja.repo.skillfern", "Skill Fern", "0.0.0")] public class Plugin : BaseUnityPlugin { public static Plugin instance; private Harmony harmony; private void Awake() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown instance = this; harmony = new Harmony("com.dajadeninja.repo.skillfern"); ((BaseUnityPlugin)instance).Logger.LogInfo((object)"Setting up configuration. . ."); ConfigHelper.Initialize(((BaseUnityPlugin)this).Config); LogInfo("Loaded successfully! Loading patches. . ."); harmony.PatchAll(); LogInfo("Patches loaded"); AssetHelper.LoadBundles(); LogInfo("Newest 33"); } public static void LogInfo(string msg) { if (ConfigHelper.EnableDebug()) { ((BaseUnityPlugin)instance).Logger.LogInfo((object)("Skill Fern: " + msg)); } } public static void LogError(string msg) { if (ConfigHelper.EnableDebug()) { ((BaseUnityPlugin)instance).Logger.LogError((object)("Skill Fern: " + msg)); } } } } namespace SkillFern.Utilities { public class AssetHelper { public static AssetBundle bundle; public static bool loaded; public static void LoadBundles() { BundleLoader.LoadBundle(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "SkillFern.bundle"), (Func<AssetBundle, IEnumerator>)OnBundleLoaded, true); } private static IEnumerator OnBundleLoaded(AssetBundle bundle) { Plugin.LogInfo("Assets successfully loaded!"); AssetHelper.bundle = bundle; loaded = true; yield break; } public static IEnumerator RegisterMenus(MenuManager menuManager) { yield return (object)new WaitUntil((Func<bool>)(() => loaded)); Plugin.LogInfo("Registering menu pages..."); menuManager.menuPages.Add(new MenuPages { menuPageIndex = (MenuPageIndex)MenuPageSkills.CUSTOM_PAGE_INDEX, menuPage = GetPrefab(MenuPageSkills.PREFAB_NAME) }); Plugin.LogInfo("Menu pages registered!"); } public static IEnumerator RegisterSkillCubes() { yield return (object)new WaitUntil((Func<bool>)(() => loaded)); Plugin.LogInfo("Waiting to register skill cubes..."); Plugin.LogInfo("Registering skill cubes..."); ShopHelper.skillCubes = bundle.LoadAllAssets<SkillCube>(); SkillCube[] skillCubes = ShopHelper.skillCubes; foreach (SkillCube cube in skillCubes) { ((Item)cube).maxAmountInShop = 0; ((Item)cube).physicalItem = false; StatsManager.instance.itemDictionary.Add(((Object)cube).name, (Item)(object)cube); string targetName = ((PrefabRef<GameObject>)(object)cube.shopPrefab).PrefabName; GameObject prefab = GetPrefab(targetName); ((PrefabRef<GameObject>)(object)((Item)cube).prefab).SetPrefab(prefab, ((Object)prefab).name); NetworkPrefabs.RegisterNetworkPrefab(prefab); Plugin.LogInfo("Registered network prefab for " + ((Object)prefab).name); } Plugin.LogInfo(ShopHelper.skillCubes.Length + " skill cubes registered!"); } public static GameObject GetPrefab(string prefab) { return bundle.LoadAsset<GameObject>(prefab); } } public class ConfigHelper { private static ConfigEntry<bool> disableShopUpgrades; private static ConfigEntry<bool> fairDistribution; private static ConfigEntry<int> startingSkillPoints; private static ConfigEntry<int> baseSkillPointsEarned; private static ConfigEntry<int> moonSkillPoints; private static ConfigEntry<bool> enableDebug; private static ConfigEntry<int> edgeNodeBase; private static ConfigEntry<int> edgeNodeIncrement; private static ConfigEntry<bool> skillPointsPurchaseable; private static ConfigEntry<int> skillCubeCost; private static ConfigEntry<int> minShopPointsPerInterval; private static ConfigEntry<int> maxShopPointsPerInterval; private static ConfigEntry<int> levelsPerInterval; private static ConfigEntry<int> shopPointsCap; private static ConfigEntry<float> discountPerPoint; public static bool ShopUpgradesDisabled() { return disableShopUpgrades.Value; } public static bool FairDistribution() { return fairDistribution.Value; } public static int StartingSkillPoints() { return startingSkillPoints.Value; } public static int BaseSkillPointsEarned() { return baseSkillPointsEarned.Value; } public static int MoonSkillPoints() { return moonSkillPoints.Value; } public static bool EnableDebug() { return enableDebug == null || enableDebug.Value; } public static int EdgeNodeBase() { return edgeNodeBase.Value; } public static int EdgeNodeIncrement() { return edgeNodeIncrement.Value; } public static bool SkillPointsPurchaseable() { return skillPointsPurchaseable.Value; } public static float SkillCubeCost() { return skillCubeCost.Value; } public static int MinShopPointsPerInterval() { return minShopPointsPerInterval.Value; } public static int MaxShopPointsPerInterval() { return maxShopPointsPerInterval.Value; } public static int LevelsPerInterval() { return levelsPerInterval.Value; } public static int ShopPointsCap() { return shopPointsCap.Value; } public static float DiscountPerPoint() { return discountPerPoint.Value; } public static void Initialize(ConfigFile config) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Expected O, but got Unknown //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Expected O, but got Unknown //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Expected O, but got Unknown //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: 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_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Expected O, but got Unknown startingSkillPoints = config.Bind<int>("General", "StartingSkillPoints", 0, new ConfigDescription("The number of skill points to start with (default 0)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); baseSkillPointsEarned = config.Bind<int>("General", "BasePointsEarned", 2, new ConfigDescription("The base number of skill points gained each level (default 2)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); moonSkillPoints = config.Bind<int>("General", "PointsPerMoon", 1, new ConfigDescription("How many additional skill points to earn per moon phase (default 1)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); edgeNodeBase = config.Bind<int>("Edge Nodes", "EdgeNodeBaseCost", 5, new ConfigDescription("Starting cost for each edge node (default 5)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); edgeNodeIncrement = config.Bind<int>("Edge Nodes", "EdgeNodeIncrement", 1, new ConfigDescription("How much the price of an edge node goes up per purchase (default 1)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); skillPointsPurchaseable = config.Bind<bool>("Shop", "SkillPointsInShop", true, "Whether skill point cubes should appear in the shop (on by default)"); skillCubeCost = config.Bind<int>("Shop", "CostPerSkillPoint", 25, new ConfigDescription("How much skill point cubes cost per point (in thousands) (default 25)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); minShopPointsPerInterval = config.Bind<int>("Shop - Advanced", "MinCubePointsPerInterval", 1, new ConfigDescription("Minimum number of skill points purchaseable in shop per interval (default 1)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); maxShopPointsPerInterval = config.Bind<int>("Shop - Advanced", "MaxCubePointsPerInterval", 2, new ConfigDescription("Maximum number of skill points purchaseable in shop per interval (default 2)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); levelsPerInterval = config.Bind<int>("Shop - Advanced", "LevelsPerInterval", 2, new ConfigDescription("Number of levels before interval advances (default 2)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); shopPointsCap = config.Bind<int>("Shop - Advanced", "ShopPointsCap", 15, new ConfigDescription("Max number of points ever available in the shop (default 14)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); discountPerPoint = config.Bind<float>("Shop - Advanced", "DiscountPerPoint", 0.02f, new ConfigDescription("Discount applied to bundles per additional point in bundle. (default 0.02)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); disableShopUpgrades = config.Bind<bool>("Miscellaneous", "DisableUpgrades", true, "Whether to disable the vanilla shop upgrades (on by default)"); fairDistribution = config.Bind<bool>("Miscellaneous", "FairDistribution", true, "Whether to distribute equal skill points to players who joined late or missed levels to ensure they don't fall behind (on by default)"); enableDebug = config.Bind<bool>("Debug", "EnableDebug", false, "Whether to spam the log with my debug info"); } } public class DebugHelper { public static void TestShop() { RunManager.instance.ChangeLevel(true, false, (ChangeLevelType)5); } public static void TestAllUpgrades() { Plugin.LogInfo("Testing all upgrades:"); string[] sKILL_NAMES = SkillData.SKILL_NAMES; foreach (string text in sKILL_NAMES) { Plugin.LogInfo("-- Trying " + text); SkillDataManager.instance.UpdateSkill(PlayerHelper.GetLocalSteamID(), text, 2); } } public static void AwardPoints(int points) { SkillNetworkSync.UpdateSkillPoints(PlayerHelper.GetLocalSteamID(), points); } } public static class PlayerHelper { private const int STARTING_ENERGY = 40; private const int ENERGY_INCREMENT = 10; private const int STARTING_HEALTH = 100; public const int HEALTH_INCREMENT = 20; private const float STARTING_SPEED = 5f; private const float STARTING_STRENGTH = 1f; private const float STRENGTH_INCREMENT = 0.2f; private const float STARTING_RANGE = 2.5f; private const float THROW_INCREMENT = 0.3f; public static bool IsLocalSteamID(string steamID) { return (Object)(object)SemiFunc.PlayerAvatarGetFromSteamID(steamID) == (Object)(object)SemiFunc.PlayerAvatarLocal(); } public static bool IsHost() { return PhotonNetwork.IsMasterClient; } public static List<string> GetAllPlayerSteamIDs() { List<string> list = new List<string>(); foreach (PlayerAvatar item in SemiFunc.PlayerGetAll()) { list.Add((string)AccessTools.Field(typeof(PlayerAvatar), "steamID").GetValue(item)); } return list; } public static PlayerController GetLocalPlayerController() { return PlayerController.instance; } public static PlayerAvatar GetLocalPlayerAvatar() { return PlayerAvatar.instance; } public static string GetLocalSteamID() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) return SteamClient.SteamId.Value.ToString(); } public static void UpdatePlayerEnergy(int newLevel) { PlayerController localPlayerController = GetLocalPlayerController(); AccessTools.Field(typeof(PlayerController), "EnergyStart").SetValue(localPlayerController, (float)(40 + newLevel * 10)); AccessTools.Field(typeof(PlayerController), "EnergyCurrent").SetValue(localPlayerController, localPlayerController.EnergyStart); } public static void UpdatePlayerHealth(int newLevel, int oldValue) { PlayerAvatar localPlayerAvatar = GetLocalPlayerAvatar(); int num = (StatsManager.instance.playerUpgradeHealth.ContainsKey(GetLocalSteamID()) ? (newLevel - oldValue) : newLevel); StatsManager.instance.playerUpgradeHealth[GetLocalSteamID()] = newLevel; AccessTools.Field(typeof(PlayerHealth), "maxHealth").SetValue(localPlayerAvatar.playerHealth, 100 + newLevel * 20); int num2 = (int)AccessTools.Field(typeof(PlayerHealth), "maxHealth").GetValue(localPlayerAvatar.playerHealth); int num3 = (int)AccessTools.Field(typeof(PlayerHealth), "health").GetValue(localPlayerAvatar.playerHealth); Plugin.LogInfo("LOCAL Updating health starting at " + num3); if (num != 0) { CameraGlitch.Instance.PlayShortHeal(); AccessTools.Field(typeof(PlayerHealth), "health").SetValue(localPlayerAvatar.playerHealth, num3 + num * 20); } } public static void UpdatePlayerExtraJump(int newLevel) { PlayerController localPlayerController = GetLocalPlayerController(); AccessTools.Field(typeof(PlayerController), "JumpExtra").SetValue(localPlayerController, newLevel); } public static void UpdatePlayerLaunch(int newLevel) { PlayerAvatar localPlayerAvatar = GetLocalPlayerAvatar(); object value = AccessTools.Field(typeof(PlayerAvatar), "tumble").GetValue(localPlayerAvatar); if (value != null) { AccessTools.Field(typeof(PlayerTumble), "tumbleLaunch").SetValue(value, newLevel); } } public static void UpdatePlayerTumbleClimb(int newLevel) { PlayerAvatar localPlayerAvatar = GetLocalPlayerAvatar(); AccessTools.Field(typeof(PlayerAvatar), "upgradeTumbleClimb").SetValue(localPlayerAvatar, (float)newLevel); } public static void UpdatePlayerDeathHeadBattery(int newLevel) { PlayerAvatar localPlayerAvatar = GetLocalPlayerAvatar(); AccessTools.Field(typeof(PlayerAvatar), "upgradeDeathHeadBattery").SetValue(localPlayerAvatar, (float)newLevel); } public static void UpdatePlayerMapPlayerCount(int newLevel) { PlayerAvatar localPlayerAvatar = GetLocalPlayerAvatar(); AccessTools.Field(typeof(PlayerAvatar), "upgradeMapPlayerCount").SetValue(localPlayerAvatar, newLevel); } public static void UpdatePlayerSpeed(int newLevel) { PlayerController localPlayerController = GetLocalPlayerController(); AccessTools.Field(typeof(PlayerController), "SprintSpeed").SetValue(localPlayerController, 5f + (float)newLevel); AccessTools.Field(typeof(PlayerController), "SprintSpeedUpgrades").SetValue(localPlayerController, (float)newLevel); AccessTools.Field(typeof(PlayerController), "playerOriginalSprintSpeed").SetValue(localPlayerController, 5f + (float)newLevel); } public static void UpdatePlayerStrength(int newLevel) { PlayerAvatar localPlayerAvatar = GetLocalPlayerAvatar(); AccessTools.Field(typeof(PhysGrabber), "grabStrength").SetValue(AccessTools.Field(typeof(PlayerAvatar), "physGrabber").GetValue(localPlayerAvatar), 1f + (float)newLevel * 0.2f); } public static void UpdatePlayerRange(int newLevel) { PlayerAvatar localPlayerAvatar = GetLocalPlayerAvatar(); AccessTools.Field(typeof(PhysGrabber), "grabRange").SetValue(AccessTools.Field(typeof(PlayerAvatar), "physGrabber").GetValue(localPlayerAvatar), 2.5f + (float)newLevel); } public static void UpdatePlayerThrow(int newLevel) { PlayerAvatar localPlayerAvatar = GetLocalPlayerAvatar(); AccessTools.Field(typeof(PhysGrabber), "throwStrength").SetValue(AccessTools.Field(typeof(PlayerAvatar), "physGrabber").GetValue(localPlayerAvatar), (float)newLevel * 0.3f); } public static void UpdatePlayerCrouchRest(int newLevel) { PlayerAvatar localPlayerAvatar = GetLocalPlayerAvatar(); AccessTools.Field(typeof(PlayerAvatar), "upgradeCrouchRest").SetValue(localPlayerAvatar, (float)newLevel); } public static void UpdatePlayerTumbleWings(int newLevel) { PlayerAvatar localPlayerAvatar = GetLocalPlayerAvatar(); AccessTools.Field(typeof(PlayerAvatar), "upgradeTumbleWings").SetValue(localPlayerAvatar, (float)newLevel); } } public class ShopHelper { private const int MIN_ONES = 2; public static SkillCube[] skillCubes; private static int[] cubeValues = new int[3] { 1, 3, 5 }; public static void SpawnSkillCubes(List<Item> potentialItemUpgrades) { int num = SemiFunc.RunGetLevelsCompleted() / ConfigHelper.LevelsPerInterval() + 1; int num2 = Mathf.Min(Random.Range(ConfigHelper.MinShopPointsPerInterval() * num, Mathf.Min(ConfigHelper.MaxShopPointsPerInterval() * num + 1, ConfigHelper.ShopPointsCap())), ConfigHelper.ShopPointsCap()); int num3 = num2; int num4 = 2; Plugin.LogInfo("Distributing " + num2 + " points into shop"); while (num2 > 0) { Plugin.LogInfo(" - Starting Cycle | totalPoints: " + num2 + " | pointsLeft: " + num3); int num5 = 0; if (num3 > 10) { num5 = 2; } else if (num3 > 4 && num2 >= cubeValues[1]) { num5 = 1; } int num6 = Random.Range(num5, 3); if (num4 > 0) { num4--; num6 = 0; } else if (cubeValues[num6] <= num2) { num3 -= cubeValues[num6]; } if (cubeValues[num6] <= num2) { num2 -= cubeValues[num6]; Plugin.LogInfo(" - - Adding a " + cubeValues[num6] + "SP cube"); potentialItemUpgrades.Add((Item)(object)skillCubes[num6]); } } } } } namespace SkillFern.Unity { [CreateAssetMenu(fileName = "SP Cube", menuName = "SkillFern/SkillCube")] public class SkillCube : Item { [HideInInspector] public static int SKILL_CUBE_INDEX = 25; public int skillPointValue = 1; public PrefabRef shopPrefab; private void Reset() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) base.disabled = false; base.itemName = "SP Cube "; base.itemNameLocalized = null; base.description = ""; base.itemType = (itemType)SKILL_CUBE_INDEX; base.emojiIcon = (emojiIcon)5; base.itemVolume = (itemVolume)6; base.maxAmount = 6; base.maxAmountInShop = 6; base.maxPurchaseAmount = 999; base.maxPurchase = false; base.physicalItem = false; } } } namespace SkillFern.Networking { public static class SkillNetworkSync { private enum EVENT_TYPE { SKILL_UPDATE, NODE_PURCHASE, POINTS_UPDATE, SKILL_SYNC, POINTS_SYNC, CAREER_SYNC, CONFIG_SYNC } private const byte SKILL_DATA_CHANNEL = 187; private static bool isInitialized = false; public static int saveCountdown = -1; public static int careerCountdown = -1; public static void Initialize() { if (!isInitialized && PhotonNetwork.NetworkingClient != null) { isInitialized = true; saveCountdown = -1; careerCountdown = -1; PhotonNetwork.NetworkingClient.EventReceived += OnEventReceived; Plugin.LogInfo("Network initialized"); } } public static void OnEventReceived(EventData data) { if (data.Code != 187) { return; } object[] array = (object[])data.CustomData; Plugin.LogInfo("Payload: " + array.ToString()); string steamID = (string)array[1]; switch ((EVENT_TYPE)array[0]) { case EVENT_TYPE.CONFIG_SYNC: { int moonSkillPoints = (int)array[2]; int baseSkillPoints = (int)array[3]; int baseEdgeNode = (int)array[4]; int edgeNodeIncrement = (int)array[5]; SkillDataManager.instance.moonSkillPoints = moonSkillPoints; SkillDataManager.instance.baseSkillPoints = baseSkillPoints; SkillDataManager.instance.baseEdgeNode = baseEdgeNode; SkillDataManager.instance.edgeNodeIncrement = edgeNodeIncrement; break; } case EVENT_TYPE.CAREER_SYNC: break; case EVENT_TYPE.NODE_PURCHASE: { string nodeID = (string)array[2]; bool sync = (bool)array[3]; SkillDataManager.instance.PurchaseNode(steamID, nodeID, sync); break; } case EVENT_TYPE.SKILL_UPDATE: case EVENT_TYPE.SKILL_SYNC: { string skillName = (string)array[2]; int newLevel = (int)array[3]; SkillDataManager.instance.UpdateSkill(steamID, skillName, newLevel, (EVENT_TYPE)array[0] == EVENT_TYPE.SKILL_SYNC); break; } case EVENT_TYPE.POINTS_UPDATE: case EVENT_TYPE.POINTS_SYNC: { int amount = (int)array[2]; SkillDataManager.instance.UpdateSkillPoints(steamID, amount, (EVENT_TYPE)array[0] == EVENT_TYPE.POINTS_SYNC); if (saveCountdown > 0 && PlayerHelper.IsHost()) { saveCountdown--; if (saveCountdown == 0) { saveCountdown = -1; Plugin.LogInfo("Forcing save after skill point updates. . ."); SaveManager.Save(SaveManager.lastFile); } } if (careerCountdown > 0 && PlayerHelper.IsHost()) { careerCountdown--; if (careerCountdown == 0) { careerCountdown = -1; Plugin.LogInfo("Syncing careers. . ."); SyncCareer(); } } break; } } } public static void UpdateSkillPointsForAll(int amount) { foreach (string allPlayerSteamID in PlayerHelper.GetAllPlayerSteamIDs()) { UpdateSkillPoints(allPlayerSteamID, amount); } } public static void UpdateSkillPoints(string steamID, int amount, bool sync = false) { //IL_005e: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) Plugin.LogInfo(" Granting " + amount + " points to " + steamID); if (!GameManager.Multiplayer()) { SkillDataManager.instance.UpdateSkillPoints(steamID, amount); return; } object[] array = new object[3] { sync ? EVENT_TYPE.POINTS_SYNC : EVENT_TYPE.POINTS_UPDATE, steamID, amount }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)1 }; PhotonNetwork.RaiseEvent((byte)187, (object)array, val, SendOptions.SendReliable); } public static void UpdateSkill(string steamID, string skillName, int newLevel, bool sync = false) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_005a: Unknown result type (might be due to invalid IL or missing references) if (!GameManager.Multiplayer()) { SkillDataManager.instance.UpdateSkill(steamID, skillName, newLevel); return; } object[] array = new object[4] { sync ? EVENT_TYPE.SKILL_SYNC : EVENT_TYPE.SKILL_UPDATE, steamID, skillName, newLevel }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)1 }; PhotonNetwork.RaiseEvent((byte)187, (object)array, val, SendOptions.SendReliable); } public static void UpdateSkill(string steamID, SkillData.SKILL_TYPE skillType, int newLevel) { UpdateSkill(steamID, SkillData.SKILL_NAMES[(int)skillType], newLevel); } public static void PurchaseNode(string steamID, string nodeID, bool sync = false) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_007d: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (!GameManager.Multiplayer()) { SkillDataManager.instance.PurchaseNode(steamID, nodeID); return; } Plugin.LogInfo("Purchasing node " + nodeID + " for " + steamID + " on network."); object[] array = new object[4] { EVENT_TYPE.NODE_PURCHASE, steamID, nodeID, sync }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)1 }; PhotonNetwork.RaiseEvent((byte)187, (object)array, val, SendOptions.SendReliable); } public static void AwardSkillPointsForLevel() { if (!GameManager.Multiplayer()) { int amount = SkillDataManager.CalculatePointsEarned(); SkillDataManager.instance.UpdateSkillPoints(PlayerHelper.GetLocalSteamID(), amount); SaveManager.Save(SaveManager.lastFile); return; } saveCountdown = 0; foreach (string allPlayerSteamID in PlayerHelper.GetAllPlayerSteamIDs()) { saveCountdown++; int amount2 = SkillDataManager.CalculatePointsEarned(); UpdateSkillPoints(allPlayerSteamID, amount2); } } public static void SyncAll() { //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_0356: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Expected O, but got Unknown //IL_0367: Unknown result type (might be due to invalid IL or missing references) if (!GameManager.Multiplayer() || !PlayerHelper.IsHost()) { return; } Plugin.LogInfo("Syncing all skill data. . ."); List<string> list = new List<string>(); List<string> allPlayerSteamIDs = PlayerHelper.GetAllPlayerSteamIDs(); careerCountdown = 0; foreach (SkillData skillData in SkillDataManager.instance.skillDatas) { if (!allPlayerSteamIDs.Contains(skillData.steamID)) { Plugin.LogInfo("Skipping " + skillData.steamID + " who is not in this game."); continue; } Plugin.LogInfo("Syncing data for " + skillData.steamID); Plugin.LogInfo("Cycling skill datas"); string[] sKILL_NAMES = SkillData.SKILL_NAMES; foreach (string text in sKILL_NAMES) { UpdateSkill(skillData.steamID, text, (int)typeof(SkillData).GetField(text).GetValue(skillData), sync: true); } Plugin.LogInfo("Cycling owned nodes"); foreach (string ownedNode in skillData.ownedNodes) { PurchaseNode(skillData.steamID, ownedNode, sync: true); } Plugin.LogInfo("Syncing skill points"); UpdateSkillPoints(skillData.steamID, skillData.skillPoints, sync: true); careerCountdown++; list.Add(skillData.steamID); } int num = allPlayerSteamIDs.Count - list.Count; if (num > 0) { Plugin.LogInfo("Creating new skill data for " + num + " new players."); } foreach (string item in allPlayerSteamIDs) { if (!list.Contains(item)) { careerCountdown++; if (ConfigHelper.FairDistribution()) { Plugin.LogInfo("Starting " + item + " with " + SkillDataManager.instance.careerPoints + " points."); UpdateSkillPoints(item, SkillDataManager.instance.careerPoints, sync: true); } else { Plugin.LogInfo("Starting " + item + " with " + ConfigHelper.StartingSkillPoints() + " points."); UpdateSkillPoints(item, ConfigHelper.StartingSkillPoints(), sync: true); } list.Add(item); } } Plugin.LogInfo("Skill data synced!"); Plugin.LogInfo("Syncing moon phase data. . ."); object[] array = new object[6] { EVENT_TYPE.CONFIG_SYNC, PlayerHelper.GetLocalSteamID(), ConfigHelper.MoonSkillPoints(), ConfigHelper.BaseSkillPointsEarned(), ConfigHelper.EdgeNodeBase(), ConfigHelper.EdgeNodeIncrement() }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)1 }; PhotonNetwork.RaiseEvent((byte)187, (object)array, val, SendOptions.SendReliable); } public static void SyncCareer() { Plugin.LogInfo("Career points: " + SkillDataManager.instance.careerPoints); if (!ConfigHelper.FairDistribution()) { return; } Plugin.LogInfo("Reconciling careers"); foreach (string allPlayerSteamID in PlayerHelper.GetAllPlayerSteamIDs()) { if (!(allPlayerSteamID == PlayerHelper.GetLocalSteamID())) { SkillData playerData = SkillDataManager.instance.GetPlayerData(allPlayerSteamID); Plugin.LogInfo("Reconciling " + allPlayerSteamID); Plugin.LogInfo("Points gained: " + playerData.pointsGained); int num = SkillDataManager.instance.careerPoints - playerData.pointsGained; Plugin.LogInfo("Difference: " + num); if (num > 0) { Plugin.LogInfo("Adjusting " + num + " career points to " + allPlayerSteamID); UpdateSkillPoints(allPlayerSteamID, num); } } } } } } namespace SkillFern.Custom { public static class SaveManager { public static string lastFile; public static void Save(string fileName) { lastFile = fileName; string text = Application.persistentDataPath + "/saves/" + fileName; string text2 = text + "/" + fileName + "_SkillFern.json"; string contents = JsonConvert.SerializeObject((object)SkillDataManager.instance, (Formatting)1); File.WriteAllText(text2, contents); Plugin.LogInfo("Saved data to " + text2); } public static void Load(string fileName) { lastFile = fileName; string text = Application.persistentDataPath + "/saves/" + fileName; string text2 = text + "/" + fileName + "_SkillFern.json"; if (File.Exists(text2)) { string text3 = File.ReadAllText(text2); SkillDataManager.instance = JsonConvert.DeserializeObject<SkillDataManager>(text3); Plugin.LogInfo("Loaded save data from " + text2); } else { Plugin.LogInfo("SAVE DOESN T EXIST"); SkillDataManager.instance = new SkillDataManager(); Plugin.LogInfo("Created new save data at " + text2); } } } [Serializable] public class SkillDataManager { public static SkillDataManager instance; public int careerPoints; public int moonSkillPoints; public int baseSkillPoints; public int baseEdgeNode; public int edgeNodeIncrement; [JsonProperty("skillDatas")] public List<SkillData> skillDatas { get; set; } [JsonConstructor] public SkillDataManager() { Plugin.LogInfo("NEW SKILLDATAMANAGER CREATED ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); skillDatas = new List<SkillData>(); careerPoints = ConfigHelper.StartingSkillPoints(); moonSkillPoints = ConfigHelper.MoonSkillPoints(); baseSkillPoints = ConfigHelper.BaseSkillPointsEarned(); baseEdgeNode = ConfigHelper.EdgeNodeBase(); edgeNodeIncrement = ConfigHelper.EdgeNodeIncrement(); } public static void Initialize() { if (instance == null) { instance = new SkillDataManager(); } } public static int CalculatePointsEarned(int offset = 0) { return instance.baseSkillPoints + RunManager.instance.CalculateMoonLevel(SemiFunc.RunGetLevelsCompleted() - 1 + offset) * instance.moonSkillPoints; } public int GetLocalSkillPoints() { return GetPlayerData(PlayerHelper.GetLocalSteamID()).skillPoints; } public SkillData GetLocalPlayerData() { return GetPlayerData(PlayerHelper.GetLocalSteamID()); } public SkillData GetPlayerData(string steamID) { SkillData skillData = skillDatas.Find((SkillData data) => data.steamID == steamID); if (skillData == null) { skillData = new SkillData(steamID); skillDatas.Add(skillData); } return skillData; } public void UpdateSkillPoints(string steamID, int amount, bool syncing = false) { if (skillDatas == null) { Plugin.LogInfo("Skill Data does not exist! Creating. . ."); skillDatas = new List<SkillData>(); } SkillData skillData = skillDatas.Find((SkillData data) => data.steamID == steamID); if (skillData == null) { skillData = new SkillData(steamID); skillDatas.Add(skillData); if (syncing) { skillData.pointsGained = amount; } Plugin.LogInfo("!!! CREATED NEW SKILL DATA with " + skillData.pointsGained + " points"); } if (syncing) { skillData.skillPoints = amount; } else { if (amount > 0) { if (steamID == PlayerHelper.GetLocalSteamID()) { careerPoints += amount; } skillData.pointsGained += amount; } skillData.skillPoints += amount; } if (steamID == PlayerHelper.GetLocalSteamID()) { CameraGlitch.Instance.PlayUpgrade(); if ((Object)(object)MenuPageSkills.instance != (Object)null) { MenuPageSkills.instance.UpdateSkillPointsText(); } } Plugin.LogInfo(steamID + " now has " + skillData.skillPoints + " points"); } public void UpdateSkill(string steamID, string skillName, int newLevel, bool syncing = false) { if (skillDatas == null) { Plugin.LogInfo("Skill Data does not exist! Creating. . ."); skillDatas = new List<SkillData>(); } SkillData skillData = skillDatas.Find((SkillData data) => data.steamID == steamID); if (skillData == null) { skillData = new SkillData(steamID); skillDatas.Add(skillData); } int num = ((!syncing) ? ((int)typeof(SkillData).GetField(skillName).GetValue(skillData) + newLevel) : newLevel); typeof(SkillData).GetField(skillName).SetValue(skillData, num); if (!syncing) { int oldValue = UpdateDictionarySkillByName(steamID, skillName, num); if (!GameManager.Multiplayer() || PlayerHelper.IsLocalSteamID(steamID)) { UpdateLocalSkillByName(skillName, num, oldValue); } } } public void PurchaseNode(string steamID, string nodeID, bool sync = false) { if (skillDatas == null) { Plugin.LogInfo("Skill Data does not exist! Creating. . ."); skillDatas = new List<SkillData>(); } SkillData skillData = skillDatas.Find((SkillData data) => data.steamID == steamID); if (skillData == null) { Plugin.LogInfo("Creating skill data for player " + steamID); skillData = new SkillData(steamID); skillDatas.Add(skillData); } if (!sync || !PlayerHelper.IsHost()) { skillData.ownedNodes.Add(nodeID); } else { Plugin.LogInfo("SKIPPING NODE ADDING"); } } public void UpdateLocalSkillByName(string skillName, int newLevel, int oldValue = 0) { switch (skillName) { case "healthLevels": PlayerHelper.UpdatePlayerHealth(newLevel, oldValue); break; case "staminaLevels": PlayerHelper.UpdatePlayerEnergy(newLevel); break; case "extraJumpLevels": PlayerHelper.UpdatePlayerExtraJump(newLevel); break; case "launchLevels": PlayerHelper.UpdatePlayerLaunch(newLevel); break; case "tumbleClimbLevels": PlayerHelper.UpdatePlayerTumbleClimb(newLevel); break; case "deathHeadBatteryLevels": PlayerHelper.UpdatePlayerDeathHeadBattery(newLevel); break; case "mapPlayerCountLevels": PlayerHelper.UpdatePlayerMapPlayerCount(newLevel); break; case "speedLevels": PlayerHelper.UpdatePlayerSpeed(newLevel); break; case "strengthLevels": PlayerHelper.UpdatePlayerStrength(newLevel); break; case "rangeLevels": PlayerHelper.UpdatePlayerRange(newLevel); break; case "throwLevels": PlayerHelper.UpdatePlayerThrow(newLevel); break; case "crouchRestLevels": PlayerHelper.UpdatePlayerCrouchRest(newLevel); break; case "tumbleWingsLevels": PlayerHelper.UpdatePlayerTumbleWings(newLevel); break; } } public int UpdateDictionarySkillByName(string steamID, string skillName, int newLevel) { int num = 0; switch (skillName) { case "healthLevels": { num = (StatsManager.instance.playerUpgradeHealth.ContainsKey(steamID) ? StatsManager.instance.playerUpgradeHealth[steamID] : 0); int playerHealth = StatsManager.instance.GetPlayerHealth(steamID); Plugin.LogInfo("Updating health starting at " + playerHealth); StatsManager.instance.SetPlayerHealth(steamID, playerHealth + (newLevel - num) * 20, true); StatsManager.instance.playerUpgradeHealth[steamID] = newLevel; break; } case "staminaLevels": StatsManager.instance.playerUpgradeStamina[steamID] = newLevel; break; case "extraJumpLevels": StatsManager.instance.playerUpgradeExtraJump[steamID] = newLevel; break; case "launchLevels": StatsManager.instance.playerUpgradeLaunch[steamID] = newLevel; break; case "tumbleClimbLevels": StatsManager.instance.playerUpgradeTumbleClimb[steamID] = newLevel; break; case "deathHeadBatteryLevels": StatsManager.instance.playerUpgradeDeathHeadBattery[steamID] = newLevel; break; case "mapPlayerCountLevels": StatsManager.instance.playerUpgradeMapPlayerCount[steamID] = newLevel; break; case "speedLevels": StatsManager.instance.playerUpgradeSpeed[steamID] = newLevel; break; case "strengthLevels": StatsManager.instance.playerUpgradeStrength[steamID] = newLevel; break; case "rangeLevels": StatsManager.instance.playerUpgradeRange[steamID] = newLevel; break; case "throwLevels": StatsManager.instance.playerUpgradeThrow[steamID] = newLevel; break; case "crouchRestLevels": StatsManager.instance.playerUpgradeCrouchRest[steamID] = newLevel; break; case "tumbleWingsLevels": StatsManager.instance.playerUpgradeTumbleWings[steamID] = newLevel; break; } return num; } } [Serializable] public class SkillData { public enum SKILL_TYPE { HEALTH, STAMINA, EXTRA_JUMP, LAUNCH, TUMBLE_CLIMB, DEATH_HEAD_BATTERY, MAP_PLAYER_COUNT, SPEED, STRENGTH, RANGE, THROW, CROUCH_REST, TUMBLE_WINGS } public static string[] SKILL_DISPLAY_NAMES = new string[13] { "Health", "Stamina", "Extra Jump", "Tumble Launch", "Tumble Climb", "Death Battery", "Player Count", "Speed", "Strength", "Range", "Throw", "Crouch Rest", "Tumble Wings" }; public static string[] SKILL_NAMES = new string[13] { "healthLevels", "staminaLevels", "extraJumpLevels", "launchLevels", "tumbleClimbLevels", "deathHeadBatteryLevels", "mapPlayerCountLevels", "speedLevels", "strengthLevels", "rangeLevels", "throwLevels", "crouchRestLevels", "tumbleWingsLevels" }; public string steamID; public int healthLevels; public int staminaLevels; public int extraJumpLevels; public int launchLevels; public int tumbleClimbLevels; public int deathHeadBatteryLevels; public int mapPlayerCountLevels; public int speedLevels; public int strengthLevels; public int rangeLevels; public int throwLevels; public int crouchRestLevels; public int tumbleWingsLevels; public int skillPoints; public int pointsGained; [JsonProperty("ownedNodes")] public List<string> ownedNodes { get; set; } public SkillData(string steamID) { this.steamID = steamID; healthLevels = 0; staminaLevels = 0; extraJumpLevels = 0; launchLevels = 0; tumbleClimbLevels = 0; deathHeadBatteryLevels = 0; mapPlayerCountLevels = 0; speedLevels = 0; strengthLevels = 0; rangeLevels = 0; throwLevels = 0; crouchRestLevels = 0; tumbleWingsLevels = 0; skillPoints = ConfigHelper.StartingSkillPoints(); ownedNodes = new List<string>(); pointsGained = 0; } [JsonConstructor] public SkillData() { ownedNodes = new List<string>(); } } } namespace SkillFern.UI { public class HoverText : MonoBehaviour { public float yOffset = 10f; public float flyInTime = 0.1f; public float fadeInTime = 0.05f; public float fadeOutTime = 0.2f; private TextMeshProUGUI textMesh; private bool shown; public void Start() { textMesh = ((Component)this).GetComponentInChildren<TextMeshProUGUI>(); ((TMP_Text)textMesh).alpha = 0f; ((TMP_Text)textMesh).SetText("", true); shown = false; } public void Update() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) if (shown) { if (((TMP_Text)textMesh).alpha < 1f) { TextMeshProUGUI obj = textMesh; ((TMP_Text)obj).alpha = ((TMP_Text)obj).alpha + Time.deltaTime / fadeInTime; } Vector2 anchoredPosition = ((TMP_Text)textMesh).rectTransform.anchoredPosition; float num = yOffset / flyInTime; if (anchoredPosition.y < 0f) { anchoredPosition.y = Mathf.MoveTowards(anchoredPosition.y, 0f, num * Time.deltaTime); } ((TMP_Text)textMesh).rectTransform.anchoredPosition = anchoredPosition; } else if (((TMP_Text)textMesh).alpha > 0f) { TextMeshProUGUI obj2 = textMesh; ((TMP_Text)obj2).alpha = ((TMP_Text)obj2).alpha - Time.deltaTime / fadeOutTime; } } public void SetText(string text) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (!shown) { ((TMP_Text)textMesh).alpha = 0f; ((TMP_Text)textMesh).SetText(text, true); shown = true; ((TMP_Text)textMesh).rectTransform.anchoredPosition = new Vector2(((TMP_Text)textMesh).rectTransform.anchoredPosition.x, 0f - yOffset); } } public void Clear() { shown = false; } } public class EdgeNode : UpgradeNode { private int timesPurchased; public new void Awake() { base.Awake(); cost = SkillDataManager.instance.baseEdgeNode; timesPurchased = 0; } public override void setOwned(bool newOwned) { if (newOwned) { timesPurchased++; cost = SkillDataManager.instance.baseEdgeNode + SkillDataManager.instance.edgeNodeIncrement * timesPurchased; } } public override void UpdateStatus() { base.UpdateStatus(); if (!CanPurchase()) { ((Behaviour)costText).enabled = false; } else { ((Behaviour)costText).enabled = true; } } } public class UpgradeNode : FernNode { public SkillData.SKILL_TYPE upgradeType; public int upgradeAmount; public new void Reset() { base.Reset(); upgradeAmount = 1; } public override void Activate() { SkillNetworkSync.UpdateSkill(PlayerHelper.GetLocalSteamID(), upgradeType, upgradeAmount); } public override string GetDisplayString() { return SkillData.SKILL_DISPLAY_NAMES[(int)upgradeType]; } } public class FernNode : MonoBehaviour { private class LineContainer { public GameObject lineObject; public FernNode dependency; } private List<LineContainer> lines = new List<LineContainer>(); public string nodeID; public Image[] targetImages; public TextMeshProUGUI costText; public FernNode[] dependencies; public int cost; protected bool owned; protected MenuButton button; protected bool wasHovering; private MenuPageSkills skillsPage; public bool isOwned() { return owned; } public virtual void setOwned(bool newOwned) { owned = newOwned; } public void DrawLines(GameObject lineContainer, int lineThickness) { //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_0136: 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_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) if (Application.isEditor) { Debug.Log((object)((Object)((Component)this).gameObject).name); nodeID = Guid.NewGuid().ToString(); List<Image> list = ((Component)((Component)this).transform).GetComponentsInChildren<Image>().ToList(); list.RemoveAt(0); targetImages = list.ToArray(); ((TMP_Text)((Component)((Component)this).transform.GetChild(1)).GetComponent<TextMeshProUGUI>()).SetText("", true); costText = ((Component)((Component)this).transform.GetChild(2)).GetComponent<TextMeshProUGUI>(); ((TMP_Text)costText).SetText(cost.ToString() ?? "", true); } if (dependencies != null && dependencies.Length != 0) { lines = new List<LineContainer>(); for (int i = 0; i < dependencies.Length; i++) { LineContainer lineContainer2 = new LineContainer(); lineContainer2.lineObject = new GameObject("Fern Line"); lineContainer2.dependency = dependencies[i]; lineContainer2.lineObject.transform.SetParent(lineContainer.transform, false); Image val = lineContainer2.lineObject.AddComponent<Image>(); ((Graphic)val).color = Color.white; RectTransform rectTransform = ((Graphic)val).rectTransform; rectTransform.pivot = new Vector2(0f, 0.5f); RectTransform component = ((Component)this).GetComponent<RectTransform>(); RectTransform component2 = ((Component)dependencies[i]).GetComponent<RectTransform>(); Rect rect = component.rect; Vector3 val2 = ((Transform)component).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center)); rect = component2.rect; Vector3 val3 = ((Transform)component2).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center)); ((Transform)rectTransform).position = val2; float num = Vector3.Distance(val2, val3); rectTransform.sizeDelta = new Vector2(num, (float)lineThickness); Vector3 val4 = val3 - val2; float num2 = Mathf.Atan2(val4.y, val4.x) * 57.29578f; ((Transform)rectTransform).rotation = Quaternion.Euler(0f, 0f, num2); lines.Add(lineContainer2); } } } public void OnValidate() { ((TMP_Text)costText).SetText(cost.ToString() ?? "", true); } public virtual void Reset() { cost = 1; nodeID = Guid.NewGuid().ToString(); List<Image> list = ((Component)((Component)this).transform).GetComponentsInChildren<Image>().ToList(); list.RemoveAt(0); targetImages = list.ToArray(); dependencies = new FernNode[1]; costText = ((Component)((Component)this).transform.GetChild(2)).GetComponent<TextMeshProUGUI>(); ((TMP_Text)costText).SetText(cost.ToString() ?? "", true); } public void Awake() { button = ((Component)this).GetComponent<MenuButton>(); skillsPage = ((Component)this).GetComponentInParent<MenuPageSkills>(); } public void Update() { if ((int)AccessTools.Field(typeof(MenuButton), "buttonState").GetValue(button) <= 1 && !owned) { wasHovering = true; skillsPage.SetHoverText(GetDisplayString()); } else if (wasHovering) { wasHovering = false; skillsPage.ClearHoverText(); } } public virtual void Initialize() { UpdateStatus(); } public bool CanPurchase() { return !owned && (dependencies.Length == 0 || dependencies.Any((FernNode node) => node.isOwned())); } public void Purchase() { int localSkillPoints = SkillDataManager.instance.GetLocalSkillPoints(); if (localSkillPoints >= cost) { Plugin.LogInfo("Purchased node " + nodeID); setOwned(newOwned: true); SkillNetworkSync.UpdateSkillPoints(PlayerHelper.GetLocalSteamID(), -cost); skillsPage.UpdateAllNodes(localSkillPoints - cost); Activate(); SkillNetworkSync.PurchaseNode(PlayerHelper.GetLocalSteamID(), nodeID); } } public virtual void Activate() { Plugin.LogInfo("Node " + nodeID + " has no effects"); } public virtual void UpdateStatus() { //IL_008b: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_015f: 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) if (owned) { ((Behaviour)costText).enabled = false; } else { ((TMP_Text)costText).SetText(cost.ToString() ?? "", true); } if (!owned && CanPurchase()) { ((Behaviour)button).enabled = true; } else { ((Behaviour)button).enabled = false; } Image[] array = targetImages; foreach (Image val in array) { if (owned) { ((Graphic)val).color = Color.green; } else if (CanPurchase()) { ((Graphic)val).color = Color.white; } else { ((Graphic)val).color = Color.gray; } } foreach (LineContainer line in lines) { if (owned && line.dependency.isOwned()) { ((Graphic)line.lineObject.GetComponent<Image>()).color = Color.green; } else if (owned || line.dependency.isOwned()) { ((Graphic)line.lineObject.GetComponent<Image>()).color = Color.white; } else { ((Graphic)line.lineObject.GetComponent<Image>()).color = Color.gray; } } } public virtual string GetDisplayString() { return "[BLANK]"; } } public class CustomMenuPage : MonoBehaviour { [HideInInspector] public static CustomMenuPage instance; [HideInInspector] public int customPageIndex; [HideInInspector] public MenuPage menuPage; protected virtual void Start() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) instance = this; menuPage = ((Component)this).GetComponent<MenuPage>(); menuPage.menuPageIndex = (MenuPageIndex)customPageIndex; } } public class MenuPageSkills : CustomMenuPage { public new static MenuPageSkills instance; public int lineThickness = 5; public GameObject lineContainer; public TextMeshProUGUI skillPointsText; [HideInInspector] public static string PREFAB_NAME = "Menu Page Skills"; [HideInInspector] public static int CUSTOM_PAGE_INDEX = 23; private List<FernNode> nodes; private HoverText hoverText; [ContextMenu("Draw Lines")] public void DrawLines() { for (int num = lineContainer.transform.childCount - 1; num >= 0; num--) { Object.DestroyImmediate((Object)(object)((Component)lineContainer.transform.GetChild(num)).gameObject); } List<string> list = new List<string>(); FernNode[] componentsInChildren = ((Component)this).GetComponentsInChildren<FernNode>(); foreach (FernNode fernNode in componentsInChildren) { fernNode.DrawLines(lineContainer, lineThickness); } } protected override void Start() { instance = this; customPageIndex = CUSTOM_PAGE_INDEX; base.Start(); hoverText = ((Component)this).GetComponentInChildren<HoverText>(); ((TMP_Text)skillPointsText).SetText("Points: " + SkillDataManager.instance.GetLocalSkillPoints(), true); nodes = new List<FernNode>(((Component)this).GetComponentsInChildren<FernNode>()); DrawLines(); List<string> ownedNodes = SkillDataManager.instance.GetPlayerData(PlayerHelper.GetLocalSteamID()).ownedNodes; foreach (string id in ownedNodes) { FernNode fernNode = nodes.Find((FernNode n) => n.nodeID == id); if ((Object)(object)fernNode != (Object)null) { fernNode.setOwned(newOwned: true); } } foreach (FernNode node in nodes) { node.Initialize(); } } private void Update() { if (SemiFunc.InputDown((InputKey)18)) { ButtonEventBack(); } } public void UpdateAllNodes(int pointsCorrection = -1) { UpdateSkillPointsText(pointsCorrection); foreach (FernNode node in nodes) { node.UpdateStatus(); } } public void UpdateSkillPointsText(int pointsCorrection = -1) { ((TMP_Text)skillPointsText).SetText("Points: " + ((pointsCorrection == -1) ? SkillDataManager.instance.GetLocalSkillPoints() : pointsCorrection), true); } public void ButtonEventBack() { MenuManager.instance.PageCloseAll(); MenuManager.instance.PageOpen((MenuPageIndex)1, false); } public void ClearHoverText() { hoverText.Clear(); } public void SetHoverText(string text) { hoverText.SetText(text); } } public class SkillsButton : MonoBehaviour { public void ButtonEventOpenSkills() { Plugin.LogInfo("Opening skills menu"); MenuManager.instance.PageSwap((MenuPageIndex)MenuPageSkills.CUSTOM_PAGE_INDEX); } } } namespace SkillFern.Patches { [HarmonyPatch(typeof(ExtractionPoint))] public class ExtractionPointPatch { [HarmonyPatch("DestroyAllPhysObjectsInShoppingList")] [HarmonyPrefix] public static void ProcessSkillCubes(ExtractionPoint __instance) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Invalid comparison between Unknown and I4 if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } List<ItemAttributes> list = (List<ItemAttributes>)AccessTools.Field(typeof(ShopManager), "shoppingList").GetValue(ShopManager.instance); Plugin.LogInfo("Checking " + list.Count + " items"); foreach (ItemAttributes item in list) { Plugin.LogInfo("Item is of type " + ((object)Unsafe.As<itemType, itemType>(ref item.item.itemType)/*cast due to .constrained prefix*/).ToString()); if ((int)item.item.itemType == SkillCube.SKILL_CUBE_INDEX) { SkillNetworkSync.UpdateSkillPointsForAll(((SkillCube)(object)item.item).skillPointValue); } } } } [HarmonyPatch(typeof(ItemAttributes))] public class ItemAttributesPatch { [HarmonyPatch("Start")] [HarmonyPostfix] public static void Initialize(ref float ___itemValueMin, ref float ___itemValueMax, Item ___item) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if ((int)___item.itemType == SkillCube.SKILL_CUBE_INDEX) { ___itemValueMin = ConfigHelper.SkillCubeCost() * (float)((SkillCube)(object)___item).skillPointValue; ___itemValueMax = ___itemValueMin; } } [HarmonyPatch("GetValue")] [HarmonyPrefix] [HarmonyPriority(0)] public static bool SkillCubePrice(ref int ___value, PhotonView ___photonView, Item ___item) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 if (GameManager.Multiplayer() && !PhotonNetwork.IsMasterClient) { return true; } if ((int)___item.itemType != SkillCube.SKILL_CUBE_INDEX) { return true; } ___value = (int)(ConfigHelper.SkillCubeCost() * (float)((SkillCube)(object)___item).skillPointValue); ___value -= (int)((float)___value * ConfigHelper.DiscountPerPoint() * (float)(((SkillCube)(object)___item).skillPointValue - 1)); if (GameManager.Multiplayer() && ___photonView.ViewID != 0) { ___photonView.RPC("GetValueRPC", (RpcTarget)1, new object[1] { ___value }); } return false; } } [HarmonyPatch(typeof(RunManager))] public class RunManagerPatch { [HarmonyPatch("ResetProgress")] [HarmonyPrefix] private static void ResetSkillDataManager() { SkillDataManager.instance = new SkillDataManager(); } [HarmonyPatch("MoonGetAttributes")] [HarmonyPostfix] private static void SkillPointsMessage(ref List<MoonAttribute> __result) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown string text = "Earn " + SkillDataManager.CalculatePointsEarned(1) + " skill points per level."; foreach (MoonAttribute item in __result) { if ((Object)(object)item.LocalizedText == (Object)null) { return; } } __result.Add(new MoonAttribute { text = text, LocalizedText = null }); } } [HarmonyPatch(typeof(ResultScreenUI))] public class ResultScreenUIPatch { [HarmonyPatch("FinishResultScreen")] [HarmonyPostfix] private static void AwardSkillPoints() { if (!GameManager.Multiplayer()) { Plugin.LogInfo("Awarding points. . ."); SkillNetworkSync.AwardSkillPointsForLevel(); } else if (PlayerHelper.IsHost()) { Plugin.LogInfo("Awarding points. . ."); SkillNetworkSync.AwardSkillPointsForLevel(); } } } [HarmonyPatch(typeof(MenuManager))] public class MenuManagerPatch { [HarmonyPatch("Start")] [HarmonyPostfix] public static void RegisterMenus(MenuManager __instance) { Plugin.LogInfo("Waiting to register menus..."); ((MonoBehaviour)__instance).StartCoroutine(AssetHelper.RegisterMenus(__instance)); } } [HarmonyPatch(typeof(MenuPageEsc))] public class MenuPageEscPatch { [HarmonyPatch("Start")] [HarmonyPostfix] public static void AddSkillsButton(MenuPageEsc __instance) { GameObject val = Object.Instantiate<GameObject>(AssetHelper.GetPrefab("Menu Button - Skills"), ((Component)__instance).transform); } } [HarmonyPatch(typeof(MenuPageLobby))] public class MenuPageLobbyPatch { [HarmonyPatch("Start")] [HarmonyPostfix] public static void Start() { Plugin.LogInfo("LOBBY PAGE START"); SkillNetworkSync.Initialize(); if (!PlayerHelper.IsHost()) { SkillDataManager.instance = new SkillDataManager(); } } [HarmonyPatch("ButtonStart")] [HarmonyPrefix] public static void OnGameStart(bool ___joiningPlayer) { if (!___joiningPlayer) { SkillNetworkSync.SyncAll(); } } } [HarmonyPatch(typeof(ShopManager))] public class ShopManagerPatch { [HarmonyPatch("GetAllItemsFromStatsManager")] [HarmonyPostfix] private static void RemoveItemUpgrades(ref List<Item> ___potentialItemUpgrades) { if (ConfigHelper.ShopUpgradesDisabled()) { ___potentialItemUpgrades.Clear(); } if (ConfigHelper.SkillPointsPurchaseable()) { ShopHelper.SpawnSkillCubes(___potentialItemUpgrades); } } } [HarmonyPatch(typeof(StatsManager))] public class StatsManagerPatch { [HarmonyPatch("Start")] [HarmonyPostfix] public static void RegisterSkillCubes(StatsManager __instance) { Plugin.LogInfo("Waiting to register skill cubes..."); ((MonoBehaviour)__instance).StartCoroutine(AssetHelper.RegisterSkillCubes()); } [HarmonyPatch("ItemPurchase")] [HarmonyPrefix] public static bool ItemPurchase(string itemName) { Plugin.LogInfo("Purchasing item: " + itemName); Plugin.LogInfo("Physical: " + StatsManager.instance.itemDictionary[itemName].physicalItem); if (itemName.Substring(0, 7) == "SP Cube") { return false; } return true; } [HarmonyPatch("SaveGame")] [HarmonyPostfix] private static void SaveSkills(string fileName) { SaveManager.Save(fileName); } [HarmonyPatch("LoadGame")] [HarmonyPostfix] private static void LoadSkills(string fileName) { SaveManager.Load(fileName); } } }