Decompiled source of DustBegone v1.0.2

BepInEx/plugins/DustBegone/DustBegone.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace DustBegone;

[BepInPlugin("DustBegone.Valheim", "DustBegone", "1.0.1")]
public class DustBegonePlugin : BaseUnityPlugin
{
	public const string PluginGuid = "DustBegone.Valheim";

	public const string PluginName = "DustBegone";

	public const string PluginVersion = "1.0.1";

	internal static DustBegonePlugin Instance;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<bool> BuildDust;

	internal static ConfigEntry<bool> CreatureDust;

	internal static ConfigEntry<bool> CultivatorDust;

	internal static ConfigEntry<bool> HoeDust;

	internal static ConfigEntry<bool> TreeDust;

	internal static ConfigEntry<bool> WeaponDust;

	internal static ConfigEntry<bool> InstantLootDrop;

	private Harmony _harmony;

	internal static bool LootEnabled => IsOn(InstantLootDrop);

	private void Awake()
	{
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Expected O, but got Unknown
		Instance = this;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch for DustBegone.");
		BuildDust = ((BaseUnityPlugin)this).Config.Bind<bool>("Dust Toggles", "Build Dust", true, "Remove building placement/destruction dust.");
		CreatureDust = ((BaseUnityPlugin)this).Config.Bind<bool>("Dust Toggles", "Creature Dust", true, "Remove creature death/corpse dust.");
		CultivatorDust = ((BaseUnityPlugin)this).Config.Bind<bool>("Dust Toggles", "Cultivator Dust", true, "Remove Cultivator dust.");
		HoeDust = ((BaseUnityPlugin)this).Config.Bind<bool>("Dust Toggles", "Hoe Dust", true, "Remove Hoe terrain dust.");
		TreeDust = ((BaseUnityPlugin)this).Config.Bind<bool>("Dust Toggles", "Tree Dust", true, "Remove tree/log/stump hit and destruction dust.");
		WeaponDust = ((BaseUnityPlugin)this).Config.Bind<bool>("Dust Toggles", "Weapon Dust", true, "Remove player weapon attack dust/VFX.");
		InstantLootDrop = ((BaseUnityPlugin)this).Config.Bind<bool>("Loot Toggles", "Instant Loot Drop", true, "Drop creature loot immediately on death.");
		_harmony = new Harmony("DustBegone.Valheim");
		_harmony.PatchAll(Assembly.GetExecutingAssembly());
		((BaseUnityPlugin)this).Logger.LogInfo((object)"DustBegone v1.0.0 loaded.");
	}

	private void OnDestroy()
	{
		try
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
		catch
		{
		}
		Instance = null;
	}

	internal static bool IsOn(ConfigEntry<bool> entry)
	{
		if ((Object)(object)Instance != (Object)null && Enabled != null && Enabled.Value && entry != null)
		{
			return entry.Value;
		}
		return false;
	}

	internal static void LogWarning(string text)
	{
		if ((Object)(object)Instance != (Object)null)
		{
			((BaseUnityPlugin)Instance).Logger.LogWarning((object)text);
		}
	}

	internal static void RemoveVfxFromList(EffectList list)
	{
		if (list != null && list.m_effectPrefabs != null && list.m_effectPrefabs.Length != 0)
		{
			list.m_effectPrefabs = list.m_effectPrefabs.Where((EffectData e) => e != null && ((Object)(object)e.m_prefab == (Object)null || !IsVfx(((Object)e.m_prefab).name))).ToArray();
		}
	}

	internal static void DisableVfx(EffectList list, bool disable)
	{
		if (list == null || list.m_effectPrefabs == null)
		{
			return;
		}
		EffectData[] effectPrefabs = list.m_effectPrefabs;
		foreach (EffectData val in effectPrefabs)
		{
			if (val != null && !((Object)(object)val.m_prefab == (Object)null) && IsVfx(((Object)val.m_prefab).name))
			{
				val.m_enabled = !disable;
			}
		}
	}

	internal static bool IsVfx(string name)
	{
		if (string.IsNullOrEmpty(name))
		{
			return false;
		}
		string text = name.ToLowerInvariant();
		if (!text.Contains("vfx") && !text.StartsWith("fx_"))
		{
			return text.Contains("dust");
		}
		return true;
	}

	internal static bool IsHoePiece(string name)
	{
		if (string.IsNullOrEmpty(name))
		{
			return false;
		}
		string text = name.ToLowerInvariant();
		if (!text.Contains("road") && !text.Contains("raise") && !text.Contains("path_"))
		{
			return text.Contains("paved");
		}
		return true;
	}

	internal static bool IsCultivatorPiece(string name)
	{
		if (string.IsNullOrEmpty(name))
		{
			return false;
		}
		string text = name.ToLowerInvariant();
		if (!text.Contains("replant"))
		{
			return text.Contains("cultivate");
		}
		return true;
	}

	internal static void StripTreePrefab(GameObject prefab)
	{
		if (!((Object)(object)prefab == (Object)null))
		{
			TreeBase component = prefab.GetComponent<TreeBase>();
			if ((Object)(object)component != (Object)null)
			{
				RemoveVfxFromList(component.m_hitEffect);
				RemoveVfxFromList(component.m_destroyedEffect);
			}
			TreeLog component2 = prefab.GetComponent<TreeLog>();
			if ((Object)(object)component2 != (Object)null)
			{
				RemoveVfxFromList(component2.m_hitEffect);
				RemoveVfxFromList(component2.m_destroyedEffect);
			}
			Destructible component3 = prefab.GetComponent<Destructible>();
			if ((Object)(object)component3 != (Object)null && LooksLikeTree(((Object)prefab).name))
			{
				RemoveVfxFromList(component3.m_hitEffect);
				RemoveVfxFromList(component3.m_destroyedEffect);
			}
			ImpactEffect component4 = prefab.GetComponent<ImpactEffect>();
			if ((Object)(object)component4 != (Object)null && LooksLikeTree(((Object)prefab).name))
			{
				RemoveVfxFromList(component4.m_hitEffect);
			}
		}
	}

	internal static bool LooksLikeTree(string name)
	{
		if (string.IsNullOrEmpty(name))
		{
			return false;
		}
		string text = name.ToLowerInvariant();
		if (!text.Contains("tree") && !text.Contains("log") && !text.Contains("stump") && !text.Contains("beech") && !text.Contains("fir") && !text.Contains("pine") && !text.Contains("birch") && !text.Contains("oak"))
		{
			return text.Contains("ygg");
		}
		return true;
	}
}
[HarmonyPatch(typeof(ZNetScene), "Awake")]
internal static class ZNetSceneAwakePatch
{
	[HarmonyPriority(0)]
	private static void Postfix(ZNetScene __instance)
	{
		if ((Object)(object)DustBegonePlugin.Instance == (Object)null || DustBegonePlugin.Enabled == null || !DustBegonePlugin.Enabled.Value)
		{
			return;
		}
		foreach (GameObject prefab3 in __instance.m_prefabs)
		{
			if ((Object)(object)prefab3 == (Object)null)
			{
				continue;
			}
			Piece component = prefab3.GetComponent<Piece>();
			WearNTear component2 = prefab3.GetComponent<WearNTear>();
			if (DustBegonePlugin.BuildDust.Value)
			{
				if ((Object)(object)component != (Object)null)
				{
					DustBegonePlugin.RemoveVfxFromList(component.m_placeEffect);
				}
				if ((Object)(object)component2 != (Object)null)
				{
					DustBegonePlugin.RemoveVfxFromList(component2.m_destroyedEffect);
				}
			}
			if (DustBegonePlugin.HoeDust.Value && (Object)(object)component != (Object)null && DustBegonePlugin.IsHoePiece(((Object)prefab3).name))
			{
				DustBegonePlugin.RemoveVfxFromList(component.m_placeEffect);
			}
			if (DustBegonePlugin.CultivatorDust.Value && (Object)(object)component != (Object)null && DustBegonePlugin.IsCultivatorPiece(((Object)prefab3).name))
			{
				DustBegonePlugin.RemoveVfxFromList(component.m_placeEffect);
			}
			if (DustBegonePlugin.TreeDust.Value)
			{
				DustBegonePlugin.StripTreePrefab(prefab3);
			}
		}
		if (!DustBegonePlugin.CultivatorDust.Value)
		{
			return;
		}
		try
		{
			GameObject prefab = __instance.GetPrefab("Cultivator");
			if (!((Object)(object)prefab != (Object)null))
			{
				return;
			}
			ItemDrop component3 = prefab.GetComponent<ItemDrop>();
			PieceTable val = (((Object)(object)component3 == (Object)null) ? null : component3.m_itemData.m_shared.m_buildPieces);
			if (!((Object)(object)val != (Object)null))
			{
				return;
			}
			foreach (GameObject piece in val.m_pieces)
			{
				if ((Object)(object)piece == (Object)null)
				{
					continue;
				}
				Piece component4 = piece.GetComponent<Piece>();
				if ((Object)(object)component4 == (Object)null && (Object)(object)ZNetScene.instance != (Object)null)
				{
					GameObject prefab2 = ZNetScene.instance.GetPrefab(((Object)piece).name);
					if ((Object)(object)prefab2 != (Object)null)
					{
						component4 = prefab2.GetComponent<Piece>();
					}
				}
				if ((Object)(object)component4 != (Object)null)
				{
					DustBegonePlugin.RemoveVfxFromList(component4.m_placeEffect);
				}
			}
		}
		catch
		{
		}
	}
}
[HarmonyPriority(700)]
[HarmonyPatch(typeof(TerrainModifier), "OnPlaced")]
internal static class TerrainModifierOnPlacedPatch
{
	private static void Prefix(TerrainModifier __instance)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Expected O, but got Unknown
		if (DustBegonePlugin.IsOn(DustBegonePlugin.HoeDust))
		{
			__instance.m_onPlacedEffect = new EffectList();
		}
	}

	private static void Postfix(TerrainModifier __instance)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Expected O, but got Unknown
		if (DustBegonePlugin.IsOn(DustBegonePlugin.HoeDust))
		{
			__instance.m_onPlacedEffect = new EffectList();
		}
	}
}
[HarmonyPriority(700)]
[HarmonyPatch(typeof(TerrainOp), "OnPlaced")]
internal static class TerrainOpOnPlacedPatch
{
	private static void Prefix(TerrainOp __instance)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Expected O, but got Unknown
		if (DustBegonePlugin.IsOn(DustBegonePlugin.HoeDust))
		{
			__instance.m_onPlacedEffect = new EffectList();
		}
	}

	private static void Postfix(TerrainOp __instance)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Expected O, but got Unknown
		if (DustBegonePlugin.IsOn(DustBegonePlugin.HoeDust))
		{
			__instance.m_onPlacedEffect = new EffectList();
		}
	}
}
[HarmonyPatch(typeof(Player), "PlacePiece")]
internal static class PlayerPlacePiecePatch
{
	[HarmonyPriority(700)]
	private static void Prefix(ref Piece piece)
	{
		if (!((Object)(object)piece == (Object)null) && DustBegonePlugin.Enabled.Value)
		{
			string name = ((Object)((Component)piece).gameObject).name;
			if (DustBegonePlugin.BuildDust.Value || (DustBegonePlugin.HoeDust.Value && DustBegonePlugin.IsHoePiece(name)) || (DustBegonePlugin.CultivatorDust.Value && DustBegonePlugin.IsCultivatorPiece(name)))
			{
				DustBegonePlugin.RemoveVfxFromList(piece.m_placeEffect);
			}
		}
	}
}
internal static class WeaponDustHelper
{
	private static Character GetAttackCharacter(Attack attack)
	{
		if (attack == null)
		{
			return null;
		}
		try
		{
			FieldInfo fieldInfo = AccessTools.Field(typeof(Attack), "m_character");
			if (fieldInfo != null)
			{
				object? value = fieldInfo.GetValue(attack);
				return (Character)((value is Character) ? value : null);
			}
			FieldInfo[] fields = typeof(Attack).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo2 in fields)
			{
				if (fieldInfo2 != null && typeof(Character).IsAssignableFrom(fieldInfo2.FieldType))
				{
					object? value2 = fieldInfo2.GetValue(attack);
					Character val = (Character)((value2 is Character) ? value2 : null);
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
				}
			}
		}
		catch
		{
		}
		return null;
	}

	private static object GetAttackWeapon(Attack attack)
	{
		if (attack == null)
		{
			return null;
		}
		try
		{
			FieldInfo fieldInfo = AccessTools.Field(typeof(Attack), "m_weapon");
			if (fieldInfo != null)
			{
				return fieldInfo.GetValue(attack);
			}
			FieldInfo[] fields = typeof(Attack).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo2 in fields)
			{
				if (fieldInfo2 == null)
				{
					continue;
				}
				string text = fieldInfo2.Name.ToLowerInvariant();
				if (text.Contains("weapon"))
				{
					object value = fieldInfo2.GetValue(attack);
					if (value != null)
					{
						return value;
					}
				}
			}
		}
		catch
		{
		}
		return null;
	}

	private static void ApplyWeaponSharedEffects(object weapon, bool disable, bool includeStart)
	{
		if (weapon == null)
		{
			return;
		}
		try
		{
			FieldInfo fieldInfo = AccessTools.Field(weapon.GetType(), "m_shared");
			object obj = ((fieldInfo == null) ? null : fieldInfo.GetValue(weapon));
			if (obj == null)
			{
				return;
			}
			string[] array = (includeStart ? new string[4] { "m_hitTerrainEffect", "m_hitEffect", "m_triggerEffect", "m_startEffect" } : new string[3] { "m_hitTerrainEffect", "m_hitEffect", "m_triggerEffect" });
			for (int i = 0; i < array.Length; i++)
			{
				FieldInfo fieldInfo2 = AccessTools.Field(obj.GetType(), array[i]);
				if (!(fieldInfo2 == null))
				{
					object? value = fieldInfo2.GetValue(obj);
					EffectList val = (EffectList)((value is EffectList) ? value : null);
					if (val != null)
					{
						DustBegonePlugin.DisableVfx(val, disable);
					}
				}
			}
		}
		catch
		{
		}
	}

	internal static void Apply(Attack attack, bool includeStart)
	{
		if (attack == null)
		{
			return;
		}
		Character attackCharacter = GetAttackCharacter(attack);
		if (!((Object)(object)attackCharacter != (Object)null) || attackCharacter.IsPlayer())
		{
			bool disable = DustBegonePlugin.IsOn(DustBegonePlugin.WeaponDust);
			DustBegonePlugin.DisableVfx(attack.m_hitTerrainEffect, disable);
			DustBegonePlugin.DisableVfx(attack.m_hitEffect, disable);
			DustBegonePlugin.DisableVfx(attack.m_triggerEffect, disable);
			if (includeStart)
			{
				DustBegonePlugin.DisableVfx(attack.m_startEffect, disable);
			}
			ApplyWeaponSharedEffects(GetAttackWeapon(attack), disable, includeStart);
		}
	}
}
[HarmonyPatch(typeof(Attack), "DoAreaAttack")]
internal static class AttackDoAreaAttackPatch
{
	private static void Prefix(Attack __instance)
	{
		WeaponDustHelper.Apply(__instance, includeStart: true);
	}
}
[HarmonyPatch(typeof(Attack), "DoNonAttack")]
internal static class AttackDoNonAttackPatch
{
	private static void Prefix(Attack __instance)
	{
		WeaponDustHelper.Apply(__instance, includeStart: true);
	}
}
[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
internal static class AttackDoMeleeAttackPatch
{
	private static void Prefix(Attack __instance)
	{
		WeaponDustHelper.Apply(__instance, includeStart: false);
	}
}
[HarmonyPatch(typeof(Character), "OnDeath")]
internal static class CharacterOnDeathPatch
{
	private static void Prefix(Character __instance)
	{
		if (DustBegonePlugin.IsOn(DustBegonePlugin.CreatureDust) && !((Object)(object)__instance == (Object)null) && !__instance.IsPlayer())
		{
			DustBegonePlugin.RemoveVfxFromList(__instance.m_deathEffects);
		}
	}
}
[HarmonyPatch(typeof(Ragdoll), "DestroyNow")]
internal static class RagdollDestroyNowPatch
{
	private static void Prefix(Ragdoll __instance)
	{
		if (DustBegonePlugin.IsOn(DustBegonePlugin.CreatureDust) && !((Object)(object)__instance == (Object)null))
		{
			DustBegonePlugin.RemoveVfxFromList(__instance.m_removeEffect);
		}
	}
}
[HarmonyPatch(typeof(Ragdoll), "Start")]
internal static class InstantLoot_RagdollStart_Patch
{
	private static readonly HashSet<int> Spawned = new HashSet<int>();

	[ThreadStatic]
	private static int _forcedInstanceId;

	private static void Postfix(Ragdoll __instance)
	{
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_0194: Unknown result type (might be due to invalid IL or missing references)
		if (!DustBegonePlugin.LootEnabled || (Object)(object)__instance == (Object)null)
		{
			return;
		}
		try
		{
			FieldInfo fieldInfo = AccessTools.Field(typeof(Ragdoll), "m_nview");
			object obj = ((fieldInfo == null) ? null : fieldInfo.GetValue(__instance));
			if (obj == null)
			{
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(obj.GetType(), "IsValid", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(obj.GetType(), "IsOwner", (Type[])null, (Type[])null);
			if (!(methodInfo == null) && !(methodInfo2 == null) && (bool)methodInfo.Invoke(obj, null) && (bool)methodInfo2.Invoke(obj, null))
			{
				int instanceID = ((Object)__instance).GetInstanceID();
				Spawned.Remove(instanceID);
				Vector3 val = ((Component)__instance).transform.position;
				MethodInfo methodInfo3 = AccessTools.Method(typeof(Ragdoll), "GetAverageBodyPosition", (Type[])null, (Type[])null);
				if (methodInfo3 != null)
				{
					val = (Vector3)methodInfo3.Invoke(__instance, null);
				}
				FieldInfo fieldInfo2 = AccessTools.Field(typeof(Ragdoll), "m_lootSpawnJoint");
				object obj2 = ((fieldInfo2 == null) ? null : fieldInfo2.GetValue(__instance));
				Component val2 = (Component)((obj2 is Component) ? obj2 : null);
				if ((Object)(object)val2 != (Object)null)
				{
					val = val2.transform.position;
				}
				MethodInfo methodInfo4 = AccessTools.Method(typeof(Ragdoll), "SpawnLoot", new Type[1] { typeof(Vector3) }, (Type[])null);
				if (!(methodInfo4 == null))
				{
					_forcedInstanceId = instanceID;
					methodInfo4.Invoke(__instance, new object[1] { val });
					Spawned.Add(instanceID);
					_forcedInstanceId = 0;
				}
			}
		}
		catch (Exception ex)
		{
			_forcedInstanceId = 0;
			DustBegonePlugin.LogWarning("Instant Loot Drop error: " + ex.Message);
		}
	}

	internal static bool AllowSpawn(Ragdoll instance)
	{
		if (!DustBegonePlugin.LootEnabled || (Object)(object)instance == (Object)null)
		{
			return true;
		}
		int instanceID = ((Object)instance).GetInstanceID();
		if (_forcedInstanceId == instanceID)
		{
			return true;
		}
		return !Spawned.Contains(instanceID);
	}

	internal static void Forget(Ragdoll instance)
	{
		if ((Object)(object)instance != (Object)null)
		{
			Spawned.Remove(((Object)instance).GetInstanceID());
		}
	}
}
[HarmonyPatch(typeof(Ragdoll), "SpawnLoot")]
internal static class InstantLoot_SpawnLoot_Patch
{
	private static bool Prefix(Ragdoll __instance)
	{
		return InstantLoot_RagdollStart_Patch.AllowSpawn(__instance);
	}
}