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 BudylivSkillRates v1.1.1
plugins/BudylivSkillRates.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("0.0.0.0")] [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; } } } namespace BudylivSkillRates { public static class FoodXp { public static string Context; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<float> IngredientBonus; internal static ConfigEntry<float> TierBonus; internal static ConfigEntry<string> Tiers; internal const string DefaultTiers = "1:RawMeat,CookedMeat,DeerMeat,CookedDeerMeat,NeckTail,NeckTailGrilled,Honey,Raspberry,Mushroom,Dandelion,Fish1,FishRaw,FishCooked;2:Blueberries,Carrot,Thistle,MushroomYellow,GreydwarfEye,BjornMeat,CookedBjornMeat,Fish2,SpiceForests,CuredSquirrelHamstring;3:Turnip,Bloodbag,Entrails,Ooze,SerpentMeat,SerpentMeatCooked,Fish3,Fish5,Fish6,Fish8,Fish9,SpiceOceans,FreshSeaweed,TrophySerpent,TrophyAbomination;4:Onion,WolfMeat,CookedWolfMeat,FreezeGland,Fish4_cave,SpiceMountains,PowderedDragonEgg,TrophyFenring,TrophyHatchling;5:Barley,BarleyFlour,Cloudberry,LoxMeat,CookedLoxMeat,ChickenEgg,ChickenMeat,CookedChickenMeat,Fish7,SpicePlains,PungentPebbles,TrophyGoblin,TrophyLox;6:BugMeat,CookedBugMeat,HareMeat,CookedHareMeat,MushroomJotunPuffs,MushroomMagecap,RoyalJelly,Sap,GiantBloodSack,Fish12,SpiceMistlands;7:AsksvinMeat,CookedAsksvinMeat,VoltureMeat,CookedVoltureMeat,VoltureEgg,Vineberry,Fiddleheadfern,MushroomSmokePuff,Fish11,SpiceAshlands,ScaleHide,TrophyCharredMelee;8:Oat,OatFlour,OatMilk,Kale,Poteitr,Lingonberry,MooseMeat,CookedMooseMeat,SealBlubber,Ice,Fish10,SpiceDeepNorth,TrophyFrostTroll"; private static Dictionary<string, int> _table = new Dictionary<string, int>(); private static readonly Dictionary<string, (int Count, int Tier)> Cache = new Dictionary<string, (int, int)>(); private static Dictionary<string, Recipe> _recipes; private static Dictionary<string, string> _cookedFrom; private static ObjectDB _indexedDb; internal static void Bind(ConfigFile config) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown Enabled = config.Bind<bool>("Cooking", "FoodDependentXP", true, new ConfigDescription("Cooking XP depends on the dish: more distinct ingredients and later-game ingredients give more.", (AcceptableValueBase)null, new object[1] { Admin() })); IngredientBonus = config.Bind<float>("Cooking", "IngredientBonus", 0.25f, new ConfigDescription("Extra multiplier per distinct ingredient after the first (0.25: 3 ingredients = x1.5).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), new object[1] { Admin() })); TierBonus = config.Bind<float>("Cooking", "TierBonus", 0.5f, new ConfigDescription("Extra multiplier per ingredient tier above 1 (0.5: tier 8 = x4.5).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), new object[1] { Admin() })); Tiers = config.Bind<string>("Cooking", "IngredientTiers", "1:RawMeat,CookedMeat,DeerMeat,CookedDeerMeat,NeckTail,NeckTailGrilled,Honey,Raspberry,Mushroom,Dandelion,Fish1,FishRaw,FishCooked;2:Blueberries,Carrot,Thistle,MushroomYellow,GreydwarfEye,BjornMeat,CookedBjornMeat,Fish2,SpiceForests,CuredSquirrelHamstring;3:Turnip,Bloodbag,Entrails,Ooze,SerpentMeat,SerpentMeatCooked,Fish3,Fish5,Fish6,Fish8,Fish9,SpiceOceans,FreshSeaweed,TrophySerpent,TrophyAbomination;4:Onion,WolfMeat,CookedWolfMeat,FreezeGland,Fish4_cave,SpiceMountains,PowderedDragonEgg,TrophyFenring,TrophyHatchling;5:Barley,BarleyFlour,Cloudberry,LoxMeat,CookedLoxMeat,ChickenEgg,ChickenMeat,CookedChickenMeat,Fish7,SpicePlains,PungentPebbles,TrophyGoblin,TrophyLox;6:BugMeat,CookedBugMeat,HareMeat,CookedHareMeat,MushroomJotunPuffs,MushroomMagecap,RoyalJelly,Sap,GiantBloodSack,Fish12,SpiceMistlands;7:AsksvinMeat,CookedAsksvinMeat,VoltureMeat,CookedVoltureMeat,VoltureEgg,Vineberry,Fiddleheadfern,MushroomSmokePuff,Fish11,SpiceAshlands,ScaleHide,TrophyCharredMelee;8:Oat,OatFlour,OatMilk,Kale,Poteitr,Lingonberry,MooseMeat,CookedMooseMeat,SealBlubber,Ice,Fish10,SpiceDeepNorth,TrophyFrostTroll", new ConfigDescription("Ingredient tiers: 'tier:Prefab,Prefab;tier:...' (1 Meadows, 2 Black Forest, 3 Swamp/Ocean, 4 Mountains, 5 Plains, 6 Mistlands, 7 Ashlands, 8 Deep North). Unlisted crafted foods take the highest tier of their ingredients, other items tier 1.", (AcceptableValueBase)null, new object[1] { Admin() })); ParseTable(); Tiers.SettingChanged += delegate { ParseTable(); }; IngredientBonus.SettingChanged += delegate { Cache.Clear(); }; TierBonus.SettingChanged += delegate { Cache.Clear(); }; static ConfigurationManagerAttributes Admin() { //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_000d: Expected O, but got Unknown return new ConfigurationManagerAttributes { IsAdminOnly = true }; } } private static void ParseTable() { Dictionary<string, int> dictionary = new Dictionary<string, int>(); string[] array = (Tiers.Value ?? "").Split(';'); foreach (string text in array) { int num = text.IndexOf(':'); if (num <= 0 || !int.TryParse(text.Substring(0, num).Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { continue; } string[] array2 = text.Substring(num + 1).Split(','); foreach (string text2 in array2) { if (text2.Trim().Length > 0) { dictionary[text2.Trim()] = Mathf.Clamp(result, 1, 20); } } } _table = dictionary; Cache.Clear(); } private static bool EnsureIndex() { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Invalid comparison between Unknown and I4 if ((Object)(object)ObjectDB.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null) { return false; } if (_recipes != null && _indexedDb == ObjectDB.instance) { return true; } _indexedDb = ObjectDB.instance; _recipes = new Dictionary<string, Recipe>(); foreach (Recipe recipe in ObjectDB.instance.m_recipes) { if (!((Object)(object)recipe == (Object)null) && !((Object)(object)recipe.m_item == (Object)null) && recipe.m_enabled && !((Object)(object)recipe.m_craftingStation == (Object)null) && (int)recipe.m_craftingStation.m_craftingSkill == 105) { string name = ((Object)((Component)recipe.m_item).gameObject).name; if (!_recipes.ContainsKey(name)) { _recipes[name] = recipe; } } } _cookedFrom = new Dictionary<string, string>(); foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { CookingStation val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<CookingStation>() : null); if ((Object)(object)val == (Object)null || val.m_conversion == null) { continue; } foreach (ItemConversion item in val.m_conversion) { if ((Object)(object)item?.m_from != (Object)null && (Object)(object)item.m_to != (Object)null && !_cookedFrom.ContainsKey(((Object)((Component)item.m_to).gameObject).name)) { _cookedFrom[((Object)((Component)item.m_to).gameObject).name] = ((Object)((Component)item.m_from).gameObject).name; } } } Cache.Clear(); Plugin.Log.LogInfo((object)$"Food XP: {_recipes.Count} cooking recipes, {_cookedFrom.Count} cooking station products, {_table.Count} items in the tier table."); return true; } private static IEnumerable<string> Ingredients(Recipe r) { return (from q in r.m_resources where q != null && (Object)(object)q.m_resItem != (Object)null && q.m_amount > 0 select ((Object)((Component)q.m_resItem).gameObject).name).Distinct(); } private static int Tier(string name, int depth) { if (_table.TryGetValue(name, out var value)) { return value; } if (depth > 8) { return 1; } if (_recipes.TryGetValue(name, out var value2)) { List<int> list = (from i in Ingredients(value2) select Tier(i, depth + 1)).ToList(); if (list.Count == 0) { return 1; } if (!value2.m_requireOnlyOneIngredient) { return list.Max(); } return list.Min(); } if (_cookedFrom.TryGetValue(name, out var value3)) { return Tier(value3, depth + 1); } return 1; } private static (int Count, int Tier) Complexity(string name, int depth) { if (Cache.TryGetValue(name, out (int, int) value)) { return value; } Recipe value2; string value3; (int, int) tuple = (_recipes.TryGetValue(name, out value2) ? (value2.m_requireOnlyOneIngredient ? 1 : Math.Max(1, Ingredients(value2).Count()), Tier(name, 0)) : ((depth >= 8 || !_cookedFrom.TryGetValue(name, out value3)) ? (1, Tier(name, 0)) : Complexity(value3, depth + 1))); Cache[name] = tuple; return tuple; } internal static float Multiplier(string prefab) { if (string.IsNullOrEmpty(prefab) || Enabled == null || !Enabled.Value || !EnsureIndex()) { return 1f; } var (num, num2) = Complexity(prefab, 0); return (1f + IngredientBonus.Value * (float)(num - 1)) * (1f + TierBonus.Value * (float)(num2 - 1)); } public static void RaiseCooking(string prefab, float amount) { if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } Context = prefab; try { ((Character)Player.m_localPlayer).RaiseSkill((SkillType)105, amount); } finally { Context = null; } } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class DoCraftingPatch { private static readonly FieldRef<InventoryGui, Recipe> CraftRecipe = AccessTools.FieldRefAccess<InventoryGui, Recipe>("m_craftRecipe"); private static void Prefix(InventoryGui __instance) { Recipe val = CraftRecipe.Invoke(__instance); FoodXp.Context = (((Object)(object)val != (Object)null && (Object)(object)val.m_item != (Object)null) ? ((Object)((Component)val.m_item).gameObject).name : null); } private static void Finalizer() { FoodXp.Context = null; } } [HarmonyPatch(typeof(CookingStation), "OnInteract")] internal static class CookingInteractPatch { private static readonly FieldRef<CookingStation, ZNetView> NView = AccessTools.FieldRefAccess<CookingStation, ZNetView>("m_nview"); private static readonly Func<CookingStation, bool> HaveDoneItem = AccessTools.MethodDelegate<Func<CookingStation, bool>>(AccessTools.Method(typeof(CookingStation), "HaveDoneItem", (Type[])null, (Type[])null), (object)null, true); private static readonly Func<CookingStation, string, bool> IsItemDone = AccessTools.MethodDelegate<Func<CookingStation, string, bool>>(AccessTools.Method(typeof(CookingStation), "IsItemDone", (Type[])null, (Type[])null), (object)null, true); private static readonly Func<CookingStation, Inventory, ItemData> FindCookableItem = AccessTools.MethodDelegate<Func<CookingStation, Inventory, ItemData>>(AccessTools.Method(typeof(CookingStation), "FindCookableItem", (Type[])null, (Type[])null), (object)null, true); private static void Prefix(CookingStation __instance, Humanoid user) { FoodXp.Context = null; try { ZNetView obj = NView.Invoke(__instance); ZDO val = ((obj != null) ? obj.GetZDO() : null); if (val == null) { return; } if (HaveDoneItem(__instance)) { for (int i = 0; i < __instance.m_slots.Length; i++) { string text = val.GetString("slot" + i, ""); if (text != "" && IsItemDone(__instance, text)) { FoodXp.Context = text; break; } } } else if ((Object)(object)user != (Object)null) { ItemData obj2 = FindCookableItem(__instance, user.GetInventory()); object context; if (obj2 == null) { context = null; } else { GameObject dropPrefab = obj2.m_dropPrefab; context = ((dropPrefab != null) ? ((Object)dropPrefab).name : null); } FoodXp.Context = (string)context; } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Food XP: cooking station lookup failed: " + ex.Message)); } } private static void Finalizer() { FoodXp.Context = null; } } [BepInPlugin("com.budyliv.skillrates", "Budyliv Skill Rates", "1.1.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string Guid = "com.budyliv.skillrates"; public const string Name = "Budyliv Skill Rates"; public const string Version = "1.1.1"; internal static readonly Dictionary<SkillType, ConfigEntry<float>> Rates = new Dictionary<SkillType, ConfigEntry<float>>(); internal static ConfigEntry<bool> CarryOver; internal static ManualLogSource Log; private static readonly HashSet<SkillType> Fast = new HashSet<SkillType> { (SkillType)10, (SkillType)108, (SkillType)103, (SkillType)107, (SkillType)12, (SkillType)13 }; private void Awake() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Invalid comparison between Unknown and I4 //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Invalid comparison between Unknown and I4 //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Expected O, but got Unknown //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; CarryOver = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "CarryOverXP", true, new ConfigDescription("Carry XP left over after a level-up to the next level (only for skills whose rate is not 1). Vanilla throws it away.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); foreach (SkillType value in Enum.GetValues(typeof(SkillType))) { if ((int)value != 0 && (int)value != 999) { float num = (((int)value == 105) ? 1f : (Fast.Contains(value) ? 10f : 3f)); Rates[value] = ((BaseUnityPlugin)this).Config.Bind<float>("Rates", ((object)value/*cast due to .constrained prefix*/).ToString(), num, new ConfigDescription("XP multiplier for this skill (1 = vanilla, 0 = no XP). Applied on top of the world skill gain modifier.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); } } FoodXp.Bind(((BaseUnityPlugin)this).Config); Harmony val2 = new Harmony("com.budyliv.skillrates"); val2.PatchAll(typeof(RaiseSkillPatch)); val2.PatchAll(typeof(DoCraftingPatch)); val2.PatchAll(typeof(CookingInteractPatch)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Budyliv Skill Rates 1.1.1 loaded"); } } [HarmonyPatch(typeof(Skills), "RaiseSkill")] internal static class RaiseSkillPatch { private static readonly Func<Skills, SkillType, Skill> GetSkill = AccessTools.MethodDelegate<Func<Skills, SkillType, Skill>>(AccessTools.Method(typeof(Skills), "GetSkill", (Type[])null, (Type[])null), (object)null, true); private static bool _inside; [HarmonyPriority(200)] private static bool Prefix(Skills __instance, SkillType skillType, ref float factor) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) if (_inside) { return true; } if ((int)skillType == 105 && FoodXp.Context != null) { factor *= FoodXp.Multiplier(FoodXp.Context); } if (!Plugin.Rates.TryGetValue(skillType, out var value)) { return true; } float value2 = value.Value; if (Mathf.Approximately(value2, 1f)) { return true; } if (value2 <= 0f) { return false; } if (factor <= 0f || !Plugin.CarryOver.Value) { factor *= value2; return true; } Skill val = GetSkill(__instance, skillType); float num = val.m_info.m_increseStep * Game.m_skillGainRate; if (num <= 0f) { factor *= value2; return true; } float num2 = num * factor * value2; _inside = true; try { for (int i = 0; i < 101; i++) { if (!(num2 > 1E-06f)) { break; } if (!(val.m_level < 100f)) { break; } float num3 = Mathf.Pow(Mathf.Floor(val.m_level + 1f), 1.5f) * 0.5f + 0.5f - val.m_accumulator; if (num3 < 0.0001f) { num3 = 0.0001f; } if (num2 >= num3) { float level = val.m_level; __instance.RaiseSkill(skillType, num3 * 1.0001f / num); num2 -= num3; if (val.m_level <= level) { break; } } else { __instance.RaiseSkill(skillType, num2 / num); num2 = 0f; } } } finally { _inside = false; } return false; } } }