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 LithoCost v1.0.0
BepInEx/plugins/LithoCost/LithoCost.dll
Decompiled a week agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("LithoCost")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("LithoCost")] [assembly: AssemblyTitle("LithoCost")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 LithoCost { [BepInPlugin("com.lithocost.valheim", "LithoCost", "1.0.0")] public sealed class LithoCostPlugin : BaseUnityPlugin { private sealed class CostRule { internal readonly ConfigEntry<bool> Enabled; internal readonly ConfigEntry<string> ReplacementPrefab; internal readonly ConfigEntry<int> Amount; internal CostRule(ConfigEntry<bool> enabled, ConfigEntry<string> replacementPrefab, ConfigEntry<int> amount) { Enabled = enabled; ReplacementPrefab = replacementPrefab; Amount = amount; } } [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class ObjectDbAwakePatch { [HarmonyPostfix] private static void Postfix() { RequestScan(); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class ZNetSceneAwakePatch { [HarmonyPostfix] private static void Postfix() { RequestScan(); } } public const string PluginGuid = "com.lithocost.valheim"; public const string PluginName = "LithoCost"; public const string PluginVersion = "1.0.0"; private static LithoCostPlugin? _instance; private readonly Dictionary<Piece, Requirement[]> _originalRequirements = new Dictionary<Piece, Requirement[]>(); private readonly Dictionary<string, CostRule> _materialRules = new Dictionary<string, CostRule>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<string, CostRule> _pieceRules = new Dictionary<string, CostRule>(StringComparer.OrdinalIgnoreCase); private ConfigEntry<string>? _resourceKeywords; private Coroutine? _scanRoutine; private bool _hasPendingConfigSave; private void Awake() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown _instance = this; _resourceKeywords = ((BaseUnityPlugin)this).Config.Bind<string>("General", "RockResourceKeywords", "stone,marble,grausten,rock,crystal,obsidian", "Comma-separated words used to identify rocky construction materials by their prefab name. Add terms here for modded rock or crystal resources."); Harmony val = new Harmony("com.lithocost.valheim"); val.PatchAll(typeof(LithoCostPlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"LithoCost loaded. Rock building costs are unchanged until an override is enabled in the config."); } internal static void RequestScan() { if (!((Object)(object)_instance == (Object)null) && _instance._scanRoutine == null) { _instance._scanRoutine = ((MonoBehaviour)_instance).StartCoroutine(_instance.ScanRoutine()); } } private IEnumerator ScanRoutine() { yield return (object)new WaitForSeconds(2f); for (int attempt = 0; attempt < 8; attempt++) { DiscoverNewPieces(); yield return (object)new WaitForSeconds(1f); } _scanRoutine = null; } private void DiscoverNewPieces() { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { return; } List<Piece> allBuildPieces; try { allBuildPieces = instance.GetAllBuildPieces(true); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not read Valheim's build-piece list yet: " + ex.Message)); return; } if (allBuildPieces == null) { return; } int num = 0; foreach (Piece item in allBuildPieces) { if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).gameObject == (Object)null || item.m_resources == null) { continue; } string name = ((Object)((Component)item).gameObject).name; if (_pieceRules.ContainsKey(name)) { continue; } Requirement[] array = (Requirement[])item.m_resources.Clone(); List<Requirement> list = array.Where((Requirement requirement) => IsRockResource(GetResourcePrefabName(requirement))).ToList(); if (list.Count == 0) { continue; } _originalRequirements[item] = array; foreach (string item2 in (from value in list.Select(GetResourcePrefabName) where !string.IsNullOrWhiteSpace(value) select value).Distinct<string>(StringComparer.OrdinalIgnoreCase)) { EnsureMaterialRule(item2); } EnsurePieceRule(item, name); num++; ApplyRules(item, array); } if (_hasPendingConfigSave) { ((BaseUnityPlugin)this).Config.Save(); _hasPendingConfigSave = false; } if (num > 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Discovered " + num + " rock-based build piece(s). Enable overrides in BepInEx/config/com.lithocost.valheim.cfg.")); } } private CostRule EnsureMaterialRule(string resourcePrefab) { if (_materialRules.TryGetValue(resourcePrefab, out CostRule value)) { return value; } string text = "Material: " + resourcePrefab; CostRule costRule = new CostRule(((BaseUnityPlugin)this).Config.Bind<bool>(text, "Enabled", false, "Apply this cost to every detected build piece that uses " + resourcePrefab + "."), ((BaseUnityPlugin)this).Config.Bind<string>(text, "ReplacementPrefab", "Stone", "Item prefab ID to charge instead of " + resourcePrefab + ". Example: Stone."), ((BaseUnityPlugin)this).Config.Bind<int>(text, "Amount", 1, "Replacement quantity per build piece. Set to 0 to remove this material cost.")); _materialRules.Add(resourcePrefab, costRule); _hasPendingConfigSave = true; return costRule; } private CostRule EnsurePieceRule(Piece piece, string prefabName) { if (_pieceRules.TryGetValue(prefabName, out CostRule value)) { return value; } string text = (string.IsNullOrWhiteSpace(piece.m_name) ? prefabName : piece.m_name); string text2 = "Piece: " + prefabName; CostRule costRule = new CostRule(((BaseUnityPlugin)this).Config.Bind<bool>(text2, "Enabled", false, "Override all rocky ingredients for " + text + " (prefab: " + prefabName + "). This takes priority over material rules."), ((BaseUnityPlugin)this).Config.Bind<string>(text2, "ReplacementPrefab", "Stone", "Item prefab ID charged for this piece. Example: Stone, BlackMarble, or Crystal."), ((BaseUnityPlugin)this).Config.Bind<int>(text2, "Amount", 1, "Replacement quantity for this piece. Set to 0 to remove all rocky material costs.")); _pieceRules.Add(prefabName, costRule); _hasPendingConfigSave = true; return costRule; } private void ApplyRules(Piece piece, Requirement[] original) { if ((Object)(object)piece == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return; } string name = ((Object)((Component)piece).gameObject).name; if (!_pieceRules.TryGetValue(name, out CostRule value)) { piece.m_resources = original; return; } if (value.Enabled.Value) { Requirement val = ((IEnumerable<Requirement>)original).FirstOrDefault((Func<Requirement, bool>)((Requirement requirement) => IsRockResource(GetResourcePrefabName(requirement)))); if (val == null) { piece.m_resources = original; return; } ItemDrop val2 = FindItemDrop(value.ReplacementPrefab.Value); if ((Object)(object)val2 == (Object)null) { WarnUnknownItem(value.ReplacementPrefab.Value, name); piece.m_resources = original; return; } List<Requirement> list = original.Where((Requirement requirement) => !IsRockResource(GetResourcePrefabName(requirement))).ToList(); if (value.Amount.Value > 0) { list.Add(CreateReplacement(val, val2, value.Amount.Value)); } piece.m_resources = list.ToArray(); return; } List<Requirement> list2 = new List<Requirement>(original.Length); foreach (Requirement val3 in original) { string resourcePrefabName = GetResourcePrefabName(val3); if (!IsRockResource(resourcePrefabName) || resourcePrefabName == null || !_materialRules.TryGetValue(resourcePrefabName, out CostRule value2) || !value2.Enabled.Value) { list2.Add(val3); continue; } ItemDrop val4 = FindItemDrop(value2.ReplacementPrefab.Value); if ((Object)(object)val4 == (Object)null) { WarnUnknownItem(value2.ReplacementPrefab.Value, name); list2.Add(val3); } else if (value2.Amount.Value > 0) { list2.Add(CreateReplacement(val3, val4, value2.Amount.Value)); } } piece.m_resources = list2.ToArray(); } private ItemDrop? FindItemDrop(string prefabName) { if (string.IsNullOrWhiteSpace(prefabName) || (Object)(object)ObjectDB.instance == (Object)null) { return null; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabName.Trim()); return ((Object)(object)itemPrefab == (Object)null) ? null : itemPrefab.GetComponent<ItemDrop>(); } private static Requirement CreateReplacement(Requirement template, ItemDrop item, int amount) { //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) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown return new Requirement { m_resItem = item, m_amount = amount, m_extraAmountOnlyOneIngredient = 0, m_amountPerLevel = 0, m_upgraderResource = template.m_upgraderResource, m_recover = template.m_recover }; } private void WarnUnknownItem(string itemPrefab, string piecePrefab) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Item prefab '" + itemPrefab + "' was not found for build piece '" + piecePrefab + "'; its original cost was kept.")); } private bool IsRockResource(string? resourcePrefab) { if (string.IsNullOrWhiteSpace(resourcePrefab) || _resourceKeywords == null) { return false; } string[] source = _resourceKeywords.Value.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); return source.Any((string keyword) => !string.IsNullOrWhiteSpace(keyword) && resourcePrefab.IndexOf(keyword.Trim(), StringComparison.OrdinalIgnoreCase) >= 0); } private static string? GetResourcePrefabName(Requirement? requirement) { if (requirement == null || (Object)(object)requirement.m_resItem == (Object)null || (Object)(object)((Component)requirement.m_resItem).gameObject == (Object)null) { return null; } return ((Object)((Component)requirement.m_resItem).gameObject).name; } } }