using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ConditionalConfigSync; using HarmonyLib; using UnityEngine; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("0.0.0.0")] namespace OreSpreadQoL; [BepInPlugin("community.valheim.OreSpreadQoL", "Ore Spread QoL", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "community.valheim.OreSpreadQoL"; public const string PluginName = "Ore Spread QoL"; public const string PluginVersion = "1.0.0"; internal static ConfigSync Sync; internal static ConfigEntry BypassKey; internal static ConfigEntry DebugLogging; internal static SyncedConfigEntry EnableLevelMode; internal static SyncedConfigEntry MinDistance; internal static SyncedConfigEntry CopperEnabled; internal static SyncedConfigEntry CopperMaxDistance; internal static SyncedConfigEntry IronEnabled; internal static SyncedConfigEntry IronMaxDistance; internal static SyncedConfigEntry SilverEnabled; internal static SyncedConfigEntry SilverMaxDistance; internal static SyncedConfigEntry SoftTissueEnabled; internal static SyncedConfigEntry SoftTissueMaxDistance; internal static SyncedConfigEntry BlackMarbleEnabled; internal static SyncedConfigEntry BlackMarbleMaxDistance; internal static SyncedConfigEntry StoneEnabled; internal static SyncedConfigEntry StoneMaxDistance; internal static SyncedConfigEntry FlametalEnabled; internal static SyncedConfigEntry FlametalMaxDistance; internal static SyncedConfigEntry OtherEnabled; internal static SyncedConfigEntry OtherMaxDistance; private Harmony _harmony; private void Awake() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0054: 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_02fc: Expected O, but got Unknown ConfigSync val = new ConfigSync("community.valheim.OreSpreadQoL"); ((ConditionalConfigSync)val).DisplayName = "Ore Spread QoL"; ((ConditionalConfigSync)val).CurrentVersion = "1.0.0"; ((ConditionalConfigSync)val).MinimumRequiredVersion = "1.0.0"; ((ConditionalConfigSync)val).ModRequired = true; Sync = val; BypassKey = ((BaseUnityPlugin)this).Config.Bind("General", "BypassKey", new KeyboardShortcut((KeyCode)308, (KeyCode[])(object)new KeyCode[0]), "Hold this key while mining to use vanilla mining for that swing. This is client-local and is not synced."); DebugLogging = ((BaseUnityPlugin)this).Config.Bind("General", "DebugLogging", false, "Enable debug diagnostics in BepInEx\\LogOutput.log. Client-local and not synced. Leave this off for normal play."); EnableLevelMode = ServerBool("General", "EnableLevelMode", defaultValue: true, "Scale spread radius with Pickaxes skill, like PickaxeMaster. At skill 0 use MinDistance; at skill 100 use the resource MaxDistance."); MinDistance = ServerFloat("General", "MinDistance", 1f, 0f, 50f, "Minimum spread radius at Pickaxes skill 0 when EnableLevelMode is enabled."); CopperEnabled = ServerBool("Copper", "Enabled", defaultValue: true, "Enable damage spreading for segmented copper deposits."); CopperMaxDistance = ServerFloat("Copper", "MaxDistance", 15f, 0f, 50f, "Copper spread radius at Pickaxes skill 100, or fixed radius when Level Mode is disabled."); IronEnabled = ServerBool("Iron", "Enabled", defaultValue: true, "Enable damage spreading for muddy scrap piles."); IronMaxDistance = ServerFloat("Iron", "MaxDistance", 1.5f, 0f, 50f, "Muddy scrap pile spread radius at Pickaxes skill 100, or fixed radius when Level Mode is disabled."); SilverEnabled = ServerBool("Silver", "Enabled", defaultValue: true, "Enable damage spreading for segmented silver veins."); SilverMaxDistance = ServerFloat("Silver", "MaxDistance", 4f, 0f, 50f, "Silver spread radius at Pickaxes skill 100, or fixed radius when Level Mode is disabled."); SoftTissueEnabled = ServerBool("Soft Tissue", "Enabled", defaultValue: true, "Enable damage spreading for giant-brain soft tissue mining."); SoftTissueMaxDistance = ServerFloat("Soft Tissue", "MaxDistance", 3.5f, 0f, 50f, "Soft tissue spread radius at Pickaxes skill 100, or fixed radius when Level Mode is disabled."); BlackMarbleEnabled = ServerBool("Black Marble", "Enabled", defaultValue: true, "Enable damage spreading for petrified giant bone / black marble mining."); BlackMarbleMaxDistance = ServerFloat("Black Marble", "MaxDistance", 2.5f, 0f, 50f, "Black marble spread radius at Pickaxes skill 100, or fixed radius when Level Mode is disabled."); StoneEnabled = ServerBool("Stone", "Enabled", defaultValue: true, "Enable damage spreading for ordinary segmented rocks."); StoneMaxDistance = ServerFloat("Stone", "MaxDistance", 15f, 0f, 50f, "Large segmented stone-deposit spread radius at Pickaxes skill 100, or fixed radius when Level Mode is disabled. Small non-segmented rocks remain vanilla."); FlametalEnabled = ServerBool("Flametal", "Enabled", defaultValue: true, "Enable damage spreading for current Flametal ore veins (LeviathanLava / MineRock)."); FlametalMaxDistance = ServerFloat("Flametal", "MaxDistance", 2f, 0f, 50f, "Current Flametal ore-vein spread radius at Pickaxes skill 100, or fixed radius when Level Mode is disabled."); OtherEnabled = ServerBool("Other", "Enabled", defaultValue: true, "Enable damage spreading for other segmented MineRock5 resources."); OtherMaxDistance = ServerFloat("Other", "MaxDistance", 1.5f, 0f, 50f, "Fallback spread radius at Pickaxes skill 100, or fixed radius when Level Mode is disabled."); _harmony = new Harmony("community.valheim.OreSpreadQoL"); _harmony.PatchAll(); } private SyncedConfigEntry ServerBool(string section, string name, bool defaultValue, string description) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown return ((ConditionalConfigSync)Sync).AddConfigEntry(((BaseUnityPlugin)this).Config, section, name, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, new object[0]), (ConfigSyncMode)0, true); } private SyncedConfigEntry ServerFloat(string section, string name, float defaultValue, float min, float max, string description) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown return ((ConditionalConfigSync)Sync).AddConfigEntry(((BaseUnityPlugin)this).Config, section, name, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange(min, max), new object[0]), (ConfigSyncMode)0, true); } private void OnDestroy() { if (_harmony != null) { _harmony.UnpatchSelf(); } } } [HarmonyPatch(typeof(MineRock5), "Damage")] internal static class MineRock5DamagePatch { private static readonly FieldInfo NViewField = AccessTools.Field(typeof(MineRock5), "m_nview"); private static bool _redistributing; private static int _debugHits; private static bool Prefix(MineRock5 __instance, HitData hit) { //IL_0028: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected O, but got Unknown //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || hit == null || _redistributing) { return true; } if (Plugin.BypassKey != null) { KeyboardShortcut value = Plugin.BypassKey.Value; if (((KeyboardShortcut)(ref value)).IsPressed()) { return true; } } Character attacker = hit.GetAttacker(); Player val = (Player)(object)((attacker is Player) ? attacker : null); if ((Object)(object)val == (Object)null) { val = TryResolvePlayerFromAttackerId(hit); } float effectiveRadius = GetEffectiveRadius(__instance, val); if (effectiveRadius <= 0f || hit.m_damage.m_pickaxe <= 0f) { return true; } Collider[] componentsInChildren = ((Component)__instance).GetComponentsInChildren(); if (componentsInChildren == null || componentsInChildren.Length == 0) { return true; } float radiusSq = effectiveRadius * effectiveRadius; Vector3 hitPoint = hit.m_point; List list = componentsInChildren.Where(delegate(Collider c) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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) if ((Object)(object)c != (Object)null) { Vector3 val4 = hitPoint; Bounds bounds2 = c.bounds; Vector3 val5 = val4 - ((Bounds)(ref bounds2)).center; return ((Vector3)(ref val5)).sqrMagnitude <= radiusSq; } return false; }).ToList(); DebugHit(__instance, val, effectiveRadius, componentsInChildren.Length, list.Count, hit); if (list.Count <= 1) { return true; } float pickaxe = hit.m_damage.m_pickaxe / (float)list.Count; _redistributing = true; try { foreach (Collider item in list) { HitData val2 = new HitData(); val2.m_damage = new DamageTypes { m_pickaxe = pickaxe }; Bounds bounds = item.bounds; val2.m_point = ((Bounds)(ref bounds)).center; val2.m_hitCollider = item; val2.m_dir = hit.m_dir; val2.m_attacker = hit.m_attacker; val2.m_pushForce = hit.m_pushForce; val2.m_toolTier = hit.m_toolTier; HitData val3 = val2; MineRock5 componentInParent = ((Component)item).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent != (Object)(object)__instance) { componentInParent.Damage(val3); } else { __instance.Damage(val3); } } } finally { _redistributing = false; } return false; } private static float GetEffectiveRadius(MineRock5 rock, Player player) { GetResourceSettings(rock, out var enabled, out var maxDistance); if (!enabled || maxDistance <= 0f) { return 0f; } if (Plugin.EnableLevelMode == null || !Plugin.EnableLevelMode.Value) { return maxDistance; } float num = ((Plugin.MinDistance != null) ? Plugin.MinDistance.Value : 1f); num = Mathf.Clamp(num, 0f, maxDistance); float num2 = (((Object)(object)player != (Object)null) ? Mathf.Clamp01(((Character)player).GetSkillFactor((SkillType)12)) : 0f); return Mathf.Lerp(num, maxDistance, num2); } private static Player TryResolvePlayerFromAttackerId(HitData hit) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) try { Type type = AccessTools.TypeByName("ZNetScene"); if (type == null) { return null; } PropertyInfo propertyInfo = AccessTools.Property(type, "instance"); object obj = ((propertyInfo != null) ? propertyInfo.GetValue(null, null) : null); if (obj == null) { return null; } MethodInfo methodInfo = AccessTools.Method(type, "FindInstance", (Type[])null, (Type[])null); if (methodInfo == null) { return null; } object obj2 = methodInfo.Invoke(obj, new object[1] { hit.m_attacker }); Component val = (Component)((obj2 is Component) ? obj2 : null); if ((Object)(object)val != (Object)null) { return val.GetComponent(); } GameObject val2 = (GameObject)((obj2 is GameObject) ? obj2 : null); return ((Object)(object)val2 != (Object)null) ? val2.GetComponent() : null; } catch { return null; } } private static void DebugHit(MineRock5 rock, Player player, float radius, int totalColliders, int affectedColliders, HitData hit) { if (Plugin.DebugLogging != null && Plugin.DebugLogging.Value && _debugHits < 12) { _debugHits++; string text = (((Object)(object)rock != (Object)null && (Object)(object)((Component)rock).gameObject != (Object)null) ? ((Object)((Component)rock).gameObject).name : ""); string text2 = (((Object)(object)rock != (Object)null) ? rock.m_name : ""); string hierarchyIdentity = GetHierarchyIdentity(rock); string networkPrefabIdentity = GetNetworkPrefabIdentity(rock); string materialIdentity = GetMaterialIdentity(rock); string dropIdentity = GetDropIdentity(rock); GetDropStats(rock, out var dropMin, out var dropMax, out var dropChance, out var dropCount); Logger.CreateLogSource("Ore Spread QoL").LogInfo((object)("Mining debug #" + _debugHits + ": object='" + text + "' m_name='" + text2 + "' hierarchy='" + hierarchyIdentity + "' prefab='" + networkPrefabIdentity + "' materials='" + materialIdentity + "' drops='" + dropIdentity + "' health=" + (((Object)(object)rock != (Object)null) ? rock.m_health.ToString("0.##") : "?") + " minTier=" + (((Object)(object)rock != (Object)null) ? rock.m_minToolTier.ToString() : "?") + " dropChance=" + dropChance.ToString("0.###") + " dropMin=" + dropMin + " dropMax=" + dropMax + " dropCount=" + dropCount + " radius=" + radius.ToString("0.00") + " totalColliders=" + totalColliders + " affected=" + affectedColliders + " attackerPlayer=" + (((Object)(object)player != (Object)null) ? "yes" : "no") + " pickaxeDamage=" + hit.m_damage.m_pickaxe.ToString("0.00"))); } } private static void GetResourceSettings(MineRock5 rock, out bool enabled, out float maxDistance) { string text = (((Object)(object)rock != (Object)null) ? (rock.m_name ?? string.Empty) : string.Empty); string text2 = (((Object)(object)rock != (Object)null && (Object)(object)((Component)rock).gameObject != (Object)null) ? (((Object)((Component)rock).gameObject).name ?? string.Empty) : string.Empty); string hierarchyIdentity = GetHierarchyIdentity(rock); string networkPrefabIdentity = GetNetworkPrefabIdentity(rock); string materialIdentity = GetMaterialIdentity(rock); string dropIdentity = GetDropIdentity(rock); GetDropStats(rock, out var dropMin, out var dropMax, out var dropChance, out var _); int num = (((Object)(object)rock != (Object)null) ? rock.m_minToolTier : (-999)); string value = networkPrefabIdentity + " " + text + " " + text2 + " " + hierarchyIdentity + " " + materialIdentity + " " + dropIdentity; if (Contains(materialIdentity, "rock_copper_internal") || Contains(materialIdentity, "rock1_copper") || Contains(dropIdentity, "copperore") || Contains(value, "rock4_copper") || Contains(value, "copper deposit")) { enabled = Plugin.CopperEnabled.Value; maxDistance = Plugin.CopperMaxDistance.Value; } else if (Contains(materialIdentity, "mudpile_ironscrap") || Contains(materialIdentity, "mudpile") || Contains(dropIdentity, "ironscrap") || Contains(value, "mudpile") || Contains(value, "mud pile")) { enabled = Plugin.IronEnabled.Value; maxDistance = Plugin.IronMaxDistance.Value; } else if (Contains(materialIdentity, "rock_silver_internal") || Contains(dropIdentity, "silverore") || Contains(value, "silver")) { enabled = Plugin.SilverEnabled.Value; maxDistance = Plugin.SilverMaxDistance.Value; } else if (Contains(materialIdentity, "giant_brain") || Contains(dropIdentity, "softtissue") || Contains(value, "softtissue") || Contains(value, "soft_tissue") || Contains(value, "giant_brain") || Contains(value, "giantbrain")) { enabled = Plugin.SoftTissueEnabled.Value; maxDistance = Plugin.SoftTissueMaxDistance.Value; } else if (Contains(materialIdentity, "giant_skeleton_exterior") || Contains(materialIdentity, "giant_skeleton_interior") || Contains(dropIdentity, "blackmarble") || Contains(value, "blackmarble") || Contains(value, "black_marble") || Contains(value, "giant_ribs") || Contains(value, "giant_skull") || Contains(value, "giant_bone") || Contains(value, "giantbone")) { enabled = Plugin.BlackMarbleEnabled.Value; maxDistance = Plugin.BlackMarbleMaxDistance.Value; } else if (Contains(dropIdentity, "flametal") || Contains(value, "flametal")) { enabled = Plugin.FlametalEnabled.Value; maxDistance = Plugin.FlametalMaxDistance.Value; } else if (num == 0 && Nearly(dropChance, 1f) && dropMin == 2 && dropMax == 4) { enabled = Plugin.CopperEnabled.Value; maxDistance = Plugin.CopperMaxDistance.Value; } else if (num == 0 && dropChance > 0f && dropChance <= 0.35f && dropMin == 1 && dropMax == 1) { enabled = Plugin.IronEnabled.Value; maxDistance = Plugin.IronMaxDistance.Value; } else if (num == 2 && Nearly(dropChance, 1f) && dropMin == 2 && dropMax == 3) { enabled = Plugin.SilverEnabled.Value; maxDistance = Plugin.SilverMaxDistance.Value; } else if (num >= 3 && Nearly(dropChance, 0.5f) && dropMin == 1 && dropMax == 1) { enabled = Plugin.SoftTissueEnabled.Value; maxDistance = Plugin.SoftTissueMaxDistance.Value; } else if (num >= 3 && Nearly(dropChance, 1f) && dropMin == 2 && dropMax == 4) { enabled = Plugin.BlackMarbleEnabled.Value; maxDistance = Plugin.BlackMarbleMaxDistance.Value; } else if (num >= 3 && Nearly(dropChance, 1f) && dropMin == 4 && dropMax == 8) { enabled = Plugin.FlametalEnabled.Value; maxDistance = Plugin.FlametalMaxDistance.Value; } else if (Contains(materialIdentity, "rock_internal") || Contains(dropIdentity, "stone") || Contains(value, "rock") || (num < 3 && Nearly(dropChance, 1f) && dropMin == 4 && dropMax == 8)) { enabled = Plugin.StoneEnabled.Value; maxDistance = Plugin.StoneMaxDistance.Value; } else { enabled = Plugin.OtherEnabled.Value; maxDistance = Plugin.OtherMaxDistance.Value; } } private static string GetNetworkPrefabIdentity(MineRock5 rock) { if ((Object)(object)rock == (Object)null || NViewField == null) { return string.Empty; } try { object value = NViewField.GetValue(rock); if (value == null) { return string.Empty; } MethodInfo methodInfo = AccessTools.Method(value.GetType(), "GetPrefabName", (Type[])null, (Type[])null); if (methodInfo == null) { return string.Empty; } object obj = methodInfo.Invoke(value, null); return (obj as string) ?? string.Empty; } catch { return string.Empty; } } private static string GetHierarchyIdentity(MineRock5 rock) { if ((Object)(object)rock == (Object)null || (Object)(object)((Component)rock).transform == (Object)null) { return string.Empty; } try { List list = new List(); Transform val = ((Component)rock).transform; int num = 0; while ((Object)(object)val != (Object)null && num++ < 12) { if (!string.IsNullOrEmpty(((Object)val).name)) { list.Add(((Object)val).name); } val = val.parent; } return string.Join("/", list.ToArray()); } catch { return string.Empty; } } private static string GetMaterialIdentity(MineRock5 rock) { if ((Object)(object)rock == (Object)null) { return string.Empty; } try { FieldInfo fieldInfo = AccessTools.Field(typeof(MineRock5), "m_meshRenderer"); Renderer val = (Renderer)((fieldInfo != null) ? /*isinst with value type is only supported in some contexts*/: null); List list = new List(); if ((Object)(object)val != (Object)null) { Material[] sharedMaterials = val.sharedMaterials; if (sharedMaterials != null) { Material[] array = sharedMaterials; foreach (Material val2 in array) { if ((Object)(object)val2 != (Object)null && !string.IsNullOrEmpty(((Object)val2).name)) { list.Add(((Object)val2).name); } } } } Renderer[] componentsInChildren = ((Component)rock).GetComponentsInChildren(); if (componentsInChildren != null) { Renderer[] array2 = componentsInChildren; foreach (Renderer val3 in array2) { if ((Object)(object)val3 == (Object)null) { continue; } Material[] sharedMaterials2 = val3.sharedMaterials; if (sharedMaterials2 == null) { continue; } Material[] array3 = sharedMaterials2; foreach (Material val4 in array3) { if ((Object)(object)val4 != (Object)null && !string.IsNullOrEmpty(((Object)val4).name) && !list.Contains(((Object)val4).name)) { list.Add(((Object)val4).name); } } } } return string.Join(",", list.ToArray()); } catch { return string.Empty; } } private static string GetDropIdentity(MineRock5 rock) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rock == (Object)null) { return string.Empty; } try { DropTable dropItems = rock.m_dropItems; if (dropItems == null || dropItems.m_drops == null) { return string.Empty; } List list = new List(); foreach (DropData drop in dropItems.m_drops) { if ((Object)(object)drop.m_item != (Object)null && !string.IsNullOrEmpty(((Object)drop.m_item).name)) { list.Add(((Object)drop.m_item).name); } } return string.Join(",", list.ToArray()); } catch { return string.Empty; } } private static void GetDropStats(MineRock5 rock, out int dropMin, out int dropMax, out float dropChance, out int dropCount) { dropMin = -1; dropMax = -1; dropChance = -1f; dropCount = 0; if ((Object)(object)rock == (Object)null || rock.m_dropItems == null) { return; } try { DropTable dropItems = rock.m_dropItems; dropMin = dropItems.m_dropMin; dropMax = dropItems.m_dropMax; dropChance = dropItems.m_dropChance; dropCount = ((dropItems.m_drops != null) ? dropItems.m_drops.Count : 0); } catch { } } private static bool Nearly(float a, float b) { return Mathf.Abs(a - b) <= 0.011f; } private static bool Contains(string value, string fragment) { if (!string.IsNullOrEmpty(value)) { return value.IndexOf(fragment, StringComparison.OrdinalIgnoreCase) >= 0; } return false; } } [HarmonyPatch(typeof(MineRock), "Damage")] internal static class MineRockFlametalDamagePatch { private static readonly FieldInfo NViewField = AccessTools.Field(typeof(MineRock), "m_nview"); private static readonly FieldInfo HitAreasField = AccessTools.Field(typeof(MineRock), "m_hitAreas"); private static readonly MethodInfo GetAreaIndexMethod = AccessTools.Method(typeof(MineRock), "GetAreaIndex", new Type[1] { typeof(Collider) }, (Type[])null); private static bool _redistributing; private static int _debugHits; private static bool Prefix(MineRock __instance, HitData hit) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Expected O, but got Unknown //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || hit == null || _redistributing) { return true; } if (Plugin.BypassKey != null) { KeyboardShortcut value = Plugin.BypassKey.Value; if (((KeyboardShortcut)(ref value)).IsPressed()) { return true; } } if (!IsModernFlametal(__instance)) { return true; } if (Plugin.FlametalEnabled == null || !Plugin.FlametalEnabled.Value) { return true; } Character attacker = hit.GetAttacker(); Player val = (Player)(object)((attacker is Player) ? attacker : null); if ((Object)(object)val == (Object)null) { val = TryResolvePlayerFromAttackerId(hit); } float effectiveRadius = GetEffectiveRadius(val); if (effectiveRadius <= 0f || hit.m_damage.m_pickaxe <= 0f) { return true; } Collider[] array = ((HitAreasField != null) ? (HitAreasField.GetValue(__instance) as Collider[]) : null); if (array == null || array.Length == 0) { return true; } float num = effectiveRadius * effectiveRadius; Vector3 point = hit.m_point; int num2 = -1; try { if ((Object)(object)hit.m_hitCollider != (Object)null && GetAreaIndexMethod != null) { object obj = GetAreaIndexMethod.Invoke(__instance, new object[1] { hit.m_hitCollider }); if (obj is int) { num2 = (int)obj; } } } catch { num2 = -1; } if (num2 < 0 || num2 >= array.Length) { DebugHit(__instance, val, effectiveRadius, array.Length, 0, num2, -1f, hit); return true; } Dictionary dictionary = new Dictionary(); float num3 = float.MaxValue; for (int i = 0; i < array.Length; i++) { Collider val2 = array[i]; if (!((Object)(object)val2 == (Object)null) && val2.enabled && !((Object)(object)((Component)val2).gameObject == (Object)null) && ((Component)val2).gameObject.activeInHierarchy) { Bounds bounds = val2.bounds; float num4 = ((Bounds)(ref bounds)).SqrDistance(point); if (num4 < num3) { num3 = num4; } if (!(num4 > num) || i == num2) { dictionary[i] = val2; } } } if (!dictionary.ContainsKey(num2) && (Object)(object)array[num2] != (Object)null) { dictionary[num2] = array[num2]; } float nearestBoundsDistance = ((num3 < float.MaxValue) ? Mathf.Sqrt(num3) : (-1f)); DebugHit(__instance, val, effectiveRadius, array.Length, dictionary.Count, num2, nearestBoundsDistance, hit); if (dictionary.Count <= 1) { return true; } float pickaxe = hit.m_damage.m_pickaxe / (float)dictionary.Count; _redistributing = true; try { foreach (Collider value2 in dictionary.Values) { HitData val3 = new HitData(); val3.m_damage = new DamageTypes { m_pickaxe = pickaxe }; Bounds bounds2 = value2.bounds; val3.m_point = ((Bounds)(ref bounds2)).center; val3.m_hitCollider = value2; val3.m_radius = 0f; val3.m_dir = hit.m_dir; val3.m_attacker = hit.m_attacker; val3.m_pushForce = hit.m_pushForce; val3.m_toolTier = hit.m_toolTier; val3.m_hitType = hit.m_hitType; HitData val4 = val3; __instance.Damage(val4); } } finally { _redistributing = false; } return false; } private static float GetEffectiveRadius(Player player) { float num = ((Plugin.FlametalMaxDistance != null) ? Plugin.FlametalMaxDistance.Value : 2f); if (num <= 0f) { return 0f; } if (Plugin.EnableLevelMode == null || !Plugin.EnableLevelMode.Value) { return num; } float num2 = ((Plugin.MinDistance != null) ? Plugin.MinDistance.Value : 1f); num2 = Mathf.Clamp(num2, 0f, num); float num3 = (((Object)(object)player != (Object)null) ? Mathf.Clamp01(((Character)player).GetSkillFactor((SkillType)12)) : 0f); return Mathf.Lerp(num2, num, num3); } private static bool IsModernFlametal(MineRock rock) { if ((Object)(object)rock == (Object)null) { return false; } string text = rock.m_name ?? string.Empty; string text2 = (((Object)(object)((Component)rock).gameObject != (Object)null) ? (((Object)((Component)rock).gameObject).name ?? string.Empty) : string.Empty); string hierarchyIdentity = GetHierarchyIdentity(rock); string networkPrefabIdentity = GetNetworkPrefabIdentity(rock); string dropIdentity = GetDropIdentity(rock); string value = text + " " + text2 + " " + hierarchyIdentity + " " + networkPrefabIdentity + " " + dropIdentity; if (!Contains(value, "LeviathanLava") && !Contains(text, "flametalore")) { return Contains(dropIdentity, "FlametalOreNew"); } return true; } private static Player TryResolvePlayerFromAttackerId(HitData hit) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) try { Type type = AccessTools.TypeByName("ZNetScene"); if (type == null) { return null; } PropertyInfo propertyInfo = AccessTools.Property(type, "instance"); object obj = ((propertyInfo != null) ? propertyInfo.GetValue(null, null) : null); if (obj == null) { return null; } MethodInfo methodInfo = AccessTools.Method(type, "FindInstance", (Type[])null, (Type[])null); if (methodInfo == null) { return null; } object obj2 = methodInfo.Invoke(obj, new object[1] { hit.m_attacker }); Component val = (Component)((obj2 is Component) ? obj2 : null); if ((Object)(object)val != (Object)null) { return val.GetComponent(); } GameObject val2 = (GameObject)((obj2 is GameObject) ? obj2 : null); return ((Object)(object)val2 != (Object)null) ? val2.GetComponent() : null; } catch { return null; } } private static string GetNetworkPrefabIdentity(MineRock rock) { if ((Object)(object)rock == (Object)null || NViewField == null) { return string.Empty; } try { object value = NViewField.GetValue(rock); if (value == null) { return string.Empty; } MethodInfo methodInfo = AccessTools.Method(value.GetType(), "GetPrefabName", (Type[])null, (Type[])null); if (methodInfo == null) { return string.Empty; } object obj = methodInfo.Invoke(value, null); return (obj as string) ?? string.Empty; } catch { return string.Empty; } } private static string GetHierarchyIdentity(MineRock rock) { if ((Object)(object)rock == (Object)null || (Object)(object)((Component)rock).transform == (Object)null) { return string.Empty; } try { List list = new List(); Transform val = ((Component)rock).transform; int num = 0; while ((Object)(object)val != (Object)null && num++ < 12) { if (!string.IsNullOrEmpty(((Object)val).name)) { list.Add(((Object)val).name); } val = val.parent; } return string.Join("/", list.ToArray()); } catch { return string.Empty; } } private static string GetDropIdentity(MineRock rock) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rock == (Object)null || rock.m_dropItems == null || rock.m_dropItems.m_drops == null) { return string.Empty; } try { List list = new List(); foreach (DropData drop in rock.m_dropItems.m_drops) { if ((Object)(object)drop.m_item != (Object)null && !string.IsNullOrEmpty(((Object)drop.m_item).name)) { list.Add(((Object)drop.m_item).name); } } return string.Join(",", list.ToArray()); } catch { return string.Empty; } } private static void DebugHit(MineRock rock, Player player, float radius, int totalColliders, int affectedAreas, int directAreaIndex, float nearestBoundsDistance, HitData hit) { if (Plugin.DebugLogging != null && Plugin.DebugLogging.Value && _debugHits < 12) { _debugHits++; string text = (((Object)(object)rock != (Object)null && (Object)(object)((Component)rock).gameObject != (Object)null) ? ((Object)((Component)rock).gameObject).name : ""); string text2 = (((Object)(object)rock != (Object)null) ? rock.m_name : ""); string hierarchyIdentity = GetHierarchyIdentity(rock); string networkPrefabIdentity = GetNetworkPrefabIdentity(rock); string dropIdentity = GetDropIdentity(rock); Logger.CreateLogSource("Ore Spread QoL").LogInfo((object)("Flametal debug #" + _debugHits + ": object='" + text + "' m_name='" + text2 + "' hierarchy='" + hierarchyIdentity + "' prefab='" + networkPrefabIdentity + "' drops='" + dropIdentity + "' radius=" + radius.ToString("0.00") + " totalHitAreas=" + totalColliders + " directArea=" + directAreaIndex + " nearestBoundsDistance=" + nearestBoundsDistance.ToString("0.00") + " affectedAreas=" + affectedAreas + " attackerPlayer=" + (((Object)(object)player != (Object)null) ? "yes" : "no") + " pickaxeDamage=" + hit.m_damage.m_pickaxe.ToString("0.00"))); } } private static bool Contains(string value, string fragment) { if (!string.IsNullOrEmpty(value)) { return value.IndexOf(fragment, StringComparison.OrdinalIgnoreCase) >= 0; } return false; } }