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 Twig Tweaks v1.0.0
BepInEx/plugins/TwigTweaks/TwigTweaks.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; 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("TwigTweaks")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("TwigTweaks")] [assembly: AssemblyTitle("TwigTweaks")] [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 TwigTweaks { [BepInPlugin("com.kingangel0475.twigtweaks", "Twig Tweaks", "1.0.0")] public sealed class TwigTweaksPlugin : BaseUnityPlugin { private sealed class AttackScope { internal readonly AttackScope? Parent; internal readonly Humanoid Attacker; internal readonly ItemData? Weapon; internal bool HitTrainingDummy; internal float Multiplier; internal AttackScope(AttackScope? parent, Humanoid attacker, ItemData? weapon) { Parent = parent; Attacker = attacker; Weapon = weapon; } } private sealed class ProjectileScope { internal readonly ProjectileScope? Parent; internal readonly float Multiplier; internal ProjectileScope(ProjectileScope? parent, float multiplier) { Parent = parent; Multiplier = multiplier; } } [HarmonyPatch(typeof(Attack), "DoMeleeAttack")] private static class MeleeAttackPrefixPatch { [HarmonyPrefix] private static void Prefix(Attack __instance, out AttackScope? __state) { __state = PushAttackScope(__instance); } [HarmonyPostfix] private static void Postfix(AttackScope? __state) { PopAttackScope(__state); } [HarmonyFinalizer] private static Exception? Finalizer(Exception? __exception, AttackScope? __state) { PopAttackScope(__state); return __exception; } } [HarmonyPatch(typeof(Attack), "DoAreaAttack")] private static class AreaAttackPrefixPatch { [HarmonyPrefix] private static void Prefix(Attack __instance, out AttackScope? __state) { __state = PushAttackScope(__instance); } [HarmonyPostfix] private static void Postfix(AttackScope? __state) { PopAttackScope(__state); } [HarmonyFinalizer] private static Exception? Finalizer(Exception? __exception, AttackScope? __state) { PopAttackScope(__state); return __exception; } } [HarmonyPatch(typeof(Character), "Damage", new Type[] { typeof(HitData) })] private static class CharacterDamagePatch { [HarmonyPrefix] private static void Prefix(Character __instance) { AttackScope attackScope = _attackScope; TwigTweaksPlugin instance = _instance; if (attackScope != null && !((Object)(object)instance == (Object)null) && attackScope.Attacker is Player && IsTrainingDummy(__instance)) { attackScope.HitTrainingDummy = true; attackScope.Multiplier = instance.GetTrainingDummyMultiplier(attackScope.Weapon); } } } [HarmonyPatch(typeof(Projectile), "OnHit", new Type[] { typeof(Collider), typeof(Vector3), typeof(bool), typeof(Vector3) })] private static class ProjectileHitPatch { [HarmonyPrefix] private static void Prefix(Projectile __instance, Collider __0, out ProjectileScope __state) { ProjectileScope projectileScope = _projectileScope; float multiplier = 1f; TwigTweaksPlugin instance = _instance; if ((Object)(object)instance != (Object)null && IsTrainingDummy(__0)) { object? obj = ProjectileWeaponField?.GetValue(__instance); ItemData weapon = (ItemData)((obj is ItemData) ? obj : null); multiplier = instance.GetTrainingDummyMultiplier(weapon); } __state = new ProjectileScope(projectileScope, multiplier); _projectileScope = __state; } [HarmonyPostfix] private static void Postfix(ProjectileScope __state) { if (_projectileScope == __state) { _projectileScope = __state.Parent; } } [HarmonyFinalizer] private static Exception? Finalizer(Exception? __exception, ProjectileScope __state) { if (_projectileScope == __state) { _projectileScope = __state.Parent; } return __exception; } } [HarmonyPatch(typeof(ArcheryTarget), "OnProjectileHit")] private static class ArcheryTargetExperiencePatch { [HarmonyPrefix] private static void Prefix(ArcheryTarget __instance, ItemData __1, out float __state) { __state = __instance.m_raiseSkillMultiplier; TwigTweaksPlugin instance = _instance; if (!((Object)(object)instance == (Object)null)) { float archeryTargetShare = instance.GetArcheryTargetShare(__1); if (archeryTargetShare >= 0f) { __instance.m_raiseSkillMultiplier = archeryTargetShare; } } } [HarmonyPostfix] private static void Postfix(ArcheryTarget __instance, float __state) { __instance.m_raiseSkillMultiplier = __state; } [HarmonyFinalizer] private static Exception? Finalizer(ArcheryTarget __instance, Exception? __exception, float __state) { __instance.m_raiseSkillMultiplier = __state; return __exception; } } [HarmonyPatch(typeof(Skills), "RaiseSkill", new Type[] { typeof(SkillType), typeof(float) })] private static class SkillExperiencePatch { [HarmonyPrefix] private static void Prefix(ref float __1) { if (_projectileScope != null && !Mathf.Approximately(_projectileScope.Multiplier, 1f)) { __1 = ScaleExperience(__1, _projectileScope.Multiplier); } else if (_attackScope != null && _attackScope.HitTrainingDummy) { __1 = ScaleExperience(__1, _attackScope.Multiplier); } } private static float ScaleExperience(float experience, float multiplier) { if (float.IsNaN(experience) || float.IsInfinity(experience) || experience <= 0f) { return experience; } float num = experience * multiplier; if (float.IsNaN(num) || float.IsInfinity(num)) { return 100000f; } return Math.Min(num, 100000f); } } public const string PluginGuid = "com.kingangel0475.twigtweaks"; public const string PluginName = "Twig Tweaks"; public const string PluginVersion = "1.0.0"; private const float VanillaArcheryTargetShare = 0.35f; private const float MaxSafeMultiplier = 100000f; private static readonly HashSet<string> WoodenTrainingWeaponIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "SwordWood", "AxeWood", "KnifeWood", "MaceWood", "SpearWood", "SledgeWood", "BattleaxeWood", "AtgeirWood", "THSwordWood" }; private static readonly FieldInfo? AttackCharacterField = AccessTools.Field(typeof(Attack), "m_character"); private static readonly FieldInfo? AttackWeaponField = AccessTools.Field(typeof(Attack), "m_weapon"); private static readonly FieldInfo? ProjectileWeaponField = AccessTools.Field(typeof(Projectile), "m_weapon"); private static TwigTweaksPlugin? _instance; [ThreadStatic] private static AttackScope? _attackScope; [ThreadStatic] private static ProjectileScope? _projectileScope; private ConfigEntry<float>? _woodenTrainingMultiplier; private ConfigEntry<float>? _standardWeaponMultiplier; private ConfigEntry<float>? _bowsAndCrossbowsMultiplier; private ConfigEntry<float>? _elementalStavesMultiplier; private ConfigEntry<float>? _archeryTargetShare; private bool _isSpanish; private int _displayOrder; private void Awake() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) _instance = this; DetectLanguage(); BindConfiguration(); new Harmony("com.kingangel0475.twigtweaks").PatchAll(typeof(TwigTweaksPlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)Text("Twig Tweaks loaded. Skill XP changes apply only to T.W.I.G. and the Archery Target.", "Twig Tweaks está activo. Los cambios de experiencia solo se aplican a T.W.I.G. y al Archery Target.")); } private void OnDestroy() { if ((Object)(object)_instance == (Object)(object)this) { _instance = 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 BindConfiguration() { _woodenTrainingMultiplier = BindMultiplier("T.W.I.G./WOODEN TRAINING WEAPONS", "ExperienceMultiplier", 2f, "Wooden training weapons — XP multiplier", "Multiplicador de experiencia para armas de entrenamiento de madera", Text("Experience multiplier when hitting T.W.I.G. with any of the nine vanilla wooden training weapons. 2 means double the normal T.W.I.G. XP; 0 disables XP from the hit.", "Multiplicador de experiencia al golpear a T.W.I.G. con cualquiera de las nueve armas de entrenamiento de madera del juego. 2 duplica la experiencia normal de T.W.I.G.; 0 desactiva la experiencia del golpe.")); _standardWeaponMultiplier = BindMultiplier("T.W.I.G./STANDARD WEAPONS", "ExperienceMultiplier", 0.5f, "Standard weapons — XP multiplier", "Armas normales — multiplicador de experiencia", Text("Experience multiplier when hitting T.W.I.G. with any weapon that is not in another category. 0.5 means half the normal T.W.I.G. XP.", "Multiplicador de experiencia al golpear a T.W.I.G. con cualquier arma que no pertenezca a otra categoría. 0.5 significa la mitad de la experiencia normal de T.W.I.G.")); _bowsAndCrossbowsMultiplier = BindMultiplier("T.W.I.G./BOWS AND CROSSBOWS", "ExperienceMultiplier", 2f, "Bows and crossbows — XP multiplier", "Arcos y ballestas — multiplicador de experiencia", Text("Experience multiplier when hitting T.W.I.G. with bows or crossbows. These have no wooden training variant. 2 means double the normal T.W.I.G. XP.", "Multiplicador de experiencia al golpear a T.W.I.G. con arcos o ballestas. No tienen una variante de entrenamiento de madera. 2 duplica la experiencia normal de T.W.I.G.")); _elementalStavesMultiplier = BindMultiplier("T.W.I.G./ELEMENTAL STAVES", "ExperienceMultiplier", 2f, "Elemental staves — XP multiplier", "Bastones elementales — multiplicador de experiencia", Text("Experience multiplier when hitting T.W.I.G. with elemental or blood-magic staves. 2 means double the normal T.W.I.G. XP.", "Multiplicador de experiencia al golpear a T.W.I.G. con bastones elementales o de magia de sangre. 2 duplica la experiencia normal de T.W.I.G.")); _archeryTargetShare = BindMultiplier("ARCHERY TARGET/RANGED WEAPONS", "ExperienceShare", 0.75f, "Archery Target — XP share of a full-value hit", "Archery Target — porcentaje de experiencia de un impacto normal", Text("Final experience as a share of a normal full-value weapon hit. 0.75 means 75%; 1 means 100%; 2 means 200%. Valheim's default target multiplier is 0.35, so this setting replaces that value. Applies to ranged projectiles from bows, crossbows, and staves.", "Experiencia final comparada con un impacto normal que otorga el 100%. 0.75 significa 75%; 1 significa 100%; 2 significa 200%. El multiplicador original del blanco es 0.35, así que este ajuste reemplaza ese valor. Se aplica a proyectiles de arcos, ballestas y bastones.")); } private ConfigEntry<float> BindMultiplier(string section, string key, float defaultValue, string labelEnglish, string labelSpanish, string description) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown return ((BaseUnityPlugin)this).Config.Bind<float>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { DispName = Text(labelEnglish, labelSpanish), Order = _displayOrder++ } })); } private float GetTrainingDummyMultiplier(ItemData? weapon) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected I4, but got Unknown if (weapon?.m_shared == null) { return GetMultiplier(_standardWeaponMultiplier, 0.5f); } string item = (((Object)(object)weapon.m_dropPrefab != (Object)null) ? NormalizePrefabName(((Object)weapon.m_dropPrefab).name) : string.Empty); if (WoodenTrainingWeaponIds.Contains(item)) { return GetMultiplier(_woodenTrainingMultiplier, 2f); } SkillType skillType = weapon.m_shared.m_skillType; SkillType val = skillType; switch (val - 8) { case 0: case 6: return GetMultiplier(_bowsAndCrossbowsMultiplier, 2f); case 1: case 2: return GetMultiplier(_elementalStavesMultiplier, 2f); default: return GetMultiplier(_standardWeaponMultiplier, 0.5f); } } private float GetArcheryTargetShare(ItemData? weapon) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 if (weapon?.m_shared == null) { return -1f; } SkillType skillType = weapon.m_shared.m_skillType; SkillType val = skillType; if (val - 8 <= 2 || (int)val == 14) { return GetMultiplier(_archeryTargetShare, 0.75f); } return -1f; } private static float GetMultiplier(ConfigEntry<float>? entry, float fallback) { float num = entry?.Value ?? fallback; if (float.IsNaN(num) || float.IsInfinity(num) || num < 0f) { return 0f; } return Math.Min(num, 100000f); } private string Text(string english, string spanish) { return _isSpanish ? spanish : english; } private static string NormalizePrefabName(string name) { return name.EndsWith("(Clone)", StringComparison.Ordinal) ? name.Substring(0, name.Length - "(Clone)".Length).TrimEnd() : name; } private static Piece? FindPiece(Component component) { return component.GetComponentInParent<Piece>() ?? component.GetComponentInChildren<Piece>(); } private static bool IsTrainingDummy(Character target) { Piece val = FindPiece((Component)(object)target); string text = NormalizePrefabName(((Object)(object)val != (Object)null) ? ((Object)((Component)val).gameObject).name : ((Object)((Component)target).gameObject).name); return text.Equals("piece_TrainingDummy", StringComparison.OrdinalIgnoreCase) || text.Equals("TrainingDummy", StringComparison.OrdinalIgnoreCase); } private static bool IsTrainingDummy(Collider collider) { Piece val = FindPiece((Component)(object)collider); string text = NormalizePrefabName(((Object)(object)val != (Object)null) ? ((Object)((Component)val).gameObject).name : ((Object)((Component)collider).gameObject).name); return text.Equals("piece_TrainingDummy", StringComparison.OrdinalIgnoreCase) || text.Equals("TrainingDummy", StringComparison.OrdinalIgnoreCase); } private static AttackScope? PushAttackScope(Attack attack) { object? obj = AttackCharacterField?.GetValue(attack); Humanoid val = (Humanoid)((obj is Humanoid) ? obj : null); if ((Object)(object)val == (Object)null) { return null; } object? obj2 = AttackWeaponField?.GetValue(attack); ItemData weapon = (ItemData)((obj2 is ItemData) ? obj2 : null); return _attackScope = new AttackScope(_attackScope, val, weapon); } private static void PopAttackScope(AttackScope? state) { if (state != null && _attackScope == state) { _attackScope = state.Parent; } } } internal sealed class ConfigurationManagerAttributes { public string? DispName; public int? Order; } }