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 JGFoP v0.1.0
BepInEx/plugins/JGFoP.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Extensions; using Jotunn.Managers; using Jotunn.Utils; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("JGFoP")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("JGFoP")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("0.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.0.0")] namespace JGFoP; internal static class FoPConfig { internal static ConfigEntry<float> SuccessChance; internal static ConfigEntry<float> FailureChance; internal static ConfigEntry<float> BreakOnFailureChance; internal static ConfigEntry<int> LevelsLostOnFailure; internal static ConfigEntry<int> MinimumLevelOnFailure; internal static ConfigEntry<bool> FailureAtMinimumLevelBreaksItem; internal static ConfigEntry<bool> BreakReturnsItemAtLevel1; internal static ConfigEntry<float> BreakReturnIngredientsPercent; internal static ConfigEntry<int> MaxUpgradeLevel; internal static ConfigEntry<int> CostStart; internal static ConfigEntry<int> CostIncreasePerInterval; internal static ConfigEntry<int> CostIncreaseInterval; internal static ConfigEntry<int> CostScalingLevelStart; internal static ConfigEntry<float> UpgradeBaseDuration; internal static ConfigEntry<float> UpgradeDurationIncreasePerLevel; internal static void Bind(ConfigFile config) { AcceptableValueBase val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f); SuccessChance = ConfigFileExtensions.BindConfig<float>(config, "01 - Success and Failure", "Success Chance", 70f, "Relative chance that an upgrade attempt succeeds.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f); FailureChance = ConfigFileExtensions.BindConfig<float>(config, "01 - Success and Failure", "Failure Chance", 30f, "Relative chance that an upgrade attempt fails. Success and Failure are normalized as weights.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f); BreakOnFailureChance = ConfigFileExtensions.BindConfig<float>(config, "01 - Success and Failure", "Break On Failure Chance", 0f, "Percentage of failed upgrade attempts that break the item.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100); LevelsLostOnFailure = ConfigFileExtensions.BindConfig<int>(config, "02 - Failure Consequences", "Levels Lost On Failure", 1, "Number of upgrade levels lost after a normal failed attempt.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100); MinimumLevelOnFailure = ConfigFileExtensions.BindConfig<int>(config, "02 - Failure Consequences", "Minimum Level On Failure", 1, "Lowest upgrade level an item can be reduced to by normal failure.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); FailureAtMinimumLevelBreaksItem = ConfigFileExtensions.BindConfig<bool>(config, "02 - Failure Consequences", "Failure At Minimum Level Breaks Item", false, "If enabled, a failure while already at the minimum failure level becomes a break.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); BreakReturnsItemAtLevel1 = ConfigFileExtensions.BindConfig<bool>(config, "03 - Breaking", "Break Returns Item At Level 1", false, "If enabled, a broken item is returned at upgrade level 1 instead of being destroyed.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f); BreakReturnIngredientsPercent = ConfigFileExtensions.BindConfig<float>(config, "03 - Breaking", "Break Return Ingredients Percent", 0f, "Percentage of recoverable recipe ingredients returned when an item is destroyed by a break.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000); MaxUpgradeLevel = ConfigFileExtensions.BindConfig<int>(config, "04 - Upgrade Limits", "Max Upgrade Level", 100, "Maximum Forge of Potential upgrade level.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000); CostStart = ConfigFileExtensions.BindConfig<int>(config, "05 - Idol Cost", "Cost Start", 1, "Base number of idols required for an upgrade.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000); CostIncreasePerInterval = ConfigFileExtensions.BindConfig<int>(config, "05 - Idol Cost", "Cost Increase Per Interval", 1, "Number of additional idols required whenever a cost interval is reached.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000); CostIncreaseInterval = ConfigFileExtensions.BindConfig<int>(config, "05 - Idol Cost", "Cost Increase Interval", 2, "Number of upgrade levels between idol cost increases.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000); CostScalingLevelStart = ConfigFileExtensions.BindConfig<int>(config, "05 - Idol Cost", "Cost Scaling Level Start", 6, "Upgrade level at which idol cost scaling begins.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f); UpgradeBaseDuration = ConfigFileExtensions.BindConfig<float>(config, "06 - Upgrade Duration", "Base Crafting Time", 2f, "Base duration in seconds for a Forge of Potential upgrade.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f); UpgradeDurationIncreasePerLevel = ConfigFileExtensions.BindConfig<float>(config, "06 - Upgrade Duration", "Upgrade Duration Increase Per Level", 0f, "Additional crafting time in seconds added for each upgrade level.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); } } internal static class ForgePotentialPatches { private sealed class UpgradeAttemptState { internal string ItemPrefabName; internal int StartingQuality; internal ItemData OriginalItem; internal int Variant; internal long PlayerID; internal string PlayerName; internal bool ItemGivenBack; internal int QualityGivenBack; } [HarmonyPatch(typeof(InventoryGui), "SetupCrafting")] internal static class UpgradeDurationPatch { [HarmonyPrefix] private static void Prefix(ref float ___m_upgraderDuration, ref float ___m_upgraderDurationPerLevel) { ___m_upgraderDuration = Math.Max(0f, FoPConfig.UpgradeBaseDuration.Value); ___m_upgraderDurationPerLevel = Math.Max(0f, FoPConfig.UpgradeDurationIncreasePerLevel.Value); } } [HarmonyPatch(typeof(Requirement), "GetAmount")] internal static class UpgraderCostPatch { [HarmonyPostfix] private static void Postfix(Requirement __instance, int qualityLevel, ref int __result) { if (__instance != null && __instance.m_upgraderResource) { int num = qualityLevel - 1; int num2 = Math.Max(1, FoPConfig.CostStart.Value); int num3 = Math.Max(1, FoPConfig.CostScalingLevelStart.Value); int num4 = Math.Max(1, FoPConfig.CostIncreaseInterval.Value); int num5 = Math.Max(0, FoPConfig.CostIncreasePerInterval.Value); int num6 = num2; if (num >= num3) { int num7 = (num - num3) / num4 + 1; num6 += num7 * num5; } __result = Math.Max(1, num6); } } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class MaxUpgradeLevelPatch { [HarmonyPrefix] private static bool Prefix(Player player, ItemData ___m_craftUpgradeItem) { if ((Object)(object)player == (Object)null || ___m_craftUpgradeItem == null) { return true; } CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); if ((Object)(object)currentCraftingStation == (Object)null || !currentCraftingStation.m_upgrader) { return true; } int num = Math.Max(1, FoPConfig.MaxUpgradeLevel.Value); if (___m_craftUpgradeItem.m_quality < num) { return true; } MessageHud instance = MessageHud.instance; if (instance != null) { instance.ShowMessage((MessageType)2, $"Maximum upgrade level reached: {num}", 0, (Sprite)null, false, true); } return false; } } private sealed class SavedUpgradeChances { internal SharedData Shared; internal float UpgradeChance; internal float BreakChance; internal float BreakReturn; } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class UpgradeChancePatch { [HarmonyPrefix] private static void Prefix(Player player, Recipe ___m_craftRecipe, ItemData ___m_craftUpgradeItem, ref List<SavedUpgradeChances> __state) { __state = null; if ((Object)(object)player == (Object)null || ___m_craftUpgradeItem == null || (Object)(object)___m_craftRecipe == (Object)null) { return; } CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); if ((Object)(object)currentCraftingStation == (Object)null || !currentCraftingStation.m_upgrader) { return; } int num = Math.Max(1, FoPConfig.MaxUpgradeLevel.Value); if (___m_craftUpgradeItem.m_quality >= num || ___m_craftRecipe.m_resources == null) { return; } float num2 = Math.Max(0f, FoPConfig.SuccessChance.Value); float num3 = Math.Max(0f, FoPConfig.FailureChance.Value); float num4 = num2 + num3; float num5 = ((num4 > 0f) ? (num2 / num4) : 0f); float num6 = Math.Max(0f, Math.Min(100f, FoPConfig.BreakOnFailureChance.Value)) / 100f; float breakChance = (1f - num5) * num6; int num7 = Math.Max(1, FoPConfig.MinimumLevelOnFailure.Value); if (FoPConfig.FailureAtMinimumLevelBreaksItem.Value && ___m_craftUpgradeItem.m_quality <= num7) { breakChance = 1f - num5; } List<SavedUpgradeChances> list = new List<SavedUpgradeChances>(); Requirement[] resources = ___m_craftRecipe.m_resources; foreach (Requirement val in resources) { if (val == null || !val.m_upgraderResource || (Object)(object)val.m_resItem == (Object)null) { continue; } ItemData itemData = val.m_resItem.m_itemData; if (itemData != null && itemData.m_shared != null) { SharedData shared = itemData.m_shared; list.Add(new SavedUpgradeChances { Shared = shared, UpgradeChance = shared.m_upgradeChance, BreakChance = shared.m_breakChance, BreakReturn = shared.m_breakReturnIngreientsAmount }); shared.m_upgradeChance = num5; shared.m_breakChance = breakChance; if (FoPConfig.BreakReturnsItemAtLevel1.Value) { shared.m_breakReturnIngreientsAmount = 0f; } else { shared.m_breakReturnIngreientsAmount = Math.Max(0f, Math.Min(100f, FoPConfig.BreakReturnIngredientsPercent.Value)) / 100f; } } } if (list.Count > 0) { __state = list; } } [HarmonyPostfix] private static void Postfix(List<SavedUpgradeChances> __state) { if (__state == null) { return; } foreach (SavedUpgradeChances item in __state) { if (item?.Shared != null) { item.Shared.m_upgradeChance = item.UpgradeChance; item.Shared.m_breakChance = item.BreakChance; item.Shared.m_breakReturnIngreientsAmount = item.BreakReturn; } } } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class FailureLevelContextPatch { [HarmonyPrefix] private static void Prefix(Player player, Recipe ___m_craftRecipe, ItemData ___m_craftUpgradeItem) { _activeUpgrade = null; if (!((Object)(object)player == (Object)null) && !((Object)(object)___m_craftRecipe == (Object)null) && ___m_craftUpgradeItem != null && !((Object)(object)___m_craftRecipe.m_item == (Object)null)) { CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); if (!((Object)(object)currentCraftingStation == (Object)null) && currentCraftingStation.m_upgrader) { _activeUpgrade = new UpgradeAttemptState { ItemPrefabName = ((Object)((Component)___m_craftRecipe.m_item).gameObject).name, StartingQuality = ___m_craftUpgradeItem.m_quality, OriginalItem = ___m_craftUpgradeItem, Variant = ___m_craftUpgradeItem.m_variant, PlayerID = player.GetPlayerID(), PlayerName = player.GetPlayerName(), ItemGivenBack = false, QualityGivenBack = 0 }; } } } [HarmonyPostfix] private static void Postfix(Player player) { UpgradeAttemptState activeUpgrade = _activeUpgrade; _activeUpgrade = null; if (activeUpgrade != null && !((Object)(object)player == (Object)null)) { Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory != null && (activeUpgrade.OriginalItem == null || !inventory.ContainsItem(activeUpgrade.OriginalItem)) && !activeUpgrade.ItemGivenBack && FoPConfig.BreakReturnsItemAtLevel1.Value && inventory.AddItem(activeUpgrade.ItemPrefabName, 1, 1, activeUpgrade.Variant, activeUpgrade.PlayerID, activeUpgrade.PlayerName ?? "", false, false) == null) { Logger.LogWarning((object)("JGFoP could not return " + activeUpgrade.ItemPrefabName + " at level 1 after a break.")); } } } } [HarmonyPatch] internal static class FailedUpgradeQualityPatch { private static IEnumerable<MethodBase> TargetMethods() { MethodInfo[] methods = typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name != "AddItem" || methodInfo.ReturnType != typeof(ItemData)) { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); bool flag = false; bool flag2 = false; ParameterInfo[] array = parameters; foreach (ParameterInfo parameterInfo in array) { if (parameterInfo.ParameterType == typeof(string) && parameterInfo.Name == "name") { flag = true; } if (parameterInfo.ParameterType == typeof(int) && parameterInfo.Name == "quality") { flag2 = true; } } if (flag && flag2) { yield return methodInfo; } } } [HarmonyPrefix] private static void Prefix(string name, ref int quality) { if (_activeUpgrade == null || !string.Equals(name, _activeUpgrade.ItemPrefabName, StringComparison.Ordinal)) { return; } if (quality > _activeUpgrade.StartingQuality) { _activeUpgrade.ItemGivenBack = true; _activeUpgrade.QualityGivenBack = quality; return; } int num = Math.Max(0, FoPConfig.LevelsLostOnFailure.Value); int num2 = Math.Max(1, FoPConfig.MinimumLevelOnFailure.Value); int num3 = _activeUpgrade.StartingQuality - num; if (num3 < num2) { num3 = num2; } if (num3 > _activeUpgrade.StartingQuality) { num3 = _activeUpgrade.StartingQuality; } quality = num3; _activeUpgrade.ItemGivenBack = true; _activeUpgrade.QualityGivenBack = quality; } } private static UpgradeAttemptState _activeUpgrade; } [BepInPlugin("com.jgmods.jgfop", "JGFoP", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal class JGFoP : BaseUnityPlugin { public const string PluginGUID = "com.jgmods.jgfop"; public const string PluginName = "JGFoP"; public const string PluginVersion = "0.1.0"; public static CustomLocalization Localization = LocalizationManager.Instance.GetLocalization(); private Harmony _harmony; private void Awake() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown FoPConfig.Bind(((BaseUnityPlugin)this).Config); IdolRecipes.Register(); CustomLocalization localization = Localization; string text = "English"; string text2 = "msg_upgrader_failed"; localization.AddTranslation(ref text, ref text2, "Refinement failed."); _harmony = new Harmony("com.jgmods.jgfop"); _harmony.PatchAll(); Logger.LogInfo((object)"JGFoP has landed"); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class IdolRecipes { internal static void Register() { AddIdolPair(0, new(string, int)[4] { ("FineWood", 20), ("Tin", 10), ("GreydwarfEye", 10), ("TrophyEikthyr", 1) }); AddIdolPair(1, new(string, int)[3] { ("Bronze", 10), ("SurtlingCore", 1), ("TrophyTheElder", 1) }); AddIdolPair(2, new(string, int)[3] { ("Iron", 10), ("ElderBark", 5), ("TrophyBonemass", 1) }); AddIdolPair(3, new(string, int)[4] { ("Silver", 10), ("FreezeGland", 5), ("Obsidian", 5), ("TrophyDragonQueen", 1) }); AddIdolPair(4, new(string, int)[4] { ("BlackMetal", 10), ("Needle", 2), ("Tar", 5), ("TrophyGoblinKing", 1) }); AddIdolPair(5, new(string, int)[4] { ("BlackMarble", 20), ("BugMeat", 10), ("Carapace", 10), ("TrophySeekerQueen", 1) }); AddIdolPair(6, new(string, int)[3] { ("FlametalNew", 10), ("CharredBone", 15), ("TrophyFader", 1) }); AddIdolPair(7, new(string, int)[3] { ("Gold", 10), ("Coins", 40), ("FrozenKingDrop", 1) }); Logger.LogInfo((object)"Registered Forge recipes for all Forge of Potential idols."); } private static void AddIdolPair(int tier, (string Item, int Amount)[] requirements) { AddIdolRecipe($"Upgrader{tier}Armor", $"JGFoP_Upgrader{tier}Armor", requirements); AddIdolRecipe($"Upgrader{tier}Weapon", $"JGFoP_Upgrader{tier}Weapon", requirements); } private static void AddIdolRecipe(string idolPrefab, string recipeName, (string Item, int Amount)[] requirements) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown RecipeConfig val = new RecipeConfig { Name = recipeName, Item = idolPrefab, Amount = 1, CraftingStation = "forge", MinStationLevel = 1 }; for (int i = 0; i < requirements.Length; i++) { var (text, num) = requirements[i]; val.AddRequirement(text, num, 0); } ItemManager.Instance.AddRecipe(new CustomRecipe(val)); } }