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 ForgeOdds v0.1.0
plugins/ForgeOdds.dll
Decompiled 14 hours agousing System; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ForgeOdds.Core; using HarmonyLib; using Jotunn.Utils; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("ForgeOdds")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+b58fe41431997a909b4c1db87a6bff19307b4f9b")] [assembly: AssemblyProduct("ForgeOdds")] [assembly: AssemblyTitle("ForgeOdds")] [assembly: AssemblyVersion("0.1.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 ForgeOdds { [BepInPlugin("sansara.ForgeOdds", "Forge Odds", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "sansara.ForgeOdds"; public const string Version = "0.1.0"; internal static ManualLogSource Log; private void Awake() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; PluginConfig.Bind(((BaseUnityPlugin)this).Config); new Harmony("sansara.ForgeOdds").PatchAll(typeof(Plugin).Assembly); Log.LogInfo((object)("Forge Odds 0.1.0 loaded: " + PluginConfig.Describe())); } } internal static class PluginConfig { private static ConfigEntry<bool> _enabled; private static ConfigEntry<float> _basePercent; private static ConfigEntry<int> _flatUpToLevel; private static ConfigEntry<float> _dropPerLevelPercent; private static ConfigEntry<float> _minPercent; public static OddsCurve Curve { get; private set; } public static bool Enabled => _enabled.Value; public static void Bind(ConfigFile cfg) { _enabled = cfg.Bind<bool>("Odds (server)", "Enabled", true, Description("Шанс улучшения в Кузнице потенциала по кривой ниже. false — ванильный шанс идола (65 %).")); _basePercent = cfg.Bind<float>("Odds (server)", "BaseChancePercent", 90f, Description("Шанс успеха до уровня FlatUpToLevel включительно (уровень — качество предмета после улучшения), %.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f))); _flatUpToLevel = cfg.Bind<int>("Odds (server)", "FlatUpToLevel", 10, Description("До какого уровня (включительно) действует BaseChancePercent.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000))); _dropPerLevelPercent = cfg.Bind<float>("Odds (server)", "DropPerLevelPercent", 10f, Description("На сколько процентных пунктов шанс падает за каждый уровень выше FlatUpToLevel.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f))); _minPercent = cfg.Bind<float>("Odds (server)", "MinChancePercent", 20f, Description("Нижний предел шанса, %. Не выше BaseChancePercent.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f))); Rebuild(log: false); _basePercent.SettingChanged += delegate { Rebuild(log: true); }; _flatUpToLevel.SettingChanged += delegate { Rebuild(log: true); }; _dropPerLevelPercent.SettingChanged += delegate { Rebuild(log: true); }; _minPercent.SettingChanged += delegate { Rebuild(log: true); }; _enabled.SettingChanged += delegate { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("Forge Odds: " + Describe())); } }; } public static string Describe() { if (!_enabled.Value) { return "выключено, ванильный шанс"; } return $"до {Curve.FlatUpToLevel} ур. {OddsCurve.FormatPercent(Curve.BasePercent)}, дальше −{Curve.DropPerLevelPercent} за уровень, " + "не ниже " + OddsCurve.FormatPercent(Curve.MinPercent); } private static void Rebuild(bool log) { Curve = new OddsCurve(_basePercent.Value, _flatUpToLevel.Value, _dropPerLevelPercent.Value, _minPercent.Value); if (log) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("Forge Odds: " + Describe())); } } } private static ConfigDescription Description(string text, AcceptableValueBase range = null) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown return new ConfigDescription(text, range, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } }); } } } namespace ForgeOdds.Core { public sealed class OddsCurve { public float BasePercent { get; } public int FlatUpToLevel { get; } public float DropPerLevelPercent { get; } public float MinPercent { get; } public OddsCurve(float basePercent, int flatUpToLevel, float dropPerLevelPercent, float minPercent) { BasePercent = Clamp(basePercent, 0f, 100f); FlatUpToLevel = Math.Max(0, flatUpToLevel); DropPerLevelPercent = Clamp(dropPerLevelPercent, 0f, 100f); MinPercent = Clamp(minPercent, 0f, BasePercent); } public float ChancePercent(int targetLevel) { int num = Math.Max(0, targetLevel - FlatUpToLevel); return Math.Max(MinPercent, BasePercent - DropPerLevelPercent * (float)num); } public float Chance(int targetLevel) { return ChancePercent(targetLevel) / 100f; } public static string FormatPercent(float percent) { float num = (float)Math.Round(percent, 1); return ((num == (float)Math.Round(num)) ? ((int)Math.Round(num)).ToString(CultureInfo.InvariantCulture) : num.ToString("0.0", CultureInfo.InvariantCulture).Replace('.', ',')) + " %"; } private static float Clamp(float value, float min, float max) { if (float.IsNaN(value)) { return min; } if (!(value < min)) { if (!(value > max)) { return value; } return max; } return min; } } } namespace ForgeOdds.Patches { [HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")] internal static class ChanceDisplayPatch { private static Func<InventoryGui, Recipe> _selectedRecipe; private static Func<InventoryGui, ItemData> _selectedItem; private static bool Prepare() { try { _selectedRecipe = Getter<Recipe>("Recipe"); _selectedItem = Getter<ItemData>("ItemData"); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Forge Odds: шанс в окне кузницы не показывается: " + ex.Message)); return false; } if (_selectedRecipe != null && _selectedItem != null) { return true; } Plugin.Log.LogWarning((object)"Forge Odds: InventoryGui.m_selectedRecipe не найден, шанс в окне кузницы не показывается."); return false; } private static void Postfix(InventoryGui __instance) { if (PluginConfig.Enabled && !((Object)(object)__instance.m_recipeDecription == (Object)null) && ForgeStation.IsActive()) { ItemData val = _selectedItem(__instance); SharedData val2 = ((val != null) ? ForgeStation.UpgraderResource(_selectedRecipe(__instance)) : null); if (val2 != null) { float percent = PluginConfig.Curve.ChancePercent(val.m_quality + 1); string text = ((val2.m_breakChance >= 1f) ? "предмет ломается" : "предмет может сломаться или потерять уровень"); TMP_Text recipeDecription = __instance.m_recipeDecription; recipeDecription.text = recipeDecription.text + "\n\n<color=orange>Шанс успеха: " + OddsCurve.FormatPercent(percent) + ". При неудаче " + text + ".</color>"; } } } private static Func<InventoryGui, T> Getter<T>(string property) { FieldInfo fieldInfo = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe"); if (fieldInfo == null || !fieldInfo.FieldType.IsValueType) { return null; } MethodInfo methodInfo = fieldInfo.FieldType.GetProperty(property, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetGetMethod(nonPublic: true); if (methodInfo == null || methodInfo.ReturnType != typeof(T)) { return null; } DynamicMethod dynamicMethod = new DynamicMethod("ForgeOdds_SelectedRecipe_" + property, typeof(T), new Type[1] { typeof(InventoryGui) }, typeof(InventoryGui), skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldflda, fieldInfo); iLGenerator.Emit(OpCodes.Call, methodInfo); iLGenerator.Emit(OpCodes.Ret); return (Func<InventoryGui, T>)dynamicMethod.CreateDelegate(typeof(Func<InventoryGui, T>)); } } internal static class ForgeStation { public static bool IsActive() { CraftingStation val = (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetCurrentCraftingStation() : null); if ((Object)(object)val != (Object)null) { return val.m_upgrader; } return false; } public static SharedData UpgraderResource(Recipe recipe) { if ((Object)(object)recipe == (Object)null || recipe.m_resources == null) { return null; } Requirement[] resources = recipe.m_resources; foreach (Requirement val in resources) { if (val != null && val.m_upgraderResource && (Object)(object)val.m_resItem != (Object)null) { return val.m_resItem.m_itemData?.m_shared; } } return null; } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class UpgraderRollPatch { internal sealed class Saved { public SharedData Shared; public float Chance; } private static void Prefix(Recipe ___m_craftRecipe, ItemData ___m_craftUpgradeItem, out Saved __state) { __state = null; if (PluginConfig.Enabled && ___m_craftUpgradeItem != null && ForgeStation.IsActive()) { SharedData val = ForgeStation.UpgraderResource(___m_craftRecipe); if (val != null) { int num = ___m_craftUpgradeItem.m_quality + 1; __state = new Saved { Shared = val, Chance = val.m_upgradeChance }; val.m_upgradeChance = PluginConfig.Curve.Chance(num); Plugin.Log.LogDebug((object)$"Forge Odds: {___m_craftUpgradeItem.m_shared.m_name} → {num}, шанс {val.m_upgradeChance:0.###}"); } } } private static void Finalizer(Saved __state) { if (__state != null) { __state.Shared.m_upgradeChance = __state.Chance; } } } }