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 Stake Tweaks v1.0.0
BepInEx/plugins/StakeTweaks/StakeTweaks.dll
Decompiled a week agousing System; using System.Collections; 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 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("StakeTweaks")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("StakeTweaks")] [assembly: AssemblyTitle("StakeTweaks")] [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 StakeTune { [BepInPlugin("com.toolkings.staketune", "Stake Tweaks", "1.0.0")] public sealed class StakeTunePlugin : BaseUnityPlugin { private sealed class TargetDefinition { internal readonly string PrefabName; internal readonly string NameEn; internal readonly string NameEs; internal readonly string Section; internal readonly bool HasDamage; internal TargetDefinition(string prefabName, string nameEn, string nameEs, string section, bool hasDamage) { PrefabName = prefabName; NameEn = nameEn; NameEs = nameEs; Section = section; HasDamage = hasDamage; } } private sealed class TargetSettings { internal readonly TargetDefinition Definition; internal ConfigEntry<float>? DamageMultiplier; internal ConfigEntry<float>? HealthMultiplier; internal ConfigEntry<float>? DamageTakenMultiplier; internal ConfigEntry<bool>? RefundMaterials; internal readonly Dictionary<string, ConfigEntry<int>> RecipeAmounts = new Dictionary<string, ConfigEntry<int>>(StringComparer.OrdinalIgnoreCase); internal TargetSettings(TargetDefinition definition) { Definition = definition; } } [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class ObjectDbAwakePatch { [HarmonyPostfix] private static void Postfix(ObjectDB __instance) { _instance?.ConfigureBuildPieces(__instance); } } [HarmonyPatch(typeof(WearNTear), "Awake")] private static class WearNTearAwakePatch { [HarmonyPrefix] private static void Prefix(WearNTear __instance) { TargetSettings targetSettings = _instance?.FindSettings(GetPrefabName((Component)(object)__instance)); if (targetSettings?.HealthMultiplier != null) { __instance.m_health *= Math.Max(0.1f, targetSettings.HealthMultiplier.Value); } } } [HarmonyPatch(typeof(WearNTear), "RPC_Damage")] private static class WearNTearDamagePatch { [HarmonyPrefix] private static void Prefix(WearNTear __instance, HitData hit) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (hit != null) { TargetSettings targetSettings = _instance?.FindSettings(GetPrefabName((Component)(object)__instance)); if (targetSettings?.DamageTakenMultiplier != null) { hit.m_damage = MultiplyDamage(hit.m_damage, Math.Max(0f, targetSettings.DamageTakenMultiplier.Value)); } } } } [HarmonyPatch(typeof(Aoe), "GetDamage", new Type[] { typeof(int) })] private static class StakeAoeDamagePatch { [HarmonyPostfix] private static void Postfix(Aoe __instance, ref DamageTypes __result) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) StakeTunePlugin instance = _instance; if (!((Object)(object)instance == (Object)null)) { TargetSettings targetSettings = instance.FindSettings(GetPrefabName((Component)(object)__instance)); if (targetSettings?.DamageMultiplier != null) { __result = MultiplyDamage(__result, Math.Max(0f, targetSettings.DamageMultiplier.Value)); } } } } public const string PluginGuid = "com.toolkings.staketune"; public const string PluginName = "Stake Tweaks"; public const string PluginVersion = "1.0.0"; private static readonly TargetDefinition[] Definitions = new TargetDefinition[5] { new TargetDefinition("piece_sharpstakes", "Sharp stakes", "Estacas afiladas", "STAKES/Sharp Stakes", hasDamage: true), new TargetDefinition("piece_dvergr_sharpstakes", "Dvergr sharp stakes", "Estacas afiladas dvergr", "STAKES/Dvergr Sharp Stakes", hasDamage: true), new TargetDefinition("piece_stakewall_blackwood", "Ashwood stakewall", "Muro de estacas de madera de fresno", "STAKES/Ashwood Stakewall", hasDamage: true), new TargetDefinition("stake_wall", "Stakewall", "Muro de estacas", "STAKEWALLS/Stakewall", hasDamage: false), new TargetDefinition("piece_dvergr_stake_wall", "Dvergr stakewall", "Muro de estacas dvergr", "STAKEWALLS/Dvergr Stakewall", hasDamage: false) }; private static readonly Dictionary<string, TargetDefinition> DefinitionByPrefab = Definitions.ToDictionary<TargetDefinition, string>((TargetDefinition definition) => definition.PrefabName, StringComparer.OrdinalIgnoreCase); private static StakeTunePlugin? _instance; private readonly Dictionary<string, TargetSettings> _settings = new Dictionary<string, TargetSettings>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<string, Requirement[]> _originalRequirements = new Dictionary<string, Requirement[]>(StringComparer.OrdinalIgnoreCase); private readonly HashSet<string> _configuredPieces = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private Coroutine? _scanRoutine; private bool _isSpanish; private bool _settingsBound; private bool _configNeedsSave; private int _displayOrder; private void Awake() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) _instance = this; DetectLanguage(); BindTargetSettings(); new Harmony("com.toolkings.staketune").PatchAll(typeof(StakeTunePlugin).Assembly); _scanRoutine = ((MonoBehaviour)this).StartCoroutine(WaitForBuildPieces()); } private IEnumerator WaitForBuildPieces() { yield return (object)new WaitForSeconds(1f); for (int attempt = 0; attempt < 12; attempt++) { if ((Object)(object)ObjectDB.instance != (Object)null) { ConfigureBuildPieces(ObjectDB.instance); SavePendingConfig(); _scanRoutine = null; yield break; } yield return (object)new WaitForSeconds(1f); } ((BaseUnityPlugin)this).Logger.LogWarning((object)Text("Valheim's build-piece list was not ready. StakeTune will try again when ObjectDB loads.", "La lista de piezas de Valheim no estaba lista. StakeTune lo intentará de nuevo cuando cargue ObjectDB.")); _scanRoutine = null; } private void DetectLanguage() { string text = null; try { Localization instance = Localization.instance; text = ((instance != null) ? instance.GetSelectedLanguage() : null); } catch { } if (!string.IsNullOrWhiteSpace(text)) { _isSpanish = text.StartsWith("Spanish", StringComparison.OrdinalIgnoreCase) || text.StartsWith("Español", StringComparison.OrdinalIgnoreCase) || text.StartsWith("es", StringComparison.OrdinalIgnoreCase); } else { _isSpanish = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName.Equals("es", StringComparison.OrdinalIgnoreCase) || CultureInfo.CurrentCulture.TwoLetterISOLanguageName.Equals("es", StringComparison.OrdinalIgnoreCase); } } private void BindTargetSettings() { if (_settingsBound) { return; } TargetDefinition[] definitions = Definitions; foreach (TargetDefinition targetDefinition in definitions) { string targetName = GetTargetName(targetDefinition); TargetSettings targetSettings = new TargetSettings(targetDefinition); if (targetDefinition.HasDamage) { targetSettings.DamageMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>(targetDefinition.Section, targetDefinition.PrefabName + ".DamageMultiplier", 2.5f, CreateFloatDescription(Text("Damage dealt multiplier. 2.5 means 2.5 times the original damage.", "Multiplicador del daño infligido. 2.5 significa 2.5 veces el daño original."), targetName + Text(" — damage multiplier", " — multiplicador de daño"), 0f, 100f)); } targetSettings.HealthMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>(targetDefinition.Section, targetDefinition.PrefabName + ".HealthMultiplier", 3f, CreateFloatDescription(Text("Maximum structure health multiplier. 3 means three times the original health.", "Multiplicador de salud máxima. 3 significa tres veces la salud original."), targetName + Text(" — health multiplier", " — multiplicador de salud"), 0.1f, 100f)); targetSettings.DamageTakenMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>(targetDefinition.Section, targetDefinition.PrefabName + ".DamageTakenMultiplier", 1f, CreateFloatDescription(Text("Damage received multiplier: 1 means 100% of incoming damage; 0.1 means 10%.", "Multiplicador del daño recibido: 1 significa 100% del daño; 0.1 significa 10%."), targetName + Text(" — damage received (1 = 100%)", " — daño recibido (1 = 100%)"), 0f, 10f)); targetSettings.RefundMaterials = ((BaseUnityPlugin)this).Config.Bind<bool>(targetDefinition.Section, targetDefinition.PrefabName + ".RefundMaterials", true, CreateDescription(Text("Return all original crafting materials when this player-built piece is destroyed.", "Devuelve todos los materiales originales cuando se destruye esta pieza construida por un jugador."), targetName + Text(" — return 100% of materials", " — devolver 100% de materiales"))); _settings.Add(targetDefinition.PrefabName, targetSettings); } _settingsBound = true; } private void ConfigureBuildPieces(ObjectDB database) { List<Piece> allBuildPieces; try { allBuildPieces = database.GetAllBuildPieces(true); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)(Text("Could not read the building catalog: ", "No se pudo leer el catálogo de construcción: ") + ex.Message)); return; } if (allBuildPieces == null) { return; } TargetDefinition[] definitions = Definitions; foreach (TargetDefinition definition in definitions) { Piece val = ((IEnumerable<Piece>)allBuildPieces).FirstOrDefault((Func<Piece, bool>)((Piece candidate) => (Object)(object)candidate != (Object)null && (Object)(object)((Component)candidate).gameObject != (Object)null && NormalizePrefabName(((Object)((Component)candidate).gameObject).name).Equals(definition.PrefabName, StringComparison.OrdinalIgnoreCase))); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)(Text("Could not find build piece ", "No se encontró la pieza de construcción ") + definition.PrefabName)); } else { ConfigurePiece(val, definition); } } if (_configNeedsSave) { ((BaseUnityPlugin)this).Config.Save(); _configNeedsSave = false; } } private void ConfigurePiece(Piece piece, TargetDefinition definition) { if (_configuredPieces.Add(definition.PrefabName)) { TargetSettings settings = _settings[definition.PrefabName]; Requirement[] array = CloneRequirements(piece.m_resources ?? Array.Empty<Requirement>()); _originalRequirements[definition.PrefabName] = array; BindRecipeAmounts(piece, definition, settings, array); piece.m_resources = ApplyRecipeAndRecovery(array, settings); ((BaseUnityPlugin)this).Logger.LogInfo((object)(Text("Configured ", "Configurado: ") + GetTargetName(definition) + " (" + definition.PrefabName + ")")); } } private void BindRecipeAmounts(Piece piece, TargetDefinition definition, TargetSettings settings, Requirement[] original) { //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Expected O, but got Unknown foreach (IGrouping<string, Requirement> item in original.Where((Requirement requirement) => (Object)(object)requirement?.m_resItem != (Object)null && (Object)(object)((Component)requirement.m_resItem).gameObject != (Object)null).GroupBy<Requirement, string>((Requirement requirement) => ((Object)((Component)requirement.m_resItem).gameObject).name, StringComparer.OrdinalIgnoreCase)) { string key = item.Key; int num = Math.Max(0, item.Sum((Requirement requirement) => requirement.m_amount)); string localizedPieceName = GetLocalizedPieceName(piece, definition); string localizedResourceName = GetLocalizedResourceName(item.First().m_resItem, key); string displayName = localizedPieceName + " (" + definition.PrefabName + ") — " + localizedResourceName; string text = Text("Exact amount of " + localizedResourceName + " required to craft this piece. The default is the piece's original recipe; set 0 for free. Range: 0 to the largest integer supported by the game.", "Cantidad exacta de " + localizedResourceName + " necesaria para fabricar esta pieza. El valor inicial es su receta original; usa 0 para que sea gratis. Rango: 0 hasta el entero máximo que admite el juego."); string text2 = definition.PrefabName + ".Material." + key; settings.RecipeAmounts[key] = ((BaseUnityPlugin)this).Config.Bind<int>(definition.Section, text2, num, new ConfigDescription(text, (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, int.MaxValue), new object[1] { CreateAttributes(displayName) })); _configNeedsSave = true; } } private static Requirement[] ApplyRecipeAndRecovery(Requirement[] original, TargetSettings settings) { List<Requirement> list = new List<Requirement>(original.Length); HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (Requirement val in original) { if (val == null) { continue; } Requirement val2 = CloneRequirement(val); val2.m_recover = settings.RefundMaterials?.Value ?? val?.m_recover ?? false; if ((Object)(object)val2.m_resItem != (Object)null && (Object)(object)((Component)val2.m_resItem).gameObject != (Object)null) { string name = ((Object)((Component)val2.m_resItem).gameObject).name; if (settings.RecipeAmounts.TryGetValue(name, out ConfigEntry<int> value)) { if (!hashSet.Add(name)) { continue; } val2.m_amount = Math.Max(0, value.Value); val2.m_extraAmountOnlyOneIngredient = 0; val2.m_amountPerLevel = 0; } } list.Add(val2); } return list.ToArray(); } private static Requirement[] CloneRequirements(Requirement[] original) { return original.Select(CloneRequirement).ToArray(); } private static Requirement CloneRequirement(Requirement original) { //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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown return new Requirement { m_resItem = original.m_resItem, m_amount = original.m_amount, m_extraAmountOnlyOneIngredient = original.m_extraAmountOnlyOneIngredient, m_amountPerLevel = original.m_amountPerLevel, m_upgraderResource = original.m_upgraderResource, m_recover = original.m_recover }; } private ConfigDescription CreateFloatDescription(string description, string displayName, float minimum, float maximum) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown return new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(minimum, maximum), new object[1] { CreateAttributes(displayName) }); } private ConfigDescription CreateDescription(string description, string displayName) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown return new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { CreateAttributes(displayName) }); } private ConfigurationManagerAttributes CreateAttributes(string displayName) { return new ConfigurationManagerAttributes { DispName = displayName, Order = _displayOrder++ }; } private TargetSettings? FindSettings(string prefabName) { string key = NormalizePrefabName(prefabName); TargetSettings value; return _settings.TryGetValue(key, out value) ? value : null; } private static string NormalizePrefabName(string name) { return name.EndsWith("(Clone)", StringComparison.Ordinal) ? name.Substring(0, name.Length - "(Clone)".Length).TrimEnd() : name; } private static string GetPrefabName(Component component) { Piece componentInParent = component.GetComponentInParent<Piece>(); return NormalizePrefabName(((Object)(object)componentInParent != (Object)null) ? ((Object)((Component)componentInParent).gameObject).name : ((Object)component.gameObject).name); } private string GetTargetName(TargetDefinition definition) { return _isSpanish ? definition.NameEs : definition.NameEn; } private string GetLocalizedPieceName(Piece piece, TargetDefinition definition) { if (!string.IsNullOrWhiteSpace(piece.m_name)) { try { Localization instance = Localization.instance; if (instance != null) { string text = instance.Localize(piece.m_name); if (!string.IsNullOrWhiteSpace(text)) { return text; } } } catch { } } return GetTargetName(definition); } private static string GetLocalizedResourceName(ItemDrop item, string fallback) { try { Localization instance = Localization.instance; string text = item.m_itemData?.m_shared?.m_name; if (instance != null && !string.IsNullOrWhiteSpace(text)) { string text2 = instance.Localize(text); if (!string.IsNullOrWhiteSpace(text2)) { return text2; } } } catch { } return fallback; } private string Text(string english, string spanish) { return _isSpanish ? spanish : english; } private void SavePendingConfig() { if (_configNeedsSave) { ((BaseUnityPlugin)this).Config.Save(); _configNeedsSave = false; } } private static DamageTypes MultiplyDamage(DamageTypes damage, float multiplier) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) damage.m_damage *= multiplier; damage.m_blunt *= multiplier; damage.m_slash *= multiplier; damage.m_pierce *= multiplier; damage.m_chop *= multiplier; damage.m_pickaxe *= multiplier; damage.m_fire *= multiplier; damage.m_frost *= multiplier; damage.m_lightning *= multiplier; damage.m_poison *= multiplier; damage.m_spirit *= multiplier; damage.m_nonPlayer *= multiplier; return damage; } } internal sealed class ConfigurationManagerAttributes { public string? DispName; public int? Order; } }