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 ExperienceTuner v1.1.1
BepInEx/plugins/ExperienceTuner/ExperienceTuner.dll
Decompiled 6 months agousing System; using System.Diagnostics; 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.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("ExperienceTunerProject")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ExperienceTunerProject")] [assembly: AssemblyTitle("ExperienceTunerProject")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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 SkillTuner { [BepInPlugin("yourname.valheim.skilltuner", "Skill Tuner", "1.0.0")] public sealed class SkillTunerPlugin : BaseUnityPlugin { private static class DeathPenaltyScope { private static int _depth; public static bool Active => _depth > 0; public static void Enter() { _depth++; } public static void Exit() { if (_depth > 0) { _depth--; } } } [HarmonyPatch(typeof(Player), "OnDeath")] private static class PlayerOnDeathPatch { private static void Prefix() { DeathPenaltyScope.Enter(); } private static void Postfix() { DeathPenaltyScope.Exit(); } } [HarmonyPatch(typeof(Skills), "RaiseSkill")] private static class RaiseSkillPatch { private static void Prefix(ref float factor) { factor *= Mathf.Max(0f, EffectiveExperienceMultiplier); } } [HarmonyPatch(typeof(Skills), "LowerAllSkills", new Type[] { typeof(float) })] private static class LowerAllSkillsPatch { private static void Prefix(ref float factor) { if (DeathPenaltyScope.Active) { factor *= Mathf.Max(0f, EffectiveDeathPenaltyMultiplier); } } } [HarmonyPatch(typeof(ZNet), "Awake")] private static class ZNetAwakePatch { private static void Postfix(ZNet __instance) { EnsureRoutedRpcRegistration(); if (__instance.IsServer()) { ApplyMultipliersFromConfig(); BroadcastMultipliers(); } else { ApplyMultipliers(1f, 1f); RequestMultipliersFromServer(); } } } [HarmonyPatch(typeof(ZNet), "OnNewPeer")] private static class ZNetOnNewPeerPatch { private static void Postfix(ZNet __instance, ZNetPeer peer) { HandlePeerConnected(__instance, peer); } } private const string PluginGuid = "yourname.valheim.skilltuner"; private const string PluginName = "Skill Tuner"; private const string PluginVersion = "1.0.0"; private const string RpcSyncMultipliers = "SkillTuner Sync"; private const string RpcRequestMultipliers = "SkillTuner Request"; internal static ConfigEntry<float>? ExperienceMultiplier; internal static ConfigEntry<float>? DeathPenaltyMultiplier; private Harmony? _harmony; private bool _registeredSettingHandler; private static bool _rpcRegistered; private static MethodInfo? _getServerPeerIdMethod; internal static SkillTunerPlugin? Instance { get; private set; } internal static float EffectiveExperienceMultiplier { get; private set; } = 1f; internal static float EffectiveDeathPenaltyMultiplier { get; private set; } = 1f; private void Awake() { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown Instance = this; ExperienceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("SkillGain", "ExperienceMultiplier", 1f, "Multiplier applied to all skill XP gains. Use values >1 for faster progression, 1 for default, 0 to disable XP gain."); DeathPenaltyMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("SkillLoss", "DeathPenaltyMultiplier", 1f, "Multiplier applied to the skill-loss factor on death. 1 keeps the vanilla penalty, 0 removes it entirely, values >1 increase it."); ((BaseUnityPlugin)this).Config.SettingChanged += OnConfigSettingChanged; _registeredSettingHandler = true; _harmony = new Harmony("yourname.valheim.skilltuner"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Skill Tuner 1.0.0 loaded."); } private void OnDestroy() { if (_registeredSettingHandler) { ((BaseUnityPlugin)this).Config.SettingChanged -= OnConfigSettingChanged; _registeredSettingHandler = false; } Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } Instance = null; } private static void OnConfigSettingChanged(object? sender, SettingChangedEventArgs e) { if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { SkillTunerPlugin? instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogDebug((object)"Ignoring local config change on client; waiting for host sync."); } } else { ApplyMultipliersFromConfig(); EnsureRoutedRpcRegistration(); BroadcastMultipliers(); } } private static void ApplyMultipliersFromConfig() { float exp = ExperienceMultiplier?.Value ?? 1f; float death = DeathPenaltyMultiplier?.Value ?? 1f; ApplyMultipliers(exp, death); } private static void ApplyMultipliers(float exp, float death) { EffectiveExperienceMultiplier = Mathf.Max(0f, exp); EffectiveDeathPenaltyMultiplier = Mathf.Max(0f, death); SkillTunerPlugin? instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogInfo((object)$"Skill multipliers set -> XP: {EffectiveExperienceMultiplier:0.###}, Death: {EffectiveDeathPenaltyMultiplier:0.###}"); } } private static void HandlePeerConnected(ZNet net, ZNetPeer peer) { if (peer?.m_rpc != null) { if (net.IsServer()) { EnsureRoutedRpcRegistration(); SendMultipliers(peer.m_uid); } else { RequestMultipliersFromServer(); } } } private static void RequestMultipliersFromServer() { if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer()) { return; } EnsureRoutedRpcRegistration(); long serverPeerId = GetServerPeerId(); if (serverPeerId == 0L) { return; } try { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC(serverPeerId, "SkillTuner Request", Array.Empty<object>()); } } catch (Exception arg) { SkillTunerPlugin? instance2 = Instance; if (instance2 != null) { ((BaseUnityPlugin)instance2).Logger.LogWarning((object)$"Failed to request multipliers from host: {arg}"); } } } private static void SendMultipliers(long targetPeerId) { if (targetPeerId == 0L) { return; } EnsureRoutedRpcRegistration(); try { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC(targetPeerId, "SkillTuner Sync", new object[2] { EffectiveExperienceMultiplier, EffectiveDeathPenaltyMultiplier }); } } catch (Exception arg) { SkillTunerPlugin? instance2 = Instance; if (instance2 != null) { ((BaseUnityPlugin)instance2).Logger.LogWarning((object)$"Failed to send multipliers to peer: {arg}"); } } } private static void BroadcastMultipliers() { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } EnsureRoutedRpcRegistration(); foreach (ZNetPeer connectedPeer in ZNet.instance.GetConnectedPeers()) { if (connectedPeer?.m_rpc != null) { SendMultipliers(connectedPeer.m_uid); } } } private static void RpcHandleRequestMultipliers(long sender) { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { SendMultipliers(sender); } } private static void RpcReceiveMultipliers(long sender, float experienceMultiplier, float deathMultiplier) { ApplyMultipliers(experienceMultiplier, deathMultiplier); } private static void EnsureRoutedRpcRegistration() { if (_rpcRegistered || ZRoutedRpc.instance == null) { return; } try { ZRoutedRpc.instance.Register("SkillTuner Request", (Action<long>)RpcHandleRequestMultipliers); ZRoutedRpc.instance.Register<float, float>("SkillTuner Sync", (Action<long, float, float>)RpcReceiveMultipliers); _rpcRegistered = true; } catch (Exception arg) { SkillTunerPlugin? instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)$"Failed to register SkillTuner routed RPCs: {arg}"); } } } private static long GetServerPeerId() { if ((Object)(object)ZNet.instance == (Object)null) { return 0L; } if ((object)_getServerPeerIdMethod == null) { _getServerPeerIdMethod = AccessTools.Method(typeof(ZNet), "GetServerPeerID", (Type[])null, (Type[])null); } if (_getServerPeerIdMethod == null) { return 0L; } try { return (_getServerPeerIdMethod.Invoke(ZNet.instance, Array.Empty<object>()) is long num) ? num : 0; } catch (Exception arg) { SkillTunerPlugin? instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)$"Failed to resolve server peer ID: {arg}"); } return 0L; } } } }