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 CraftingXP v1.6.2
CraftingXP_v1.6.2.dll
Decompiled 2 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; 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: AssemblyCompany("CraftingXP")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.6.2.0")] [assembly: AssemblyInformationalVersion("1.6.2")] [assembly: AssemblyProduct("CraftingXP")] [assembly: AssemblyTitle("CraftingXP")] [assembly: AssemblyVersion("1.6.2.0")] namespace CraftingXP; [BepInPlugin("frost.craftingxp", "CraftingXP", "1.6.2")] public class CraftingXPPlugin : BaseUnityPlugin { public const string PluginGuid = "frost.craftingxp"; public const string PluginName = "CraftingXP"; public const string PluginVersion = "1.6.2"; internal static ManualLogSource Log; internal static ConfigEntry<float> GlobalMultiplier; internal static ConfigEntry<float> BuildMultiplier; internal static ConfigEntry<float> BonusPerPowerPoint; internal static ConfigEntry<float> MaxXP; internal static ConfigEntry<int> RemoveGrace; internal static ConfigEntry<float> BonusPerBarTier; internal static ConfigEntry<string> BarTiersConfig; private void Awake() { //IL_0140: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; GlobalMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("CraftingXP", "GlobalMultiplier", 2f, "Во сколько раз усиливается весь опыт Ремесла (крафт, постройка, ремонт)"); BuildMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("CraftingXP", "BuildMultiplier", 8f, "Дополнительный множитель опыта ТОЛЬКО за постановку деталей молотом, применяется поверх GlobalMultiplier: ваниль 0.25 × Global 2 × Build 8 = 4 XP за деталь. На крафт и ремонт не действует. Потолок MaxXP действует и здесь — если хочешь больше 5 XP за деталь, подними и MaxXP"); BonusPerPowerPoint = ((BaseUnityPlugin)this).Config.Bind<float>("CraftingXP", "BonusPerPowerPoint", 0.02f, "Бонусный опыт за каждую единицу силы крафтимой вещи (урон, броня или блок)"); MaxXP = ((BaseUnityPlugin)this).Config.Bind<float>("CraftingXP", "MaxXP", 5f, "Максимум опыта за одно действие"); RemoveGrace = ((BaseUnityPlugin)this).Config.Bind<int>("CraftingXP", "RemoveGrace", 3, "Сколько построек подряд можно снести молотом без потери опыта (долг за снос не больше этого числа прощается; дальше долг = числу снесённого)"); BonusPerBarTier = ((BaseUnityPlugin)this).Config.Bind<float>("CraftingXP", "BonusPerBarTier", 1f, "Опыт за одну заложенную руду = тир металла × это число (тиры в BarTiers). В ванили плавка не даёт опыта вообще. Потолок MaxXP на плавку не действует — значение ограничено только старшим тиром"); BarTiersConfig = ((BaseUnityPlugin)this).Config.Bind<string>("CraftingXP", "BarTiers", "Copper:1,Tin:1,Bronze:2,Iron:3,Silver:4,BlackMetal:5,EitrInfusedIron:6,Flametal:7", "Тиры слитков: ИмяПрефаба:тир, через запятую. Сравнение по полному имени, регистр не важен. Если у тебя другое название слитка эйтр-стали — посмотри его в LogOutput.log (строка 'Слиток без тира') и впиши сюда"); BarTiers.Parse(BarTiersConfig.Value); BarTiersConfig.SettingChanged += delegate { BarTiers.Parse(BarTiersConfig.Value); }; new Harmony("frost.craftingxp").PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"CraftingXP 1.6.2 загружен"); } } internal static class CraftContext { public const float None = -1f; public static float Power = -1f; } internal static class BuildContext { public static bool Pending; } internal static class SmeltContext { public const float None = -1f; public static float XP = -1f; } internal static class BarTiers { private static readonly List<KeyValuePair<string, int>> _tiers = new List<KeyValuePair<string, int>>(); private static readonly HashSet<string> _reportedUnknown = new HashSet<string>(); public static void Parse(string config) { _tiers.Clear(); string[] array = config.Split(','); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(':'); if (array2.Length == 2 && int.TryParse(array2[1].Trim(), out var result) && array2[0].Trim().Length > 0) { _tiers.Add(new KeyValuePair<string, int>(array2[0].Trim(), result)); } } CraftingXPPlugin.Log.LogInfo((object)("Тиры слитков: " + config)); } public static int GetTier(string prefabName, string sharedName) { string text = ((prefabName != null) ? prefabName.Replace("(Clone)", "") : ""); string b = ((sharedName != null && sharedName.StartsWith("$item_")) ? sharedName.Substring(6) : (sharedName ?? "")); foreach (KeyValuePair<string, int> tier in _tiers) { if (string.Equals(tier.Key, text, StringComparison.OrdinalIgnoreCase) || string.Equals(tier.Key, b, StringComparison.OrdinalIgnoreCase)) { return tier.Value; } } ReportUnknown(text); return 0; } private static void ReportUnknown(string prefab) { if (!string.IsNullOrEmpty(prefab)) { string text = prefab.ToLowerInvariant(); if ((text.Contains("metal") || text.Contains("eitr") || text.Contains("flame") || text.Contains("copper") || text.Contains("tin") || text.Contains("bronze") || text.Contains("iron") || text.Contains("silver")) && _reportedUnknown.Add(text)) { CraftingXPPlugin.Log.LogInfo((object)("Слиток без тира: " + prefab + " — можно добавить в BarTiers в конфиге")); } } } } [HarmonyPatch(typeof(Smelter), "OnAddOre")] internal static class Smelter_OnAddOre_Patch { private static readonly FieldInfo ConversionField = AccessTools.Field(typeof(Smelter), "m_conversion"); private static void Postfix(Smelter __instance, Humanoid user, ItemData item, bool __result) { if (!__result) { return; } Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return; } ItemConversion val2 = FindConversion(__instance, user, item); if (val2 == null) { return; } ItemDrop to = val2.m_to; if (!((Object)(object)to == (Object)null) && to.m_itemData != null && to.m_itemData.m_shared != null) { int tier = BarTiers.GetTier(((Object)((Component)to).gameObject).name, to.m_itemData.m_shared.m_name); if (tier > 0) { float num = (SmeltContext.XP = (float)tier * CraftingXPPlugin.BonusPerBarTier.Value); ((Character)val).RaiseSkill((SkillType)107, num); CraftingXPPlugin.Log.LogInfo((object)string.Format("Руда в печь ({0} → {1}): +{2:F2} XP (тир {3})", (item != null && (Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : "?", ((Object)((Component)to).gameObject).name, num, tier)); } } } private static ItemConversion FindConversion(Smelter smelter, Humanoid user, ItemData item) { if (!(ConversionField?.GetValue(smelter) is IEnumerable<ItemConversion> enumerable)) { return null; } string text = ((item != null && (Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : null); foreach (ItemConversion item2 in enumerable) { if (item2 == null || (Object)(object)item2.m_from == (Object)null || (Object)(object)item2.m_to == (Object)null) { continue; } if (text != null) { if (((Object)((Component)item2.m_from).gameObject).name == text) { return item2; } } else if (user.GetInventory() != null && user.GetInventory().GetItem(item2.m_from.m_itemData.m_shared.m_name, -1, false) != null) { return item2; } } return null; } } [HarmonyPatch(typeof(Player), "RaiseSkill")] internal static class Player_RaiseSkill_Patch { private static float _nextLogTime; private static void Prefix(Player __instance, SkillType skill, ref float value) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 if ((int)skill != 107 || value <= 0f) { return; } float xP = SmeltContext.XP; SmeltContext.XP = -1f; if (xP > 0f) { value = xP; return; } bool pending = BuildContext.Pending; BuildContext.Pending = false; if (pending) { value = Mathf.Min(value * CraftingXPPlugin.GlobalMultiplier.Value * CraftingXPPlugin.BuildMultiplier.Value, CraftingXPPlugin.MaxXP.Value); if (Time.time >= _nextLogTime) { _nextLogTime = Time.time + 10f; CraftingXPPlugin.Log.LogInfo((object)$"XP за деталь: {value:F2}"); } return; } float num = ((CraftContext.Power > 0f) ? CraftContext.Power : 0f); CraftContext.Power = -1f; value = Mathf.Min(value * CraftingXPPlugin.GlobalMultiplier.Value + num * CraftingXPPlugin.BonusPerPowerPoint.Value, CraftingXPPlugin.MaxXP.Value); if (Time.time >= _nextLogTime) { _nextLogTime = Time.time + 10f; CraftingXPPlugin.Log.LogInfo((object)$"Crafting XP: {value:F2} (сила вещи: {num:F0})"); } } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] internal static class Player_TryPlacePiece_Patch { private static void Postfix(bool __result) { if (__result) { BuildContext.Pending = true; } } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class InventoryGui_DoCrafting_Patch { private static void Prefix(InventoryGui __instance) { try { object? obj = AccessTools.Field(typeof(InventoryGui), "m_craftRecipe")?.GetValue(__instance); CraftContext.Power = CraftMath.CraftPower(((Recipe)(((obj is Recipe) ? obj : null)?)).m_item?.m_itemData?.m_shared); } catch (Exception ex) { Debug.LogError((object)("[CraftingXP] Ошибка расчёта силы вещи: " + ex)); } } } [HarmonyPatch(typeof(Player), "UpdatePlacement")] internal static class Player_UpdatePlacement_Patch { private static readonly FieldInfo DebtField = AccessTools.Field(typeof(Player), "m_buildRemoveDebt"); private static int _debtBefore; private static void Prefix(Player __instance) { BuildContext.Pending = false; _debtBefore = ((DebtField != null) ? ((int)DebtField.GetValue(__instance)) : 0); } private static void Postfix(Player __instance) { BuildContext.Pending = false; if (DebtField == null) { return; } int num = (int)DebtField.GetValue(__instance); if (num <= _debtBefore) { if (_debtBefore > 0 && num == 0) { ((Character)__instance).Message((MessageType)2, "Штраф за снос снят — опыт за постройки вернулся", 0, (Sprite)null, false); CraftingXPPlugin.Log.LogInfo((object)"Долг за снос полностью выплачен"); } } else if (num <= CraftingXPPlugin.RemoveGrace.Value) { DebtField.SetValue(__instance, 0); CraftingXPPlugin.Log.LogInfo((object)$"Снос прощён (льгота {CraftingXPPlugin.RemoveGrace.Value}): долг {num} → 0"); } else { if (_debtBefore <= CraftingXPPlugin.RemoveGrace.Value) { ((Character)__instance).Message((MessageType)2, $"Штраф за снос: следующие {num} построек без опыта Ремесла", 0, (Sprite)null, false); } CraftingXPPlugin.Log.LogInfo((object)string.Format("Долг за снос: {0} (следующие {0} построек без XP)", num)); } } } internal static class CraftMath { public static float CraftPower(SharedData shared) { //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_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) if (shared == null) { return 0f; } DamageTypes damages = shared.m_damages; return Mathf.Max(damages.m_damage + damages.m_blunt + damages.m_slash + damages.m_pierce + damages.m_fire + damages.m_frost + damages.m_lightning + damages.m_poison + damages.m_spirit + damages.m_chop + damages.m_pickaxe, Mathf.Max(shared.m_armor, shared.m_blockPower)); } }