using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using ServerSync;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("OreDamageDistributor")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("OreDamageDistributor")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("2ec3237c-551f-4847-a11f-2a1b277a5c42")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace PickaxeMaster;
[BepInPlugin("com.mysteryuniverse.valheim.PickaxeMaster", "Pickaxe Master", "6.0.0")]
[BepInProcess("valheim.exe")]
[BepInProcess("valheim_server.exe")]
public class PickaxeMaster : BaseUnityPlugin
{
private static ManualLogSource log;
private static PickaxeMaster instance;
private static FieldInfo nviewFieldInfo;
private static Type znetViewType;
private static MethodInfo znetIsValidMethod;
private static MethodInfo znetIsOwnerMethod;
private static ConfigSync configSync;
private static SyncedConfigEntry<KeyboardShortcut> disableKey;
private static SyncedConfigEntry<float> damageMultiplier;
private static SyncedConfigEntry<float> minSegmentDamage;
private static SyncedConfigEntry<bool> scaleToolDamage;
private static SyncedConfigEntry<bool> enableAOEMode;
private static SyncedConfigEntry<float> minAOEDistance;
private static SyncedConfigEntry<float> maxAOEDistance;
public static SyncedConfigEntry<string> language;
private static bool disablePressed;
private static bool isProcessing;
public static string CurrentLang
{
get
{
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Invalid comparison between Unknown and I4
if (language != null && (language.Value == "en" || language.Value == "ru"))
{
return language.Value;
}
return ((int)Application.systemLanguage == 30) ? "ru" : "en";
}
}
private void Awake()
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: 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_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Expected O, but got Unknown
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Expected O, but got Unknown
instance = this;
log = ((BaseUnityPlugin)this).Logger;
configSync = new ConfigSync("com.mysteryuniverse.valheim.PickaxeMaster")
{
DisplayName = Localization.Get("MOD_NAME"),
CurrentVersion = "6.0.0",
MinimumRequiredVersion = "5.9.8",
ModRequired = true,
IsLocked = true
};
language = configSync.AddConfigEntry<string>(((BaseUnityPlugin)this).Config.Bind<string>("General", "Language", "en", Localization.Get("CONFIG_LANGUAGE")));
disableKey = configSync.AddConfigEntry<KeyboardShortcut>(((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "DisableKey", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), new ConfigDescription(Localization.Get("CONFIG_DISABLE_KEY"), (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 10
}
})));
damageMultiplier = configSync.AddConfigEntry<float>(((BaseUnityPlugin)this).Config.Bind<float>("General", "DamageMultiplier", 1f, Localization.Get("CONFIG_DAMAGE_MULTIPLIER")));
minSegmentDamage = configSync.AddConfigEntry<float>(((BaseUnityPlugin)this).Config.Bind<float>("General", "MinSegmentDamage", 0f, Localization.Get("CONFIG_MIN_SEGMENT_DAMAGE")));
scaleToolDamage = configSync.AddConfigEntry<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("General", "ScaleToolDamage", false, Localization.Get("CONFIG_SCALE_TOOL_DAMAGE")));
enableAOEMode = configSync.AddConfigEntry<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("AOE", "EnableLevelMode", true, Localization.Get("CONFIG_ENABLE_AOE")));
minAOEDistance = configSync.AddConfigEntry<float>(((BaseUnityPlugin)this).Config.Bind<float>("AOE", "MinDistance", 1f, Localization.Get("CONFIG_MIN_DISTANCE")));
maxAOEDistance = configSync.AddConfigEntry<float>(((BaseUnityPlugin)this).Config.Bind<float>("AOE", "MaxDistance", 10f, Localization.Get("CONFIG_MAX_DISTANCE")));
nviewFieldInfo = typeof(MineRock5).GetField("m_nview", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (nviewFieldInfo != null)
{
znetViewType = nviewFieldInfo.FieldType;
znetIsValidMethod = znetViewType?.GetMethod("IsValid", BindingFlags.Instance | BindingFlags.Public);
znetIsOwnerMethod = znetViewType?.GetMethod("IsOwner", BindingFlags.Instance | BindingFlags.Public);
}
Harmony.CreateAndPatchAll(typeof(PickaxeMaster), (string)null);
}
private static float GetAOERadius(Player player)
{
if ((Object)(object)player == (Object)null)
{
return minAOEDistance.Value;
}
float skillFactor = ((Character)player).GetSkillFactor((SkillType)12);
return Mathf.Lerp(minAOEDistance.Value, maxAOEDistance.Value, skillFactor);
}
private static Collider[] GetAOESegments(MineRock5 rock, Vector3 hitPoint, Player player)
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: 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_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
if (!enableAOEMode.Value)
{
return ((Component)rock).GetComponentsInChildren<Collider>();
}
float aOERadius = GetAOERadius(player);
float num = aOERadius * aOERadius;
List<Collider> list = new List<Collider>();
Collider[] componentsInChildren = ((Component)rock).GetComponentsInChildren<Collider>();
foreach (Collider val in componentsInChildren)
{
Bounds bounds = val.bounds;
Vector3 val2 = hitPoint - ((Bounds)(ref bounds)).center;
if (((Vector3)(ref val2)).sqrMagnitude <= num)
{
list.Add(val);
}
}
return list.ToArray();
}
private void Update()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
KeyboardShortcut value = disableKey.Value;
disablePressed = ((KeyboardShortcut)(ref value)).IsDown();
}
[HarmonyPatch(typeof(MineRock5), "Damage")]
[HarmonyPrefix]
public static bool Prefix(MineRock5 __instance, HitData hit)
{
//IL_0112: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
//IL_030c: Unknown result type (might be due to invalid IL or missing references)
//IL_030e: Unknown result type (might be due to invalid IL or missing references)
//IL_0313: Unknown result type (might be due to invalid IL or missing references)
//IL_0315: Unknown result type (might be due to invalid IL or missing references)
//IL_031a: Unknown result type (might be due to invalid IL or missing references)
//IL_031f: Unknown result type (might be due to invalid IL or missing references)
//IL_032a: Unknown result type (might be due to invalid IL or missing references)
//IL_032c: Unknown result type (might be due to invalid IL or missing references)
//IL_0331: Unknown result type (might be due to invalid IL or missing references)
//IL_0336: Unknown result type (might be due to invalid IL or missing references)
//IL_0338: Unknown result type (might be due to invalid IL or missing references)
//IL_033d: Unknown result type (might be due to invalid IL or missing references)
//IL_0342: Unknown result type (might be due to invalid IL or missing references)
//IL_034e: Unknown result type (might be due to invalid IL or missing references)
//IL_035c: Expected O, but got Unknown
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
//IL_02d9: Expected O, but got Unknown
if (!((Object)(object)__instance == (Object)null) && hit != null && !disablePressed)
{
_ = hit.m_attacker;
if (0 == 0)
{
if (isProcessing)
{
return true;
}
isProcessing = true;
try
{
ZNetScene obj = ZNetScene.instance;
GameObject val = ((obj != null) ? obj.FindInstance(hit.m_attacker) : null);
Player val2 = ((val != null) ? val.GetComponent<Player>() : null);
if ((Object)(object)val2 == (Object)null)
{
return true;
}
if (nviewFieldInfo != null && znetIsValidMethod != null && znetIsOwnerMethod != null)
{
try
{
object value = nviewFieldInfo.GetValue(__instance);
if (value != null)
{
bool flag = (bool)znetIsValidMethod.Invoke(value, null);
bool flag2 = (bool)znetIsOwnerMethod.Invoke(value, null);
if (flag && !flag2)
{
return true;
}
}
}
catch
{
}
}
Collider[] aOESegments = GetAOESegments(__instance, hit.m_point, val2);
if (aOESegments.Length == 0)
{
return true;
}
int num = aOESegments.Length;
float pickaxe = hit.m_damage.m_pickaxe;
float num2 = Mathf.Max(Mathf.Round(pickaxe / (float)num * 10f) / 10f, minSegmentDamage.Value);
float num3 = pickaxe - num2 * (float)num;
int num4 = Mathf.RoundToInt(num3 * 10f);
float[] array = new float[num];
for (int i = 0; i < num; i++)
{
array[i] = num2;
}
List<int> list = new List<int>();
for (int j = 0; j < num; j++)
{
list.Add(j);
}
for (int k = 0; k < num; k++)
{
int num5 = Random.Range(k, num);
List<int> list2 = list;
int index = k;
int index2 = num5;
int value2 = list[num5];
int value3 = list[k];
list2[index] = value2;
list[index2] = value3;
}
for (int l = 0; l < num4 && l < num; l++)
{
array[list[l]] += 0.1f;
}
for (int m = 0; m < array.Length; m++)
{
array[m] *= damageMultiplier.Value;
}
ItemData val3 = null;
try
{
MethodInfo method = typeof(Humanoid).GetMethod("GetRightItem", BindingFlags.Instance | BindingFlags.NonPublic);
if (method != null)
{
val3 = (ItemData)method.Invoke(val2, null);
}
}
catch
{
}
float num6 = 0f;
for (int n = 0; n < num; n++)
{
try
{
HitData val4 = new HitData
{
m_damage = new DamageTypes
{
m_damage = array[n]
},
m_point = hit.m_point,
m_hitCollider = aOESegments[n],
m_dir = hit.m_dir,
m_attacker = hit.m_attacker,
m_pushForce = hit.m_pushForce,
m_toolTier = hit.m_toolTier
};
Destructible componentInParent = ((Component)aOESegments[n]).GetComponentInParent<Destructible>();
if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent != (Object)(object)__instance)
{
componentInParent.Damage(val4);
}
else
{
__instance.Damage(val4);
}
num6 += array[n];
}
catch
{
}
}
if (val3 != null)
{
SharedData shared = val3.m_shared;
if (shared != null && shared.m_useDurability && num6 > 0f && scaleToolDamage.Value)
{
float value4 = damageMultiplier.Value;
float num7 = Mathf.Max(0f, value4 - 1f);
val3.m_durability = Mathf.Max(0f, val3.m_durability - num7);
}
}
}
finally
{
isProcessing = false;
}
return false;
}
}
return true;
}
}
public static class Localization
{
private static readonly Dictionary<string, string> en = new Dictionary<string, string>
{
{ "MOD_NAME", "PickaxeMaster" },
{ "MOD_DESCRIPTION", "Distributes ore damage across segments and scales tool wear." },
{ "CONFIG_DISABLE_KEY", "Temporary Disable Key" },
{ "CONFIG_DAMAGE_MULTIPLIER", "Damage Multiplier" },
{ "CONFIG_MIN_SEGMENT_DAMAGE", "Minimum Segment Damage" },
{ "CONFIG_SCALE_TOOL_DAMAGE", "Scale Tool Durability" },
{ "CONFIG_ENABLE_AOE", "Scale AOE Radius by Pickaxe Skill" },
{ "CONFIG_MIN_DISTANCE", "Min AOE Distance" },
{ "CONFIG_MAX_DISTANCE", "Max AOE Distance" },
{ "CONFIG_LANGUAGE", "Language. en/ru" }
};
private static readonly Dictionary<string, string> ru = new Dictionary<string, string>
{
{ "MOD_NAME", "Мастер Кирки" },
{ "MOD_DESCRIPTION", "Распределяет урон по сегментам руды и масштабирует износ инструментов." },
{ "CONFIG_DISABLE_KEY", "Клавиша временного отключения" },
{ "CONFIG_DAMAGE_MULTIPLIER", "Множитель урона" },
{ "CONFIG_MIN_SEGMENT_DAMAGE", "Минимальный урон сегмента" },
{ "CONFIG_SCALE_TOOL_DAMAGE", "Масштабировать износ инструмента" },
{ "CONFIG_ENABLE_AOE", "Масштабировать радиус AOE по уровню владения киркой" },
{ "CONFIG_MIN_DISTANCE", "Минимальная дистанция AOE" },
{ "CONFIG_MAX_DISTANCE", "Максимальная дистанция AOE" },
{ "CONFIG_LANGUAGE", "Language. en, ru" }
};
public static string Get(string key)
{
string currentLang = PickaxeMaster.CurrentLang;
return (!(currentLang == "ru")) ? (en.ContainsKey(key) ? en[key] : key) : (ru.ContainsKey(key) ? ru[key] : key);
}
}
internal sealed class ConfigurationManagerAttributes
{
public bool? ShowRangeAsPercent;
public int? Order;
public bool? IsAdminOnly;
public string Category;
public string DispName;
public string Description;
public object DefaultValue;
public AcceptableValueBase AcceptableValues;
public bool? HideSettingName;
public bool? ReadOnly;
}