Decompiled source of MagicMirror v1.0.0

MagicMirror.dll

Decompiled an hour ago
using System;
using System.Collections.Generic;
using System.IO;
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 MagicMirrorMod;

[BepInPlugin("neck.valheim.magicmirror", "Magic Mirror", "1.0.0")]
public class MagicMirrorPlugin : BaseUnityPlugin
{
	public const string Guid = "neck.valheim.magicmirror";

	public const string Prefab = "MagicMirror";

	private const string Key = "item_magicmirror";

	internal static MagicMirrorPlugin Instance;

	private static ConfigEntry<int> cfgCrystal;

	private static ConfigEntry<int> cfgSilver;

	private static ConfigEntry<int> cfgWood;

	private static ConfigEntry<float> cfgCooldown;

	private static ConfigEntry<bool> cfgIgnoreTeleportRule;

	private static ConfigEntry<bool> cfgFallbackSpawn;

	private static GameObject container;

	private static GameObject instance;

	private static Sprite icon;

	private static float lastUse = -999f;

	private void Awake()
	{
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: Expected O, but got Unknown
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Expected O, but got Unknown
		//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c1: Expected O, but got Unknown
		Instance = this;
		cfgCrystal = ((BaseUnityPlugin)this).Config.Bind<int>("Recipe", "Crystal", 2, "Crystals needed to craft the mirror (0 = not required)");
		cfgSilver = ((BaseUnityPlugin)this).Config.Bind<int>("Recipe", "Silver", 1, "Silver needed to craft the mirror (0 = not required)");
		cfgWood = ((BaseUnityPlugin)this).Config.Bind<int>("Recipe", "Wood", 0, "Wood needed to craft the mirror (0 = not required)");
		cfgCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("General", "CooldownSeconds", 5f, "Delay between uses");
		cfgIgnoreTeleportRule = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "IgnoreTeleportRestrictions", true, "Allow teleporting with unteleportable items (ore, metals) in the inventory");
		cfgFallbackSpawn = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "TeleportToSpawnWithoutBed", true, "If you have no bed, go to the world spawn point instead of failing");
		Harmony val = new Harmony("neck.valheim.magicmirror");
		try
		{
			val.PatchAll(typeof(Patches));
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)ex);
		}
		MethodInfo methodInfo = AccessTools.Method(typeof(Humanoid), "ConsumeItem", (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			methodInfo = AccessTools.Method(typeof(Player), "ConsumeItem", (Type[])null, (Type[])null);
		}
		if (methodInfo != null)
		{
			val.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Patches), "ConsumePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
		else
		{
			Debug.LogError((object)"MagicMirror: ConsumeItem not found");
		}
		MethodInfo methodInfo2 = AccessTools.Method(typeof(Humanoid), "UseItem", (Type[])null, (Type[])null);
		if (methodInfo2 != null)
		{
			val.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(Patches), "UsePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
		else
		{
			Debug.LogError((object)"MagicMirror: UseItem not found");
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)("patched ConsumeItem=" + (methodInfo != null) + " UseItem=" + (methodInfo2 != null)));
	}

	private static GameObject FindItem(ObjectDB db, string name)
	{
		for (int i = 0; i < db.m_items.Count; i++)
		{
			if ((Object)(object)db.m_items[i] != (Object)null && ((Object)db.m_items[i]).name == name)
			{
				return db.m_items[i];
			}
		}
		return null;
	}

	private static void AddWord(string key, string value)
	{
		MethodInfo methodInfo = AccessTools.Method(typeof(Localization), "AddWord", (Type[])null, (Type[])null);
		if (methodInfo != null)
		{
			methodInfo.Invoke(Localization.instance, new object[2] { key, value });
		}
	}

	private static bool RussianUi()
	{
		return Localization.instance != null && Localization.instance.GetSelectedLanguage() == "Russian";
	}

	private static Sprite LoadIcon()
	{
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Expected O, but got Unknown
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)icon != (Object)null)
		{
			return icon;
		}
		using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MagicMirrorMod.MagicMirror.png");
		if (stream == null)
		{
			return null;
		}
		byte[] array = new byte[stream.Length];
		stream.Read(array, 0, array.Length);
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
		if (!ImageConversion.LoadImage(val, array))
		{
			return null;
		}
		icon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
		return icon;
	}

	private static void BuildPrefab(ObjectDB db)
	{
		//IL_00cf: 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)
		//IL_0062: Expected O, but got Unknown
		//IL_018e: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = FindItem(db, "Wishbone");
		if ((Object)(object)val == (Object)null)
		{
			val = FindItem(db, "BeltStrength");
		}
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		if ((Object)(object)container == (Object)null)
		{
			container = new GameObject("MagicMirrorContainer");
			container.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)container);
		}
		GameObject val2 = Object.Instantiate<GameObject>(val, container.transform);
		((Object)val2).name = "MagicMirror";
		ItemDrop component = val2.GetComponent<ItemDrop>();
		component.m_itemData.m_dropPrefab = val2;
		SharedData shared = component.m_itemData.m_shared;
		shared.m_name = "$item_magicmirror";
		shared.m_description = "$item_magicmirror_description";
		shared.m_itemType = (ItemType)18;
		shared.m_maxStackSize = 1;
		shared.m_weight = 0.5f;
		shared.m_food = 0f;
		shared.m_foodStamina = 0f;
		shared.m_foodRegen = 0f;
		shared.m_foodBurnTime = 0f;
		shared.m_consumeStatusEffect = null;
		shared.m_setStatusEffect = null;
		shared.m_equipStatusEffect = null;
		Sprite val3 = LoadIcon();
		if ((Object)(object)val3 != (Object)null)
		{
			shared.m_icons = (Sprite[])(object)new Sprite[1] { val3 };
		}
		Renderer[] componentsInChildren = val2.GetComponentsInChildren<Renderer>(true);
		foreach (Renderer val4 in componentsInChildren)
		{
			Material[] materials = val4.materials;
			for (int j = 0; j < materials.Length; j++)
			{
				materials[j].color = new Color(0.55f, 0.8f, 1f);
			}
			val4.materials = materials;
		}
		instance = val2;
	}

	internal static void EnsureItems(ObjectDB db)
	{
		if ((Object)(object)db == (Object)null || db.m_items.Count == 0)
		{
			return;
		}
		FieldInfo fieldInfo = AccessTools.Field(typeof(ObjectDB), "m_itemByHash");
		Dictionary<int, GameObject> dictionary = ((fieldInfo != null) ? ((Dictionary<int, GameObject>)fieldInfo.GetValue(db)) : null);
		if ((Object)(object)instance == (Object)null)
		{
			BuildPrefab(db);
		}
		if ((Object)(object)instance == (Object)null)
		{
			return;
		}
		bool flag = RussianUi();
		AddWord("item_magicmirror", flag ? "Магическое зеркало" : "Magic Mirror");
		AddWord("item_magicmirror_description", flag ? "Загляните в зеркало - и вы окажетесь у своей кровати. Не расходуется." : "Gaze into the mirror to return to your bed. Never used up.");
		if ((Object)(object)FindItem(db, "MagicMirror") == (Object)null)
		{
			db.m_items.Add(instance);
			if (dictionary != null)
			{
				dictionary[StringExtensionMethods.GetStableHashCode("MagicMirror")] = instance;
			}
		}
		AddRecipe(db);
	}

	private static void AddRecipe(ObjectDB db)
	{
		for (int i = 0; i < db.m_recipes.Count; i++)
		{
			if ((Object)(object)db.m_recipes[i] != (Object)null && ((Object)db.m_recipes[i]).name == "Recipe_MagicMirror")
			{
				return;
			}
		}
		List<Requirement> list = new List<Requirement>();
		AddReq(db, list, "Crystal", cfgCrystal.Value);
		AddReq(db, list, "Silver", cfgSilver.Value);
		AddReq(db, list, "Wood", cfgWood.Value);
		if (list.Count == 0)
		{
			AddReq(db, list, "Wood", 1);
		}
		if (list.Count != 0)
		{
			Recipe val = ScriptableObject.CreateInstance<Recipe>();
			((Object)val).name = "Recipe_MagicMirror";
			val.m_item = instance.GetComponent<ItemDrop>();
			val.m_amount = 1;
			val.m_enabled = true;
			val.m_craftingStation = null;
			val.m_minStationLevel = 1;
			val.m_resources = list.ToArray();
			db.m_recipes.Add(val);
		}
	}

	private static void AddReq(ObjectDB db, List<Requirement> list, string item, int amount)
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Expected O, but got Unknown
		if (amount > 0)
		{
			GameObject val = FindItem(db, item);
			if (!((Object)(object)val == (Object)null))
			{
				Requirement val2 = new Requirement();
				val2.m_resItem = val.GetComponent<ItemDrop>();
				val2.m_amount = amount;
				val2.m_amountPerLevel = 0;
				val2.m_recover = true;
				list.Add(val2);
			}
		}
	}

	internal static void RegisterInScene(ZNetScene scene)
	{
		if ((Object)(object)scene == (Object)null || (Object)(object)instance == (Object)null)
		{
			return;
		}
		FieldInfo fieldInfo = AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs");
		Dictionary<int, GameObject> dictionary = ((fieldInfo != null) ? ((Dictionary<int, GameObject>)fieldInfo.GetValue(scene)) : null);
		if (dictionary != null)
		{
			int stableHashCode = StringExtensionMethods.GetStableHashCode("MagicMirror");
			if (!dictionary.ContainsKey(stableHashCode))
			{
				scene.m_prefabs.Add(instance);
				dictionary[stableHashCode] = instance;
			}
		}
	}

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

	private static void Say(Player p, string en, string ru)
	{
		((Character)p).Message((MessageType)2, RussianUi() ? ru : en, 0, (Sprite)null, false);
	}

	internal static bool Use(Player p)
	{
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_0153: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: 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)
		if ((Object)(object)p == (Object)null || (Object)(object)p != (Object)(object)Player.m_localPlayer)
		{
			return false;
		}
		if (Time.time - lastUse < cfgCooldown.Value)
		{
			Say(p, "The mirror is still glowing...", "Зеркало ещё светится...");
			return false;
		}
		if (((Character)p).IsTeleporting())
		{
			return false;
		}
		if (!cfgIgnoreTeleportRule.Value && !((Humanoid)p).GetInventory().IsTeleportable(cfgIgnoreTeleportRule.Value))
		{
			Say(p, "You can't teleport with this cargo", "С этим грузом телепортироваться нельзя");
			return false;
		}
		PlayerProfile val = (((Object)(object)Game.instance != (Object)null) ? Game.instance.GetPlayerProfile() : null);
		if (val == null)
		{
			return false;
		}
		Vector3 val2;
		if (val.HaveCustomSpawnPoint())
		{
			val2 = val.GetCustomSpawnPoint();
		}
		else
		{
			if (!cfgFallbackSpawn.Value)
			{
				Say(p, "You have no bed", "У вас нет кровати");
				return false;
			}
			val2 = val.GetHomePoint();
		}
		lastUse = Time.time;
		Say(p, "Returning to your bed...", "Возвращение к кровати...");
		((Character)p).TeleportTo(val2 + Vector3.up * 0.5f, ((Component)p).transform.rotation, true);
		return true;
	}
}
internal static class Patches
{
	[HarmonyPostfix]
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	private static void ObjectDBAwake(ObjectDB __instance)
	{
		MagicMirrorPlugin.EnsureItems(__instance);
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
	private static void ObjectDBCopy(ObjectDB __instance)
	{
		MagicMirrorPlugin.EnsureItems(__instance);
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	private static void ZNetSceneAwake(ZNetScene __instance)
	{
		MagicMirrorPlugin.EnsureItems(ObjectDB.instance);
		MagicMirrorPlugin.RegisterInScene(__instance);
	}

	public static bool UsePrefix(Humanoid __instance, object[] __args)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Expected O, but got Unknown
		ItemData item = null;
		for (int i = 0; i < __args.Length; i++)
		{
			if (__args[i] is ItemData)
			{
				item = (ItemData)__args[i];
				break;
			}
		}
		if (!MagicMirrorPlugin.IsMirror(item))
		{
			return true;
		}
		MagicMirrorPlugin.Use((Player)(object)((__instance is Player) ? __instance : null));
		return false;
	}

	public static bool ConsumePrefix(Humanoid __instance, object[] __args, ref bool __result)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Expected O, but got Unknown
		ItemData item = null;
		for (int i = 0; i < __args.Length; i++)
		{
			if (__args[i] is ItemData)
			{
				item = (ItemData)__args[i];
				break;
			}
		}
		if (!MagicMirrorPlugin.IsMirror(item))
		{
			return true;
		}
		__result = MagicMirrorPlugin.Use((Player)(object)((__instance is Player) ? __instance : null));
		return false;
	}
}