Decompiled source of TerrainImpact v1.0.0

TerrainImpact.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ChorusReef.TerrainImpact;

[BepInProcess("valheim.exe")]
[BepInPlugin("ChorusReef.TerrainImpact", "Terrain Impact", "1.0.0")]
public sealed class TerrainImpactPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "ChorusReef.TerrainImpact";

	public const string PluginName = "Terrain Impact";

	public const string PluginVersion = "1.0.0";

	internal static ManualLogSource Log;

	internal static ConfigEntry<int> Strength;

	internal static ConfigEntry<float> Radius;

	internal static ConfigEntry<float> Cooldown;

	internal static ConfigEntry<bool> StoneDrops;

	internal static TerrainImpactPlugin Instance;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Expected O, but got Unknown
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Expected O, but got Unknown
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Expected O, but got Unknown
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Expected O, but got Unknown
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Instance = this;
		Strength = ((BaseUnityPlugin)this).Config.Bind<int>("Terrain Impact", "Impact Strength", 1, new ConfigDescription("Strength of one accepted impact. 1 approximates a normal pickaxe strike. Higher values lower more terrain; above 16, strength also widens the impact because Valheim limits digging depth.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 99), new object[0]));
		Radius = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain Impact", "Impact Radius (m)", 1.5f, new ConfigDescription("Base dig radius in metres. Normal is 1.5 m. Extreme strength adds more radius on top of this value.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 40f), new object[0]));
		Cooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain Impact", "Global Cooldown (s)", 10f, new ConfigDescription("Seconds after a successful terrain edit before any creature can make another. This is shared by all qualifying creatures. 0 allows every valid attack to attempt an edit.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), new object[0]));
		StoneDrops = ((BaseUnityPlugin)this).Config.Bind<bool>("Terrain Impact", "Stone Drops", false, new ConfigDescription("Allow the vanilla pickaxe terrain operation to spawn Stone from creature impacts. Disabled by default.", (AcceptableValueBase)null, new object[0]));
		_harmony = new Harmony("ChorusReef.TerrainImpact");
		_harmony.PatchAll(typeof(TerrainImpactPlugin).Assembly);
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Terrain Impact loaded: strength=" + Strength.Value + ", baseRadius=" + Radius.Value + "m, globalCooldown=" + Cooldown.Value + "s, stoneDrops=" + StoneDrops.Value + "."));
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
			_harmony = null;
		}
		Log = null;
		if (object.ReferenceEquals(Instance, this))
		{
			Instance = null;
		}
	}

	internal static bool IsHostReady()
	{
		if ((Object)(object)ZNet.instance != (Object)null)
		{
			return ZNet.instance.IsServer();
		}
		return false;
	}

	internal static string QualifyingAttack(Character character, ItemData weapon)
	{
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: 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_00a0: Invalid comparison between Unknown and I4
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: Invalid comparison between Unknown and I4
		if ((Object)(object)character == (Object)null || weapon == null || weapon.m_shared == null)
		{
			return null;
		}
		if (weapon.m_shared.m_attack == null)
		{
			return null;
		}
		string text = (((Object)(object)weapon.m_dropPrefab != (Object)null) ? ((Object)weapon.m_dropPrefab).name : null);
		if (text == null)
		{
			return null;
		}
		if (text.EndsWith("(Clone)", StringComparison.Ordinal))
		{
			text = text.Substring(0, text.Length - 7);
		}
		ZNetView component = ((Component)character).GetComponent<ZNetView>();
		ZDO val = (((Object)(object)component != (Object)null) ? component.GetZDO() : null);
		if (val == null)
		{
			return null;
		}
		int prefab = val.GetPrefab();
		AttackType attackType = weapon.m_shared.m_attack.m_attackType;
		if ((int)attackType == 1)
		{
			if (prefab == StringExtensionMethods.GetStableHashCode("Troll") && (text == "troll_groundslam" || text == "troll_log_swing_v"))
			{
				return text;
			}
			if (prefab == StringExtensionMethods.GetStableHashCode("Troll_Summoned") && (text == "troll_summoned_groundslam" || text == "troll_summoned_log_swing_v"))
			{
				return text;
			}
			if (prefab == StringExtensionMethods.GetStableHashCode("GoblinBrute") && text == "GoblinBrute_RageAttack")
			{
				return text;
			}
		}
		if ((int)attackType == 4)
		{
			if (prefab == StringExtensionMethods.GetStableHashCode("Lox") && text == "lox_stomp")
			{
				return text;
			}
			if (prefab == StringExtensionMethods.GetStableHashCode("SeekerBrute") && text == "SeekerBrute_groundslam")
			{
				return text;
			}
			if (prefab == StringExtensionMethods.GetStableHashCode("Abomination") && text == "Abomination_attack3")
			{
				return text;
			}
		}
		return null;
	}

	internal static string Position(Vector3 point)
	{
		return $"({point.x:F1}, {point.y:F1}, {point.z:F1})";
	}

	internal static float DigRadius()
	{
		return Radius.Value + (float)Mathf.Max(0, Strength.Value - 16) * 0.5f;
	}

	internal static float OperationRadius()
	{
		return DigRadius() + 1f;
	}

	internal static void ApplyPreset(bool maximum)
	{
		Strength.Value = ((!maximum) ? 1 : 99);
		Radius.Value = (maximum ? 40f : 1.5f);
		Cooldown.Value = (maximum ? 0f : 10f);
		StoneDrops.Value = false;
		if (maximum)
		{
			CreatureTerrainSpawnPatch.ClearCooldown();
		}
		if ((Object)(object)Instance != (Object)null)
		{
			((BaseUnityPlugin)Instance).Config.Save();
		}
		Log.LogInfo((object)("terrainimpact " + (maximum ? "max" : "min") + " applied."));
	}
}
[HarmonyPatch(typeof(Terminal), "InitTerminal")]
internal static class TerrainImpactDevCommandPatch
{
	private static readonly FieldInfo CommandsField = AccessTools.Field(typeof(Terminal), "commands");

	[HarmonyPostfix]
	private static void Postfix()
	{
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Expected O, but got Unknown
		if (CommandsField == null || CommandsField.GetValue(null) == null)
		{
			TerrainImpactPlugin.Log.LogError((object)"Valheim console command registry is unavailable.");
		}
		else
		{
			if (!(CommandsField.GetValue(null) is Dictionary<string, ConsoleCommand> dictionary) || dictionary.ContainsKey("terrainimpact"))
			{
				return;
			}
			new ConsoleCommand("terrainimpact", "Set Terrain Impact configuration: terrainimpact max or terrainimpact min", (ConsoleEvent)delegate(ConsoleEventArgs args)
			{
				if (args.Args.Length != 2 || (args.Args[1] != "max" && args.Args[1] != "min"))
				{
					args.Context.AddString("Usage: terrainimpact max | terrainimpact min");
				}
				else
				{
					bool flag = args.Args[1] == "max";
					TerrainImpactPlugin.ApplyPreset(flag);
					args.Context.AddString("Terrain Impact: " + (flag ? "max" : "min") + " settings applied.");
				}
			}, true, false, false, false, false, true, (ConsoleOptionsFetcher)null, false, false, false);
		}
	}
}
[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
internal static class CreatureImpactPreparePatch
{
	private static bool _reportedMissingPickaxe;

	[HarmonyPrefix]
	private static void Prefix(Attack __instance, Humanoid ___m_character)
	{
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		if (!TerrainImpactPlugin.IsHostReady())
		{
			return;
		}
		ItemData weapon = __instance.GetWeapon();
		string text = TerrainImpactPlugin.QualifyingAttack((Character)(object)___m_character, weapon);
		if (text != null)
		{
			CreatureTerrainSpawnPatch.BeginMelee(__instance);
			TerrainImpactPlugin.Log.LogInfo((object)("Qualifying " + text + " triggered near " + TerrainImpactPlugin.Position(((Component)___m_character).transform.position) + "."));
			if (!__instance.m_hitTerrain)
			{
				TerrainImpactPlugin.Log.LogWarning((object)(text + " has m_hitTerrain=false; no terrain operation will be attempted."));
			}
			else
			{
				AttachPickaxeTerrain(weapon);
			}
		}
	}

	[HarmonyFinalizer]
	private static Exception Finalizer(Exception __exception, Attack __instance)
	{
		CreatureTerrainSpawnPatch.EndMelee(__instance);
		return __exception;
	}

	internal static void AttachPickaxeTerrain(ItemData weapon)
	{
		if (!((Object)(object)weapon.m_shared.m_spawnOnHitTerrain != (Object)null))
		{
			GameObject pickaxeTerrain = GetPickaxeTerrain();
			if (!((Object)(object)pickaxeTerrain == (Object)null))
			{
				weapon.m_shared.m_spawnOnHitTerrain = pickaxeTerrain;
				TerrainImpactPlugin.Log.LogInfo((object)("Attached vanilla PickaxeAntler terrain operation digg_v3 to " + (((Object)(object)weapon.m_dropPrefab != (Object)null) ? ((Object)weapon.m_dropPrefab).name : "unknown attack") + "."));
			}
		}
	}

	internal static GameObject GetPickaxeTerrain()
	{
		GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab("PickaxeAntler") : null);
		ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null);
		GameObject val3 = (((Object)(object)val2 != (Object)null) ? val2.m_itemData.m_shared.m_spawnOnHitTerrain : null);
		if ((Object)(object)val3 == (Object)null || ((Object)val3).name != "digg_v3" || (Object)(object)val3.GetComponent<TerrainOp>() == (Object)null)
		{
			if (!_reportedMissingPickaxe)
			{
				TerrainImpactPlugin.Log.LogError((object)"Could not obtain the vanilla PickaxeAntler digg_v3 TerrainOp; creature terrain impact is disabled.");
				_reportedMissingPickaxe = true;
			}
			return null;
		}
		return val3;
	}
}
[HarmonyPatch(typeof(Attack), "SpawnOnHitTerrain")]
internal static class CreatureTerrainSpawnPatch
{
	private static ZNet _world;

	private static double _nextAllowedAt;

	[ThreadStatic]
	private static bool _tracking;

	[ThreadStatic]
	private static int _operationCalls;

	[ThreadStatic]
	private static Attack _activeMeleeAttack;

	[ThreadStatic]
	private static bool _meleeImpactConsumed;

	internal static void BeginMelee(Attack attack)
	{
		_activeMeleeAttack = attack;
		_meleeImpactConsumed = false;
	}

	internal static void ClearCooldown()
	{
		_nextAllowedAt = 0.0;
	}

	internal static void EndMelee(Attack attack)
	{
		if (object.ReferenceEquals(_activeMeleeAttack, attack))
		{
			_activeMeleeAttack = null;
			_meleeImpactConsumed = false;
		}
	}

	[HarmonyPrefix]
	private static bool Prefix(Attack __instance, Vector3 hitPoint, GameObject prefab, Character character, ItemData weapon, ref GameObject __result, out bool __state)
	{
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0179: Unknown result type (might be due to invalid IL or missing references)
		//IL_0192: Unknown result type (might be due to invalid IL or missing references)
		__state = false;
		if (!TerrainImpactPlugin.IsHostReady())
		{
			return true;
		}
		string text = TerrainImpactPlugin.QualifyingAttack(character, weapon);
		if (text == null)
		{
			return true;
		}
		if ((Object)(object)prefab != (Object)null && ((Object)prefab).name != "digg_v3" && text.StartsWith("troll_summoned_", StringComparison.Ordinal))
		{
			return true;
		}
		if (!object.ReferenceEquals(_world, ZNet.instance))
		{
			_world = ZNet.instance;
			_nextAllowedAt = 0.0;
		}
		double timeSeconds = ZNet.instance.GetTimeSeconds();
		TerrainImpactPlugin.Log.LogInfo((object)("Qualifying creature terrain contact at " + TerrainImpactPlugin.Position(hitPoint) + "."));
		if (object.ReferenceEquals(_activeMeleeAttack, __instance) && _meleeImpactConsumed)
		{
			TerrainImpactPlugin.Log.LogInfo((object)"Terrain deformation rejected: this melee attack already made one dent.");
			__result = null;
			return false;
		}
		if (timeSeconds < _nextAllowedAt)
		{
			TerrainImpactPlugin.Log.LogInfo((object)$"Terrain deformation rejected: global cooldown active ({_nextAllowedAt - timeSeconds:F1}s remaining) at {TerrainImpactPlugin.Position(hitPoint)}.");
			__result = null;
			return false;
		}
		if ((Object)(object)prefab == (Object)null || ((Object)prefab).name != "digg_v3")
		{
			TerrainImpactPlugin.Log.LogWarning((object)"Creature terrain contact did not carry digg_v3; operation skipped.");
			__result = null;
			return false;
		}
		if (!PrivateArea.CheckAccess(hitPoint, TerrainImpactPlugin.OperationRadius(), true, false))
		{
			TerrainImpactPlugin.Log.LogWarning((object)("Configured impact radius fails private-area access at " + TerrainImpactPlugin.Position(hitPoint) + "."));
			__result = null;
			return false;
		}
		TerrainOp componentInChildren = prefab.GetComponentInChildren<TerrainOp>();
		if ((Object)(object)componentInChildren != (Object)null)
		{
			bool flag = PrivateArea.CheckAccess(hitPoint, componentInChildren.GetRadius(), false, false);
			bool flag2 = Location.IsInsideNoBuildLocation(hitPoint);
			if (!flag || flag2)
			{
				TerrainImpactPlugin.Log.LogWarning((object)$"Native terrain gate at {TerrainImpactPlugin.Position(hitPoint)}: accessAllowed={flag}, noBuildLocation={flag2}; Valheim may reject this strike.");
			}
		}
		_operationCalls = 0;
		_tracking = true;
		__state = true;
		return true;
	}

	[HarmonyPostfix]
	private static void Postfix(Attack __instance, Vector3 hitPoint, GameObject __result, bool __state)
	{
		//IL_0095: 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)
		if (!__state)
		{
			return;
		}
		_tracking = false;
		if (_operationCalls > 0)
		{
			if (object.ReferenceEquals(_activeMeleeAttack, __instance))
			{
				_meleeImpactConsumed = true;
			}
			_nextAllowedAt = ZNet.instance.GetTimeSeconds() + (double)TerrainImpactPlugin.Cooldown.Value;
			TerrainImpactPlugin.Log.LogInfo((object)("Terrain deformation accepted at " + TerrainImpactPlugin.Position(hitPoint) + "; global cooldown started."));
			TerrainImpactPlugin.Log.LogInfo((object)$"Native terrain operation invoked ({_operationCalls} overlapping terrain compiler(s)).");
		}
		else
		{
			TerrainImpactPlugin.Log.LogWarning((object)("No native terrain operation was invoked at " + TerrainImpactPlugin.Position(hitPoint) + "; nativeResult=" + (((Object)(object)__result != (Object)null) ? "created" : "null") + "; cooldown remains available."));
		}
		_operationCalls = 0;
	}

	[HarmonyFinalizer]
	private static Exception Finalizer(Exception __exception, bool __state)
	{
		if (__state)
		{
			_tracking = false;
			_operationCalls = 0;
		}
		return __exception;
	}

	internal static void NoteNativeOperation(TerrainOp operation)
	{
		if (_tracking && (Object)(object)operation != (Object)null && ((Object)((Component)operation).gameObject).name.StartsWith("digg_v3", StringComparison.Ordinal))
		{
			_operationCalls++;
		}
	}

	internal static bool IsConfiguredCreatureOperation(Settings settings, GameObject prefab)
	{
		if (_tracking && settings != null && (Object)(object)prefab != (Object)null)
		{
			return ((Object)prefab).name.StartsWith("digg_v3", StringComparison.Ordinal);
		}
		return false;
	}

	internal static void ConfigureNativeOperation(TerrainOp operation)
	{
		if (_tracking && !((Object)(object)operation == (Object)null) && operation.m_settings != null && ((Object)((Component)operation).gameObject).name.StartsWith("digg_v3", StringComparison.Ordinal))
		{
			float num = TerrainImpactPlugin.DigRadius();
			operation.m_settings.m_raiseDelta = -0.5f * (float)TerrainImpactPlugin.Strength.Value;
			operation.m_settings.m_raiseRadius = num;
			operation.m_settings.m_paintRadius = num + 1f;
			if (!TerrainImpactPlugin.StoneDrops.Value)
			{
				operation.m_spawnOnPlaced = null;
			}
			TerrainImpactPlugin.Log.LogInfo((object)$"Configured creature dig: strength={TerrainImpactPlugin.Strength.Value}, targetDelta={operation.m_settings.m_raiseDelta:F1}m, digRadius={num:F1}m, stoneDrops={TerrainImpactPlugin.StoneDrops.Value}.");
		}
	}
}
[HarmonyPatch(typeof(Attack), "SpawnOnHitTerrain")]
internal static class SummonedTrollTerrainEffectPatch
{
	private static readonly MethodInfo SpawnOnHitTerrain = AccessTools.Method(typeof(Attack), "SpawnOnHitTerrain", (Type[])null, (Type[])null);

	[HarmonyPostfix]
	private static void Postfix(Attack __instance, Vector3 hitPoint, GameObject prefab, Character character, float __3, ItemData weapon, ItemData __5, bool __6)
	{
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		if (!TerrainImpactPlugin.IsHostReady() || (Object)(object)prefab == (Object)null || ((Object)prefab).name == "digg_v3")
		{
			return;
		}
		string text = TerrainImpactPlugin.QualifyingAttack(character, weapon);
		if (text == null || !text.StartsWith("troll_summoned_", StringComparison.Ordinal))
		{
			return;
		}
		GameObject pickaxeTerrain = CreatureImpactPreparePatch.GetPickaxeTerrain();
		if ((Object)(object)pickaxeTerrain == (Object)null || SpawnOnHitTerrain == null)
		{
			return;
		}
		TerrainImpactPlugin.Log.LogInfo((object)("Summoned Troll " + text + " kept native terrain-hit prefab " + ((Object)prefab).name + "; adding digg_v3 at " + TerrainImpactPlugin.Position(hitPoint) + "."));
		try
		{
			SpawnOnHitTerrain.Invoke(__instance, new object[7] { hitPoint, pickaxeTerrain, character, __3, weapon, __5, __6 });
		}
		catch (TargetInvocationException ex)
		{
			TerrainImpactPlugin.Log.LogError((object)("Summoned Troll terrain dig failed: " + ex.InnerException));
		}
	}
}
[HarmonyPatch(typeof(TerrainOp), "Awake")]
internal static class CreatureTerrainOperationConfigurePatch
{
	[HarmonyPrefix]
	private static void Prefix(TerrainOp __instance)
	{
		CreatureTerrainSpawnPatch.ConfigureNativeOperation(__instance);
	}
}
[HarmonyPatch(typeof(Settings), "Serialize")]
internal static class CreatureTerrainSettingsSerializePatch
{
	internal const int Marker = 1414090064;

	[HarmonyPostfix]
	private static void Postfix(Settings __instance, ZPackage __0, GameObject __1)
	{
		if (CreatureTerrainSpawnPatch.IsConfiguredCreatureOperation(__instance, __1))
		{
			__0.Write(1414090064);
			__0.Write(__instance.m_raiseDelta);
			__0.Write(__instance.m_raiseRadius);
			__0.Write(__instance.m_paintRadius);
		}
	}
}
[HarmonyPatch(typeof(Settings), "Deserialize")]
internal static class CreatureTerrainSettingsDeserializePatch
{
	private static readonly MethodInfo CloneMethod = typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic);

	[HarmonyPostfix]
	private static void Postfix(ZPackage __0, ref Settings __result)
	{
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Expected O, but got Unknown
		if (__result == null || __0.Size() - __0.GetPos() < 16)
		{
			return;
		}
		int pos = __0.GetPos();
		if (__0.ReadInt() != 1414090064)
		{
			__0.SetPos(pos);
			return;
		}
		float num = __0.ReadSingle();
		float num2 = __0.ReadSingle();
		float num3 = __0.ReadSingle();
		if (CloneMethod == null || float.IsNaN(num) || float.IsNaN(num2) || float.IsNaN(num3) || num > -0.5f || num < -49.5f || num2 < 0.5f || num2 > 81.5f || num3 < 1.5f || num3 > 82.5f)
		{
			TerrainImpactPlugin.Log.LogError((object)"Invalid creature terrain settings in RPC; vanilla settings retained.");
			return;
		}
		Settings val = (Settings)CloneMethod.Invoke(__result, null);
		val.m_raiseDelta = num;
		val.m_raiseRadius = num2;
		val.m_paintRadius = num3;
		__result = val;
	}
}
[HarmonyPatch(typeof(TerrainComp), "ApplyOperation")]
internal static class TerrainOperationObservedPatch
{
	[HarmonyPostfix]
	private static void Postfix(TerrainOp modifier)
	{
		CreatureTerrainSpawnPatch.NoteNativeOperation(modifier);
	}
}
[HarmonyPatch(typeof(Attack), "DoAreaAttack")]
internal static class CreatureAreaImpactPatch
{
	private static readonly MethodInfo GetAttackOrigin = AccessTools.Method(typeof(Attack), "GetAttackOrigin", (Type[])null, (Type[])null);

	private static readonly MethodInfo SpawnOnHitTerrain = AccessTools.Method(typeof(Attack), "SpawnOnHitTerrain", (Type[])null, (Type[])null);

	[HarmonyPrefix]
	private static void Prefix(Attack __instance, Humanoid ___m_character)
	{
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		if (TerrainImpactPlugin.IsHostReady())
		{
			ItemData weapon = __instance.GetWeapon();
			string text = TerrainImpactPlugin.QualifyingAttack((Character)(object)___m_character, weapon);
			if (text != null)
			{
				CreatureImpactPreparePatch.AttachPickaxeTerrain(weapon);
				TerrainImpactPlugin.Log.LogInfo((object)("Qualifying " + text + " area attack triggered near " + TerrainImpactPlugin.Position(((Component)___m_character).transform.position) + "."));
			}
		}
	}

	[HarmonyPostfix]
	private static void Postfix(Attack __instance, Humanoid ___m_character)
	{
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Expected O, but got Unknown
		//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_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0189: 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_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_0163: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Unknown result type (might be due to invalid IL or missing references)
		if (!TerrainImpactPlugin.IsHostReady())
		{
			return;
		}
		ItemData weapon = __instance.GetWeapon();
		if (TerrainImpactPlugin.QualifyingAttack((Character)(object)___m_character, weapon) == null || (Object)(object)weapon.m_shared.m_spawnOnHitTerrain == (Object)null)
		{
			return;
		}
		if (GetAttackOrigin == null || SpawnOnHitTerrain == null)
		{
			TerrainImpactPlugin.Log.LogError((object)"Required native Attack method missing; area terrain operation skipped.");
			return;
		}
		Transform val = (Transform)GetAttackOrigin.Invoke(__instance, null);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		Transform transform = ((Component)___m_character).transform;
		Vector3 val2 = val.position + Vector3.up * __instance.m_attackHeight + transform.forward * __instance.m_attackRange + transform.right * __instance.m_attackOffset;
		float attackRayWidth = __instance.m_attackRayWidth;
		RaycastHit[] array = Physics.RaycastAll(val2 + Vector3.up * attackRayWidth, Vector3.down, attackRayWidth * 2f + 0.5f);
		float num = float.MaxValue;
		Vector3 val3 = Vector3.zero;
		bool flag = false;
		RaycastHit[] array2 = array;
		for (int i = 0; i < array2.Length; i++)
		{
			RaycastHit val4 = array2[i];
			if (!((Object)(object)((RaycastHit)(ref val4)).collider == (Object)null) && !((Object)(object)((Component)((RaycastHit)(ref val4)).collider).GetComponent<Heightmap>() == (Object)null))
			{
				float num2 = Vector3.Distance(val2, ((RaycastHit)(ref val4)).point);
				if (!(num2 > attackRayWidth) && !(num2 >= num))
				{
					num = num2;
					val3 = ((RaycastHit)(ref val4)).point;
					flag = true;
				}
			}
		}
		if (!flag)
		{
			TerrainImpactPlugin.Log.LogInfo((object)("Qualifying area attack had no Heightmap contact near " + TerrainImpactPlugin.Position(val2) + "."));
			return;
		}
		try
		{
			SpawnOnHitTerrain.Invoke(__instance, new object[7]
			{
				val3,
				weapon.m_shared.m_spawnOnHitTerrain,
				___m_character,
				__instance.m_attackHitNoise,
				weapon,
				null,
				false
			});
		}
		catch (TargetInvocationException ex)
		{
			TerrainImpactPlugin.Log.LogError((object)("Native area terrain spawn failed: " + ex.InnerException));
		}
	}
}