Decompiled source of FriendlyTrollstav v1.0.0

BepInEx/plugins/FriendlyTrollstav/FriendlyTrollstav.dll

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

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

[BepInPlugin("nikki.valheim.friendlytrollstav", "Friendly Trollstav", "1.0.0")]
public sealed class Plugin : BaseUnityPlugin
{
	private Harmony harmony;

	private void Awake()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		harmony = new Harmony("nikki.valheim.friendlytrollstav");
		harmony.PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Friendly Trollstav loaded: summoned trolls and Trollstav effects cannot target or damage players.");
	}

	private void OnDestroy()
	{
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
	}
}
public sealed class FriendlyEffect : MonoBehaviour
{
	private void Start()
	{
		ZNetView component = ((Component)this).GetComponent<ZNetView>();
		if ((Object)(object)component != (Object)null && component.IsValid() && component.IsOwner())
		{
			component.GetZDO().Set("nikki_friendly_trollstav", true);
		}
	}
}
internal static class Rules
{
	[ThreadStatic]
	internal static bool InTrollEffect;

	internal static bool IsTroll(Character character)
	{
		if ((Object)(object)character == (Object)null)
		{
			return false;
		}
		string name = ((Object)((Component)character).gameObject).name;
		return name == "Troll_Summoned" || name.StartsWith("Troll_Summoned(", StringComparison.Ordinal) || name.StartsWith("Troll_Summoned ", StringComparison.Ordinal);
	}

	internal static bool IsStaff(ItemData item)
	{
		return item != null && (Object)(object)item.m_dropPrefab != (Object)null && ((Object)item.m_dropPrefab).name == "StaffRedTroll";
	}

	internal static bool Protected(Component component)
	{
		if ((Object)(object)component == (Object)null)
		{
			return false;
		}
		if ((Object)(object)component.GetComponentInParent<FriendlyEffect>() != (Object)null)
		{
			return true;
		}
		Character character = (Character)(object)((component is Character) ? component : null);
		if (IsTroll(character))
		{
			return true;
		}
		ZNetView component2 = component.GetComponent<ZNetView>();
		if ((Object)(object)component2 != (Object)null && component2.IsValid() && component2.GetZDO().GetBool("nikki_friendly_trollstav", false))
		{
			return true;
		}
		FieldInfo fieldInfo = AccessTools.Field(((object)component).GetType(), "m_owner");
		return fieldInfo != null && IsTroll((Character)/*isinst with value type is only supported in some contexts*/);
	}

	internal static void Mark(GameObject obj)
	{
		if ((Object)(object)obj != (Object)null && (Object)(object)obj.GetComponent<FriendlyEffect>() == (Object)null)
		{
			obj.AddComponent<FriendlyEffect>();
		}
	}

	public static GameObject Spawn(GameObject prefab, Vector3 position, Quaternion rotation)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Object.Instantiate<GameObject>(prefab, position, rotation);
		if (InTrollEffect)
		{
			Mark(val);
		}
		return val;
	}
}
[HarmonyPatch(typeof(BaseAI), "IsEnemy", new Type[]
{
	typeof(Character),
	typeof(Character)
})]
internal static class NoPlayerTarget
{
	private static bool Prefix(Character __0, Character __1, ref bool __result)
	{
		if (Rules.IsTroll(__0) && (Object)(object)__1 != (Object)null && __1.IsPlayer())
		{
			__result = false;
			return false;
		}
		return true;
	}
}
[HarmonyPatch(typeof(MonsterAI), "UpdateTarget")]
internal static class ClearExistingTarget
{
	private static void Postfix(MonsterAI __instance)
	{
		if (Rules.IsTroll(((Component)__instance).GetComponent<Character>()))
		{
			object? value = AccessTools.Field(typeof(MonsterAI), "m_targetCreature").GetValue(__instance);
			Character val = (Character)((value is Character) ? value : null);
			if ((Object)(object)val != (Object)null && val.IsPlayer())
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(MonsterAI), "SetTarget", (Type[])null, (Type[])null);
				object[] parameters = new object[1];
				methodInfo.Invoke(__instance, parameters);
			}
		}
	}
}
[HarmonyPatch(typeof(Character), "Damage")]
internal static class NoPlayerDamage
{
	private static bool Prefix(Character __instance, HitData __0)
	{
		return !__instance.IsPlayer() || (!Rules.InTrollEffect && (__0 == null || !Rules.IsTroll(__0.GetAttacker())));
	}
}
[HarmonyPatch(typeof(Character), "RPC_Damage")]
internal static class NoPlayerRPCDamage
{
	private static bool Prefix(Character __instance, HitData __1)
	{
		return !__instance.IsPlayer() || (!Rules.InTrollEffect && (__1 == null || !Rules.IsTroll(__1.GetAttacker())));
	}
}
[HarmonyPatch(typeof(Projectile), "Setup")]
internal static class MarkProjectile
{
	private static void Postfix(Projectile __instance, Character __0, ItemData __4, ItemData __5)
	{
		if (Rules.InTrollEffect || Rules.IsTroll(__0) || Rules.IsStaff(__4) || Rules.IsStaff(__5))
		{
			Rules.Mark(((Component)__instance).gameObject);
			__instance.m_hitOwner = false;
		}
	}
}
[HarmonyPatch(typeof(Aoe), "Setup")]
internal static class MarkArea
{
	private static void Postfix(Aoe __instance, Character __0, ItemData __4, ItemData __5)
	{
		if (Rules.InTrollEffect || Rules.IsTroll(__0) || Rules.IsStaff(__4) || Rules.IsStaff(__5))
		{
			Rules.Mark(((Component)__instance).gameObject);
			__instance.m_hitOwner = false;
		}
	}
}
[HarmonyPatch(typeof(Aoe), "OnHit")]
internal static class NoAreaPlayerHit
{
	private static bool Prefix(Aoe __instance, Collider __0, ref bool __result)
	{
		if ((Object)(object)__0 == (Object)null || (!Rules.InTrollEffect && !Rules.Protected((Component)(object)__instance)))
		{
			return true;
		}
		Character componentInParent = ((Component)__0).GetComponentInParent<Character>();
		if ((Object)(object)componentInParent != (Object)null && componentInParent.IsPlayer())
		{
			__result = false;
			return false;
		}
		return true;
	}
}
[HarmonyPatch]
internal static class CaptureAttackContext
{
	private static IEnumerable<MethodBase> TargetMethods()
	{
		yield return AccessTools.Method(typeof(Projectile), "OnHit", (Type[])null, (Type[])null);
		yield return AccessTools.Method(typeof(Projectile), "SpawnOnHit", (Type[])null, (Type[])null);
		yield return AccessTools.Method(typeof(Aoe), "OnHit", (Type[])null, (Type[])null);
		yield return AccessTools.Method(typeof(Aoe), "CustomFixedUpdate", (Type[])null, (Type[])null);
		yield return AccessTools.Method(typeof(EffectList), "Create", (Type[])null, (Type[])null);
		yield return AccessTools.Method(typeof(Character), "OnDeath", (Type[])null, (Type[])null);
	}

	[HarmonyPriority(800)]
	private static void Prefix(object __instance, out bool __state)
	{
		__state = Rules.InTrollEffect;
		if (Rules.Protected((Component)((__instance is Component) ? __instance : null)))
		{
			Rules.InTrollEffect = true;
		}
	}

	private static void Finalizer(bool __state)
	{
		Rules.InTrollEffect = __state;
	}

	private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
	{
		foreach (CodeInstruction code in instructions)
		{
			MethodInfo method = code.operand as MethodInfo;
			if (method != null && method.DeclaringType == typeof(Object) && method.Name == "Instantiate" && method.IsGenericMethod && method.ReturnType == typeof(GameObject))
			{
				ParameterInfo[] parameters = method.GetParameters();
				if (parameters.Length == 3 && parameters[1].ParameterType == typeof(Vector3) && parameters[2].ParameterType == typeof(Quaternion))
				{
					code.opcode = OpCodes.Call;
					code.operand = AccessTools.Method(typeof(Rules), "Spawn", (Type[])null, (Type[])null);
				}
			}
			yield return code;
		}
	}
}
[HarmonyPatch]
internal static class MarkEarlyEffects
{
	private static IEnumerable<MethodBase> TargetMethods()
	{
		yield return AccessTools.Method(typeof(Aoe), "Awake", (Type[])null, (Type[])null);
		yield return AccessTools.Method(typeof(Projectile), "Awake", (Type[])null, (Type[])null);
	}

	private static void Postfix(Component __instance)
	{
		if (Rules.InTrollEffect)
		{
			Rules.Mark(__instance.gameObject);
		}
	}
}