Decompiled source of DanPe Mods v1.0.0

plugins/Sentinels.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Rendering;

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

[BepInPlugin("danpe.RuneMagicSentinels", "Rune Magic - Sentinel Stones", "1.0.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class SentinelsPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "danpe.RuneMagicSentinels";

	public const string PluginName = "Rune Magic - Sentinel Stones";

	public const string PluginVersion = "1.0.1";

	internal const string RuneMagicGuid = "hyleanlegend.RuneMagic";

	internal const string StonePrefab = "runemagic_StandingStone";

	internal const string WaygateName = "runemagic_waygate";

	internal const string NamePrefix = "runemagic_sentinel_";

	private const string RuneFocusItemName = "$item_runemagic_runefocus";

	private const int TestedMajor = 1;

	private const int TestedMinor = 5;

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<float> Range;

	internal static ConfigEntry<bool> ShootWildlife;

	internal static ConfigEntry<bool> SpareTaming;

	internal static ConfigEntry<float> EnergyCost;

	internal static ConfigEntry<bool> AllowUntestedVersion;

	internal static readonly Element[] Elements = Element.All();

	internal static bool Armed;

	private static Harmony _harmony;

	private static MethodInfo _sceneAwake;

	private static GameObject _container;

	private static PieceTable _table;

	private static bool _piecesConfigured;

	private static Texture _staveTexture;

	private static List<GameObject> _rmPrefabs;

	private void Awake()
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Expected O, but got Unknown
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Expected O, but got Unknown
		//IL_0158: Unknown result type (might be due to invalid IL or missing references)
		//IL_0162: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch (restart required). Every player on the server needs this add-on: the sentinels are new pieces. Off: no new sentinels and placed ones stand inert, but they are kept (never deleted), also by a host that has it switched off.");
		Range = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Range", 30f, new ConfigDescription("How far a sentinel sees and shoots, in metres (the vanilla ballista sees 30 m).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 60f), new object[0]));
		ShootWildlife = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Shoot wildlife", false, "Also shoot deer, hares and chickens. Off: only creatures that fight back are targets. Players, tames, your training dummy and Dvergers you have not angered are never targets, and sentinel shots pass through them, through your buildings and player-raised stones, and through crops.");
		SpareTaming = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Spare creatures being tamed", true, "Do not shoot a creature that has been fed and is partway through taming (boar, wolf, lox...). Off: every untamed creature that fights back is a target.");
		EnergyCost = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Energy cost", 150f, new ConfigDescription("Runic energy to raise a sentinel (refunded when you remove it).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f), new object[0]));
		AllowUntestedVersion = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Allow untested Rune Magic version", false, "This add-on was verified against Rune Magic 1.5.x. With any other version sentinels stay inert unless this is true.");
		for (int i = 0; i < Elements.Length; i++)
		{
			Elements[i].BindConfig(((BaseUnityPlugin)this).Config);
		}
		((BaseUnityPlugin)this).Config.SettingChanged += delegate
		{
			Tuning.LocalChanged();
		};
		_harmony = new Harmony("danpe.RuneMagicSentinels");
		try
		{
			PreparePersistence();
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Could not register the sentinel pieces; a host without them deletes placed sentinels. " + ex));
			return;
		}
		if (!Enabled.Value)
		{
			Log.LogInfo((object)"Sentinel Stones is OFF: placed sentinels are kept but inert.");
			return;
		}
		try
		{
			Setup();
			Armed = true;
			Log.LogInfo((object)"Sentinel Stones ready; the sentinels appear in the Rune Focus menu once a world is loaded.");
		}
		catch (Exception ex2)
		{
			Log.LogError((object)("Setup failed - sentinels stay inert and are not offered in the menu (placed ones are kept). " + ex2));
			Disarm();
		}
	}

	private void Update()
	{
		if ((Object)(object)_container != (Object)null)
		{
			Tuning.Tick();
		}
	}

	private void OnDestroy()
	{
		Teardown();
	}

	private static void PreparePersistence()
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Expected O, but got Unknown
		Type type = AccessTools.TypeByName("ValheimMod.CustomContentSetupHandler");
		FieldInfo fieldInfo = ((type != null) ? AccessTools.Field(type, "RegisteredNonItemPrefabs") : null);
		_rmPrefabs = ((fieldInfo != null) ? (fieldInfo.GetValue(null) as List<GameObject>) : null);
		GameObject val = FindStone();
		if ((Object)(object)val != (Object)null)
		{
			CaptureStave(val);
		}
		_container = new GameObject("RuneMagicSentinels_Prefabs");
		_container.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)_container);
		_sceneAwake = RequireMethod(typeof(ZNetScene), "Awake", Type.EmptyTypes);
		HarmonyMethod val2 = H("ZNetSceneAwakePrefix");
		val2.priority = 200;
		_harmony.Patch((MethodBase)_sceneAwake, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}

	private static void Disarm()
	{
		Armed = false;
		_table = null;
		if (_harmony == null)
		{
			return;
		}
		List<MethodBase> list;
		try
		{
			list = new List<MethodBase>(_harmony.GetPatchedMethods());
		}
		catch (Exception)
		{
			list = new List<MethodBase>();
		}
		foreach (MethodBase item in list)
		{
			if (!(item == _sceneAwake))
			{
				try
				{
					_harmony.Unpatch(item, (HarmonyPatchType)0, "danpe.RuneMagicSentinels");
				}
				catch (Exception ex2)
				{
					Log.LogWarning((object)("Unpatch failed for " + item.Name + ": " + ex2.Message));
				}
			}
		}
	}

	private static void Teardown()
	{
		Armed = false;
		try
		{
			for (int i = 0; i < Elements.Length; i++)
			{
				GameObject prefab = Elements[i].Prefab;
				if (!((Object)(object)prefab == (Object)null))
				{
					if ((Object)(object)_table != (Object)null)
					{
						_table.m_pieces.Remove(prefab);
					}
					if ((Object)(object)ZNetScene.instance != (Object)null)
					{
						ZNetScene.instance.m_prefabs.Remove(prefab);
					}
					Elements[i].Prefab = null;
				}
			}
			if ((Object)(object)_container != (Object)null)
			{
				Object.Destroy((Object)(object)_container);
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Unregister failed: " + ex.Message));
		}
		_container = null;
		_table = null;
		_piecesConfigured = false;
		if (_harmony != null)
		{
			try
			{
				_harmony.UnpatchSelf();
			}
			catch (Exception ex2)
			{
				Log.LogWarning((object)("Unpatch failed: " + ex2.Message));
			}
			_harmony = null;
		}
	}

	private static void CheckRuneMagicVersion()
	{
		if (!Chainloader.PluginInfos.TryGetValue("hyleanlegend.RuneMagic", out var value) || value == null)
		{
			throw new InvalidOperationException("Rune Magic is not loaded");
		}
		Version version = value.Metadata.Version;
		if (version.Major != 1 || version.Minor != 5)
		{
			if (!AllowUntestedVersion.Value)
			{
				throw new InvalidOperationException(string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x). Set 'Allow untested Rune Magic version' to true to try anyway."));
			}
			Log.LogWarning((object)string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x); continuing because the config allows it."));
		}
	}

	private static Type RequireType(string name)
	{
		Type type = AccessTools.TypeByName(name);
		if (type == null)
		{
			throw new InvalidOperationException("Type not found: " + name);
		}
		return type;
	}

	private static MethodInfo RequireMethod(Type t, string name, Type[] args)
	{
		MethodInfo methodInfo = ((args == null) ? AccessTools.Method(t, name, (Type[])null, (Type[])null) : AccessTools.Method(t, name, args, (Type[])null));
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Method not found: " + t.FullName + "." + name);
		}
		return methodInfo;
	}

	private static FieldInfo RequireField(Type t, string name)
	{
		FieldInfo fieldInfo = AccessTools.Field(t, name);
		if (fieldInfo == null)
		{
			throw new InvalidOperationException("Field not found: " + t.FullName + "." + name);
		}
		return fieldInfo;
	}

	private static HarmonyMethod H(string name)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(typeof(Patches), name, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Patch method missing: " + name);
		}
		return new HarmonyMethod(methodInfo);
	}

	private static void Setup()
	{
		CheckRuneMagicVersion();
		Type t = RequireType("ValheimMod.ValheimMod");
		MethodInfo methodInfo = RequireMethod(t, "get_isModAwake", Type.EmptyTypes);
		if (!(bool)methodInfo.Invoke(null, null))
		{
			throw new InvalidOperationException("Rune Magic did not finish initialising (isModAwake is false)");
		}
		Type t2 = RequireType("ValheimMod.UnlockManager");
		Type t3 = RequireType("ValheimMod.RunemagicPieceConfig");
		Type t4 = RequireType("ValheimMod.CustomContentSetupHandler");
		Type t5 = RequireType("ValheimMod.BoulderSetupHandler");
		MethodInfo methodInfo2 = RequireMethod(t2, "isUnlockable", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo3 = RequireMethod(t2, "isUnlocked", new Type[2]
		{
			typeof(Player),
			typeof(Piece)
		});
		MethodInfo methodInfo4 = RequireMethod(t3, "getEnergyCost", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo5 = RequireMethod(t5, "SetUpCustomBoulderFeatures", Type.EmptyTypes);
		MethodInfo methodInfo6 = RequireMethod(typeof(Projectile), "IsValidTarget", new Type[1] { typeof(IDestructible) });
		MethodInfo methodInfo7 = RequireMethod(typeof(Aoe), "ShouldHit", new Type[1] { typeof(Collider) });
		MethodInfo methodInfo8 = RequireMethod(typeof(Character), "Damage", new Type[1] { typeof(HitData) });
		MethodInfo methodInfo9 = RequireMethod(typeof(WearNTear), "Damage", new Type[1] { typeof(HitData) });
		MethodInfo methodInfo10 = RequireMethod(typeof(ShieldGenerator), "CheckProjectile", new Type[1] { typeof(Projectile) });
		FieldInfo fieldInfo = RequireField(typeof(Projectile), "m_ammo");
		RequireField(typeof(Aoe), "m_ammo");
		if (fieldInfo.FieldType != typeof(ItemData))
		{
			throw new InvalidOperationException("Projectile.m_ammo has an unexpected type");
		}
		Patches.ProjectileAmmo = MakeGetter(fieldInfo);
		if (!(RequireField(t4, "RegisteredItemPrefabs").GetValue(null) is List<GameObject> list))
		{
			throw new InvalidOperationException("Rune Magic's item prefab list has an unexpected type");
		}
		PieceTable val = null;
		foreach (GameObject item in list)
		{
			ItemDrop val2 = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null && val2.m_itemData.m_shared.m_name == "$item_runemagic_runefocus")
			{
				val = val2.m_itemData.m_shared.m_buildPieces;
				break;
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			throw new InvalidOperationException("Rune Focus piece table not found");
		}
		GameObject val3 = FindStone();
		if ((Object)(object)val3 == (Object)null || (Object)(object)val3.GetComponent<Piece>() == (Object)null || (Object)(object)val3.GetComponent<WearNTear>() == (Object)null || (Object)(object)val3.GetComponent<ZNetView>() == (Object)null)
		{
			throw new InvalidOperationException("Rune Magic's Standing Stone prefab was not found or has an unexpected shape");
		}
		_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, H("IsUnlockablePostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, H("IsUnlockedPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, H("EnergyCostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, H("BoulderSetupPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo6, H("ValidTargetPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo7, H("ShouldHitPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo8, H("CharacterDamagePrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo9, H("WearNTearDamagePrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo10, H("ShieldCheckPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		MethodBase[] array = new MethodBase[5] { methodInfo6, methodInfo7, methodInfo8, methodInfo9, methodInfo10 };
		for (int i = 0; i < array.Length; i++)
		{
			if (!HasOurPrefix(array[i]))
			{
				throw new InvalidOperationException("The friendly-fire filter on " + array[i].DeclaringType.Name + "." + array[i].Name + " did not apply");
			}
		}
		_table = val;
	}

	private static Func<Projectile, ItemData> MakeGetter(FieldInfo field)
	{
		DynamicMethod dynamicMethod = new DynamicMethod("Sentinel_GetAmmo", typeof(ItemData), new Type[1] { typeof(Projectile) }, typeof(Projectile), skipVisibility: true);
		ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
		iLGenerator.Emit(OpCodes.Ldarg_0);
		iLGenerator.Emit(OpCodes.Ldfld, field);
		iLGenerator.Emit(OpCodes.Ret);
		return (Func<Projectile, ItemData>)dynamicMethod.CreateDelegate(typeof(Func<Projectile, ItemData>));
	}

	private static bool HasOurPrefix(MethodBase m)
	{
		Patches patchInfo = Harmony.GetPatchInfo(m);
		if (patchInfo == null || patchInfo.Prefixes == null)
		{
			return false;
		}
		foreach (Patch prefix in patchInfo.Prefixes)
		{
			if (prefix.owner == "danpe.RuneMagicSentinels")
			{
				return true;
			}
		}
		return false;
	}

	private static GameObject FindStone()
	{
		if (_rmPrefabs == null)
		{
			return null;
		}
		for (int i = 0; i < _rmPrefabs.Count; i++)
		{
			if ((Object)(object)_rmPrefabs[i] != (Object)null && ((Object)_rmPrefabs[i]).name == "runemagic_StandingStone")
			{
				return _rmPrefabs[i];
			}
		}
		return null;
	}

	private static void CaptureStave(GameObject stone)
	{
		try
		{
			Transform val = stone.transform.Find("StandingStone");
			MeshRenderer val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<MeshRenderer>() : null);
			Material val3 = (((Object)(object)val2 != (Object)null) ? ((Renderer)val2).sharedMaterial : null);
			if ((Object)(object)val3 != (Object)null && val3.HasProperty("_EmissionMap"))
			{
				_staveTexture = val3.GetTexture("_EmissionMap");
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Could not read the standing stone's stave texture (sentinels will not glow): " + ex.Message));
		}
		if ((Object)(object)_staveTexture == (Object)null)
		{
			Log.LogInfo((object)"The standing stone's stave texture is not available; sentinels will not glow.");
		}
	}

	internal static void OnZNetSceneAwake(ZNetScene scene)
	{
		if ((Object)(object)scene == (Object)null || scene.m_prefabs == null || (Object)(object)_container == (Object)null)
		{
			return;
		}
		Dictionary<string, GameObject> dictionary = new Dictionary<string, GameObject>();
		for (int i = 0; i < scene.m_prefabs.Count; i++)
		{
			GameObject val = scene.m_prefabs[i];
			if ((Object)(object)val != (Object)null && !dictionary.ContainsKey(((Object)val).name))
			{
				dictionary[((Object)val).name] = val;
			}
		}
		if (!dictionary.TryGetValue("runemagic_StandingStone", out var value) || (Object)(object)value == (Object)null)
		{
			value = FindStone();
		}
		for (int j = 0; j < Elements.Length; j++)
		{
			Element element = Elements[j];
			if ((Object)(object)element.Prefab == (Object)null)
			{
				try
				{
					element.Resolve(dictionary);
				}
				catch (Exception ex)
				{
					element.Failed = true;
					Log.LogWarning((object)("The " + element.Title + " sentinel cannot fire and is not offered: " + ex.Message));
				}
				try
				{
					element.Prefab = (((Object)(object)value != (Object)null) ? Prefabs.Build(value, element, j, _staveTexture, _container.transform) : null);
				}
				catch (Exception ex2)
				{
					element.Failed = true;
					element.Prefab = null;
					Log.LogWarning((object)("The " + element.Title + " sentinel could not be built: " + ex2.Message));
				}
				if ((Object)(object)element.Prefab == (Object)null)
				{
					element.Failed = true;
					element.Prefab = Prefabs.Placeholder(element, _container.transform);
				}
			}
			if (!scene.m_prefabs.Contains(element.Prefab))
			{
				scene.m_prefabs.Add(element.Prefab);
			}
		}
		TryFinishPieceSetup();
	}

	internal static void TryFinishPieceSetup()
	{
		if ((Object)(object)_table == (Object)null || !Armed)
		{
			return;
		}
		if (!_piecesConfigured && (Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_items != null && ObjectDB.instance.m_items.Count > 0)
		{
			GameObject val = FindStone();
			Sprite stoneIcon = (((Object)(object)val != (Object)null && (Object)(object)val.GetComponent<Piece>() != (Object)null) ? val.GetComponent<Piece>().m_icon : null);
			int category = ((_table.m_categoryLabels != null && _table.m_categoryLabels.Count > 3) ? 3 : 0);
			bool piecesConfigured = false;
			for (int i = 0; i < Elements.Length; i++)
			{
				if (Elements[i].Offerable())
				{
					Prefabs.ConfigurePiece(Elements[i], stoneIcon, category);
					piecesConfigured = true;
				}
			}
			_piecesConfigured = piecesConfigured;
		}
		if (!_piecesConfigured)
		{
			return;
		}
		List<GameObject> pieces = _table.m_pieces;
		for (int num = pieces.Count - 1; num >= 0; num--)
		{
			GameObject val2 = pieces[num];
			if ((Object)(object)val2 != (Object)null && ((Object)val2).name.StartsWith("runemagic_sentinel_", StringComparison.Ordinal) && Array.IndexOf(PrefabList(), val2) < 0)
			{
				pieces.RemoveAt(num);
			}
		}
		for (int j = 0; j < Elements.Length; j++)
		{
			Element element = Elements[j];
			if ((Object)(object)element.Prefab == (Object)null)
			{
				continue;
			}
			bool flag = element.Offerable() && Tuning.HostAllows() && Tuning.Current.Offer[j];
			bool flag2 = pieces.Contains(element.Prefab);
			if (!flag)
			{
				if (flag2)
				{
					pieces.Remove(element.Prefab);
				}
			}
			else
			{
				if (flag2)
				{
					continue;
				}
				int index = pieces.Count;
				for (int k = 0; k < pieces.Count; k++)
				{
					if ((Object)(object)pieces[k] != (Object)null && ((Object)pieces[k]).name == "runemagic_waygate")
					{
						index = k;
						break;
					}
				}
				pieces.Insert(index, element.Prefab);
			}
		}
	}

	private static GameObject[] PrefabList()
	{
		GameObject[] array = (GameObject[])(object)new GameObject[Elements.Length];
		for (int i = 0; i < Elements.Length; i++)
		{
			array[i] = Elements[i].Prefab;
		}
		return array;
	}

	internal static int IndexFor(Piece piece)
	{
		if ((Object)(object)piece == (Object)null)
		{
			return -1;
		}
		string prefabName = Utils.GetPrefabName(((Component)piece).gameObject);
		for (int i = 0; i < Elements.Length; i++)
		{
			if (Elements[i].PrefabName == prefabName)
			{
				return i;
			}
		}
		return -1;
	}
}
internal sealed class Element
{
	internal string Key;

	internal string Title;

	internal string ProjectileName;

	internal string[][] OrbParts;

	internal Color LightColor;

	internal bool Flicker;

	internal Color StaveColor;

	internal string IconItem;

	internal float Speed;

	internal float DefaultSpread;

	internal float OrbScale;

	internal float DefaultDamage;

	internal float DefaultPhysical;

	internal float DefaultCooldown;

	internal int DefaultShots;

	internal string Blurb;

	internal ConfigEntry<bool> Enabled;

	internal ConfigEntry<float> Damage;

	internal ConfigEntry<float> Physical;

	internal ConfigEntry<float> Cooldown;

	internal ConfigEntry<int> Shots;

	internal ConfigEntry<float> Spread;

	internal GameObject Projectile;

	internal float Gravity;

	internal float RayRadius;

	internal List<GameObject> OrbSources = new List<GameObject>();

	internal GameObject Prefab;

	internal bool Failed;

	internal string PrefabName => "runemagic_sentinel_" + Key;

	internal bool Offerable()
	{
		if ((Object)(object)Prefab != (Object)null && !Failed && (Object)(object)Projectile != (Object)null)
		{
			return (Object)(object)Prefab.GetComponent<Piece>() != (Object)null;
		}
		return false;
	}

	internal static Element[] All()
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: 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_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_01af: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0254: Unknown result type (might be due to invalid IL or missing references)
		//IL_0269: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_030e: Unknown result type (might be due to invalid IL or missing references)
		return new Element[5]
		{
			Make("fire", "Fire", "Imp_fireball_projectile", new string[1][] { new string[4] { "Imp_fireball_projectile", "Sphere", "flames", "flames_world" } }, new Color(1f, 0.69f, 0.45f), flicker: false, new Color(3f, 0.9f, 0.1f), "StaffFireball", 25f, 1f, 1.75f, 50f, 15f, 2f, 1, "hurls fireballs that set hostile creatures burning (fire damage over time, plus a blunt blow). Surtlings, serpents, leeches and stone golems shrug off the fire."),
			Make("frost", "Frost", "staff_iceshard_projectile", new string[1][] { new string[4] { "hatchling_cold_projectile", "Sphere", "flames", "sparcs_world" } }, new Color(0.45f, 0.84f, 1f), flicker: false, new Color(0.3f, 1.5f, 3.5f), "StaffIceShards", 35f, 1.5f, 1.75f, 30f, 10f, 2f, 2, "fires volleys of ice shards that chill and slow hostile creatures. Drakes, wraiths, bats, abominations and stone golems are immune to the frost."),
			Make("lightning", "Lightning", "staff_lightning_projectile", new string[2][]
			{
				new string[2] { "fx_Lightning_red", "Sparcs" },
				new string[2] { "Imp_fireball_projectile", "Sphere" }
			}, new Color(1f, 0.35f, 0.15f), flicker: true, new Color(5f, 0.6f, 0.3f), "StaffLightning", 150f, 1.5f, 1.25f, 20f, 0f, 2.5f, 3, "strikes hostile creatures with bolts of lightning that land almost instantly. Few creatures resist lightning."),
			Make("poison", "Poison", "staff_greenroots_projectile", new string[1][] { new string[4] { "staff_greenroots_projectile", "Sphere", "flames", "Spores_World" } }, new Color(0.49f, 1f, 0.3f), flicker: false, new Color(0.5f, 2.5f, 0.2f), "StaffGreenRoots", 25f, 1f, 1.75f, 60f, 10f, 3f, 1, "lobs bursting orbs of venom that poison hostile creatures over time. The undead, surtlings, bats, abominations, golems and most blobs are immune to poison."),
			Make("spirit", "Spirit", "staff_skeleton_projectile", new string[1][] { new string[4] { "staff_skeleton_projectile", "fi_vil_combs_props_bone_skull", "fi_vil_combs_props_bone_skull (1)", "flames" } }, new Color(0.86f, 0.3f, 1f), flicker: false, new Color(1.8f, 0.2f, 3f), "StaffSkeleton", 22f, 1f, 1.5f, 50f, 25f, 2f, 1, "sends spirit skulls that sear the undead. Most living creatures are immune to spirit and take only the skull's piercing blow.")
		};
	}

	private static Element Make(string key, string title, string projectile, string[][] orbParts, Color light, bool flicker, Color stave, string iconItem, float speed, float spread, float orbScale, float damage, float physical, float cooldown, int shots, string blurb)
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		Element element = new Element();
		element.Key = key;
		element.Title = title;
		element.ProjectileName = projectile;
		element.OrbParts = orbParts;
		element.LightColor = light;
		element.Flicker = flicker;
		element.StaveColor = stave;
		element.IconItem = iconItem;
		element.Speed = speed;
		element.DefaultSpread = spread;
		element.OrbScale = orbScale;
		element.DefaultDamage = damage;
		element.DefaultPhysical = physical;
		element.DefaultCooldown = cooldown;
		element.DefaultShots = shots;
		element.Blurb = blurb;
		return element;
	}

	internal void BindConfig(ConfigFile config)
	{
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Expected O, but got Unknown
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Expected O, but got Unknown
		//IL_0165: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Expected O, but got Unknown
		//IL_0195: Unknown result type (might be due to invalid IL or missing references)
		//IL_019f: Expected O, but got Unknown
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d6: Expected O, but got Unknown
		string text = Title + " sentinel";
		string text2 = PhysicalKind();
		Enabled = config.Bind<bool>(text, "Enabled", true, "Offer the " + Title + " sentinel in the Rune Focus menu (the host's choice applies to everyone). Sentinels already raised keep working.");
		Damage = config.Bind<float>(text, Title + " damage", DefaultDamage, new ConfigDescription(Title + " damage per projectile" + ((Key == "fire" || Key == "poison" || Key == "spirit") ? " (dealt over a few seconds)" : "") + ".", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f), new object[0]));
		Physical = config.Bind<float>(text, "Physical damage", DefaultPhysical, new ConfigDescription("Extra " + text2 + " damage per projectile, so creatures immune to " + Title.ToLowerInvariant() + " still get hurt.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f), new object[0]));
		Cooldown = config.Bind<float>(text, "Seconds between volleys", DefaultCooldown, new ConfigDescription("Time between volleys.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f), new object[0]));
		Shots = config.Bind<int>(text, "Projectiles per volley", DefaultShots, new ConfigDescription("Projectiles fired at once, fanned out slightly.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 12), new object[0]));
		Spread = config.Bind<float>(text, "Spread (degrees)", DefaultSpread, new ConfigDescription("Largest random aim error per projectile. It is also capped so a volley stays about 0.7 m wide at the target.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), new object[0]));
	}

	internal string PhysicalKind()
	{
		if (!(Key == "fire") && !(Key == "poison"))
		{
			return "pierce";
		}
		return "blunt";
	}

	internal DamageTypes DamageTypes(float element, float physical)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		DamageTypes result = default(DamageTypes);
		switch (Key)
		{
		case "fire":
			result.m_fire = element;
			break;
		case "frost":
			result.m_frost = element;
			break;
		case "lightning":
			result.m_lightning = element;
			break;
		case "poison":
			result.m_poison = element;
			break;
		case "spirit":
			result.m_spirit = element;
			break;
		}
		if (PhysicalKind() == "blunt")
		{
			result.m_blunt = physical;
		}
		else
		{
			result.m_pierce = physical;
		}
		return result;
	}

	internal void Resolve(Dictionary<string, GameObject> byName)
	{
		OrbSources.Clear();
		for (int i = 0; i < OrbParts.Length; i++)
		{
			OrbSources.Add(byName.TryGetValue(OrbParts[i][0], out var value) ? value : null);
		}
		if (!byName.TryGetValue(ProjectileName, out var value2) || (Object)(object)value2 == (Object)null || (Object)(object)value2.GetComponent<Projectile>() == (Object)null)
		{
			throw new InvalidOperationException("vanilla projectile " + ProjectileName + " not found");
		}
		Projectile = value2;
		Projectile component = value2.GetComponent<Projectile>();
		Gravity = Mathf.Max(0f, component.m_gravity);
		RayRadius = Mathf.Max(0f, component.m_rayRadius);
	}
}
internal static class Tuning
{
	internal sealed class Values
	{
		internal float Range = 30f;

		internal bool Wild;

		internal bool SpareTaming = true;

		internal float Cost = 150f;

		internal float[] Damage = new float[SentinelsPlugin.Elements.Length];

		internal float[] Physical = new float[SentinelsPlugin.Elements.Length];

		internal float[] Cooldown = new float[SentinelsPlugin.Elements.Length];

		internal int[] Shots = new int[SentinelsPlugin.Elements.Length];

		internal float[] Spread = new float[SentinelsPlugin.Elements.Length];

		internal bool[] Offer = new bool[SentinelsPlugin.Elements.Length];

		internal bool Armed;
	}

	private const string RpcRequest = "danpe_Sentinels_ConfigRequest";

	private const string RpcConfig = "danpe_Sentinels_Config";

	private const int Version = 2;

	private static Values _local;

	private static Values _host;

	private static ZRoutedRpc _registeredOn;

	private static float _nextRequest;

	private static bool _broadcast;

	private static Values _menuValues;

	private static bool _menuAllowed = true;

	internal static Values Current
	{
		get
		{
			if (_host != null && (Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer())
			{
				return _host;
			}
			if (_local == null)
			{
				_local = FromConfig();
			}
			return _local;
		}
	}

	internal static void LocalChanged()
	{
		_local = null;
		_broadcast = true;
	}

	private static Values FromConfig()
	{
		Values values = new Values();
		values.Range = ((SentinelsPlugin.Range != null) ? SentinelsPlugin.Range.Value : 30f);
		values.Wild = SentinelsPlugin.ShootWildlife != null && SentinelsPlugin.ShootWildlife.Value;
		values.SpareTaming = SentinelsPlugin.SpareTaming == null || SentinelsPlugin.SpareTaming.Value;
		values.Cost = ((SentinelsPlugin.EnergyCost != null) ? SentinelsPlugin.EnergyCost.Value : 150f);
		for (int i = 0; i < SentinelsPlugin.Elements.Length; i++)
		{
			Element element = SentinelsPlugin.Elements[i];
			values.Damage[i] = ((element.Damage != null) ? element.Damage.Value : element.DefaultDamage);
			values.Physical[i] = ((element.Physical != null) ? element.Physical.Value : element.DefaultPhysical);
			values.Cooldown[i] = ((element.Cooldown != null) ? element.Cooldown.Value : element.DefaultCooldown);
			values.Shots[i] = ((element.Shots != null) ? element.Shots.Value : element.DefaultShots);
			values.Spread[i] = ((element.Spread != null) ? element.Spread.Value : element.DefaultSpread);
			values.Offer[i] = element.Enabled == null || element.Enabled.Value;
		}
		return Sanitize(values);
	}

	private static Values Sanitize(Values v)
	{
		v.Range = Mathf.Clamp(v.Range, 10f, 60f);
		v.Cost = Mathf.Clamp(v.Cost, 0f, 1000f);
		for (int i = 0; i < v.Damage.Length; i++)
		{
			v.Damage[i] = Mathf.Clamp(v.Damage[i], 0f, 1000f);
			v.Physical[i] = Mathf.Clamp(v.Physical[i], 0f, 1000f);
			v.Cooldown[i] = Mathf.Clamp(v.Cooldown[i], 0.5f, 30f);
			v.Shots[i] = Mathf.Clamp(v.Shots[i], 1, 12);
			v.Spread[i] = Mathf.Clamp(v.Spread[i], 0f, 10f);
		}
		return v;
	}

	private static ZPackage Pack(Values v)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		ZPackage val = new ZPackage();
		val.Write(2);
		val.Write(v.Damage.Length);
		val.Write(SentinelsPlugin.Armed);
		val.Write(v.Range);
		val.Write(v.Wild);
		val.Write(v.SpareTaming);
		val.Write(v.Cost);
		for (int i = 0; i < v.Damage.Length; i++)
		{
			val.Write(v.Damage[i]);
			val.Write(v.Physical[i]);
			val.Write(v.Cooldown[i]);
			val.Write(v.Shots[i]);
			val.Write(v.Spread[i]);
			val.Write(v.Offer[i]);
		}
		return val;
	}

	private static Values Unpack(ZPackage pkg)
	{
		if (pkg.ReadInt() != 2 || pkg.ReadInt() != SentinelsPlugin.Elements.Length)
		{
			return null;
		}
		Values values = new Values();
		values.Armed = pkg.ReadBool();
		values.Range = pkg.ReadSingle();
		values.Wild = pkg.ReadBool();
		values.SpareTaming = pkg.ReadBool();
		values.Cost = pkg.ReadSingle();
		for (int i = 0; i < values.Damage.Length; i++)
		{
			values.Damage[i] = pkg.ReadSingle();
			values.Physical[i] = pkg.ReadSingle();
			values.Cooldown[i] = pkg.ReadSingle();
			values.Shots[i] = pkg.ReadInt();
			values.Spread[i] = pkg.ReadSingle();
			values.Offer[i] = pkg.ReadBool();
		}
		return Sanitize(values);
	}

	internal static bool HostAllows()
	{
		if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer())
		{
			return true;
		}
		if (_host != null)
		{
			return _host.Armed;
		}
		return false;
	}

	internal static void Tick()
	{
		Values current = Current;
		bool flag = HostAllows();
		if (!object.ReferenceEquals(current, _menuValues) || flag != _menuAllowed)
		{
			_menuValues = current;
			_menuAllowed = flag;
			SentinelsPlugin.TryFinishPieceSetup();
		}
		ZRoutedRpc instance = ZRoutedRpc.instance;
		if (instance == null || (Object)(object)ZNet.instance == (Object)null)
		{
			_host = null;
			return;
		}
		if (!object.ReferenceEquals(instance, _registeredOn))
		{
			_registeredOn = instance;
			_host = null;
			_nextRequest = 0f;
			instance.Register("danpe_Sentinels_ConfigRequest", (Action<long>)OnRequest);
			instance.Register<ZPackage>("danpe_Sentinels_Config", (Action<long, ZPackage>)OnConfig);
		}
		if (ZNet.instance.IsServer())
		{
			if (_broadcast)
			{
				_broadcast = false;
				instance.InvokeRoutedRPC(0L, "danpe_Sentinels_Config", new object[1] { Pack(Current) });
			}
		}
		else if (_host == null && SentinelsPlugin.Armed && (Object)(object)Player.m_localPlayer != (Object)null && Time.time >= _nextRequest)
		{
			_nextRequest = Time.time + 30f;
			instance.InvokeRoutedRPC("danpe_Sentinels_ConfigRequest", new object[0]);
		}
	}

	private static void OnRequest(long sender)
	{
		if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && ZRoutedRpc.instance != null)
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(sender, "danpe_Sentinels_Config", new object[1] { Pack(Current) });
		}
	}

	private static void OnConfig(long sender, ZPackage pkg)
	{
		ZNetPeer val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetServerPeer() : null);
		if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer() || val == null || sender != val.m_uid)
		{
			return;
		}
		try
		{
			Values values = Unpack(pkg);
			if (values != null)
			{
				_host = values;
				SentinelsPlugin.Log.LogInfo((object)(values.Armed ? "Using the host's sentinel settings." : "The host has Sentinel Stones switched off or unavailable: sentinels here stay inert."));
			}
		}
		catch (Exception ex)
		{
			SentinelsPlugin.Log.LogWarning((object)("Could not read the host's sentinel settings: " + ex.Message));
		}
	}
}
internal static class Prefabs
{
	internal const float StoneScale = 0.7f;

	internal const float OrbHeight = 2.6f;

	internal static GameObject Build(GameObject stone, Element el, int index, Texture stave, Transform container)
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Expected O, but got Unknown
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Expected O, but got Unknown
		//IL_0113: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		//IL_013a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0141: Expected O, but got Unknown
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_019f: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Object.Instantiate<GameObject>(stone, container, false);
		((Object)val).name = el.PrefabName;
		for (int i = 0; i < val.transform.childCount; i++)
		{
			Transform child = val.transform.GetChild(i);
			child.localScale *= 0.7f;
			child.localPosition *= 0.7f;
		}
		Piece component = val.GetComponent<Piece>();
		component.m_enabled = false;
		component.m_resources = (Requirement[])(object)new Requirement[0];
		component.m_craftingStation = null;
		component.m_notOnWood = false;
		component.m_name = "Rune of the Sentinel: " + el.Title;
		GameObject val2 = new GameObject("OrbPivot");
		val2.transform.SetParent(val.transform, false);
		val2.transform.localPosition = new Vector3(0f, 2.6f, 0f);
		GameObject val3 = new GameObject("Orb");
		val3.transform.SetParent(val2.transform, false);
		if (!Application.isBatchMode)
		{
			val3.transform.localScale = Vector3.one * el.OrbScale;
			BuildOrb(el, val3.transform);
			GameObject val4 = new GameObject("SentinelLight");
			val4.transform.SetParent(val2.transform, false);
			Light val5 = val4.AddComponent<Light>();
			val5.type = (LightType)2;
			val5.color = el.LightColor;
			val5.range = 6f;
			val5.intensity = 2.5f;
			val5.shadows = (LightShadows)0;
			if ((Object)(object)stave != (Object)null)
			{
				ApplyStave(val, stave, el.StaveColor);
			}
		}
		RuneTurret runeTurret = val.AddComponent<RuneTurret>();
		runeTurret.ElementIndex = index;
		return val;
	}

	internal static GameObject Placeholder(Element el, Transform container)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		GameObject val = new GameObject(el.PrefabName);
		val.transform.SetParent(container, false);
		ZNetView val2 = val.AddComponent<ZNetView>();
		val2.m_persistent = true;
		return val;
	}

	internal static void ConfigurePiece(Element el, Sprite stoneIcon, int category)
	{
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		Piece component = el.Prefab.GetComponent<Piece>();
		component.m_name = "Rune of the Sentinel: " + el.Title;
		component.m_description = "Raises a sentinel stone that " + el.Blurb + " Players, tames and your buildings are never harmed.";
		component.m_category = (PieceCategory)category;
		Sprite front = null;
		GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(el.IconItem) : null);
		ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null);
		if ((Object)(object)val2 != (Object)null && val2.m_itemData != null)
		{
			try
			{
				front = val2.m_itemData.GetIcon();
			}
			catch (Exception)
			{
			}
		}
		Sprite val3 = Icon.Compose(stoneIcon, front);
		if ((Object)(object)val3 != (Object)null)
		{
			component.m_icon = val3;
		}
		component.m_enabled = true;
	}

	private static void ApplyStave(GameObject clone, Texture stave, Color hdr)
	{
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Expected O, but got Unknown
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Transform val = clone.transform.Find("StandingStone");
			MeshRenderer val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<MeshRenderer>() : null);
			if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Renderer)val2).sharedMaterial == (Object)null) && ((Renderer)val2).sharedMaterial.HasProperty("_EmissionColor") && ((Renderer)val2).sharedMaterial.HasProperty("_EmissionMap"))
			{
				Material val3 = new Material(((Renderer)val2).sharedMaterial);
				((Object)val3).name = "Sentinel_" + ((Object)clone).name;
				val3.SetTexture("_EmissionMap", stave);
				val3.SetColor("_EmissionColor", hdr);
				val3.EnableKeyword("_EMISSION");
				((Renderer)val2).sharedMaterial = val3;
			}
		}
		catch (Exception ex)
		{
			SentinelsPlugin.Log.LogWarning((object)("Could not light the " + ((Object)clone).name + " stave: " + ex.Message));
		}
	}

	private static void BuildOrb(Element el, Transform orb)
	{
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		int num = 0;
		for (int i = 0; i < el.OrbParts.Length; i++)
		{
			GameObject val = ((i < el.OrbSources.Count) ? el.OrbSources[i] : null);
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			for (int j = 1; j < el.OrbParts[i].Length; j++)
			{
				string text = el.OrbParts[i][j];
				Transform val2 = val.transform.Find(text);
				if (!((Object)(object)val2 == (Object)null) && ((Component)val2).gameObject.activeSelf)
				{
					GameObject val3 = Object.Instantiate<GameObject>(((Component)val2).gameObject, orb, false);
					((Object)val3).name = text;
					val3.transform.localPosition = val2.localPosition;
					val3.transform.localRotation = val2.localRotation;
					StripVisual(val3);
					num++;
				}
			}
		}
		if (num == 0)
		{
			SentinelsPlugin.Log.LogWarning((object)("The " + el.Title + " sentinel's orb has no visuals; it will show only its light."));
		}
	}

	private static void StripVisual(GameObject go)
	{
		//IL_009b: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		for (int i = 0; i < 6; i++)
		{
			bool flag = false;
			Component[] componentsInChildren = go.GetComponentsInChildren<Component>(true);
			Component[] array = componentsInChildren;
			foreach (Component val in array)
			{
				if (!((Object)(object)val == (Object)null) && !(val is Transform) && !(val is MeshFilter) && !(val is MeshRenderer) && !(val is ParticleSystem) && !(val is ParticleSystemRenderer) && !(val is LODGroup))
				{
					try
					{
						Object.DestroyImmediate((Object)(object)val);
					}
					catch (Exception)
					{
					}
					if ((Object)(object)val != (Object)null)
					{
						flag = true;
					}
				}
			}
			if (!flag)
			{
				break;
			}
		}
		ParticleSystem[] componentsInChildren2 = go.GetComponentsInChildren<ParticleSystem>(true);
		foreach (ParticleSystem val2 in componentsInChildren2)
		{
			MainModule main = val2.main;
			EmissionModule emission = val2.emission;
			bool flag2 = ((EmissionModule)(ref emission)).rateOverTimeMultiplier <= 0f;
			if (!((MainModule)(ref main)).loop || flag2)
			{
				((EmissionModule)(ref emission)).enabled = false;
			}
			else
			{
				((MainModule)(ref main)).scalingMode = (ParticleSystemScalingMode)0;
			}
		}
		Renderer[] componentsInChildren3 = go.GetComponentsInChildren<Renderer>(true);
		foreach (Renderer val3 in componentsInChildren3)
		{
			val3.shadowCastingMode = (ShadowCastingMode)0;
		}
	}
}
internal static class Hostility
{
	private const int FactionPlayers = 0;

	private const int FactionDverger = 10;

	private const int FactionPlayerSpawned = 11;

	internal static bool IsHostile(Character c)
	{
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Expected I4, but got Unknown
		if ((Object)(object)c == (Object)null || c.IsDead() || c.IsPlayer() || c.IsTamed())
		{
			return false;
		}
		if (c.m_aiSkipTarget || (Object)(object)((Component)c).GetComponent<Piece>() != (Object)null)
		{
			return false;
		}
		int num = (int)c.GetFaction();
		if (num == 0 || num == 11)
		{
			return false;
		}
		BaseAI baseAI = c.GetBaseAI();
		if (num == 10 && ((Object)(object)baseAI == (Object)null || !baseAI.IsAggravated()))
		{
			return false;
		}
		Tuning.Values current = Tuning.Current;
		if (baseAI is AnimalAI && !current.Wild)
		{
			return false;
		}
		if (current.SpareTaming && BeingTamed(c))
		{
			return false;
		}
		return true;
	}

	private static bool BeingTamed(Character c)
	{
		Tameable component = ((Component)c).GetComponent<Tameable>();
		if ((Object)(object)component == (Object)null)
		{
			return false;
		}
		ZNetView component2 = ((Component)c).GetComponent<ZNetView>();
		if ((Object)(object)component2 == (Object)null || !component2.IsValid())
		{
			return false;
		}
		if (!component.IsHungry())
		{
			return component2.GetZDO().GetFloat(ZDOVars.s_tameTimeLeft, component.m_tamingTime) < component.m_tamingTime;
		}
		return false;
	}

	internal static bool AllowHit(object target)
	{
		if (target == null)
		{
			return true;
		}
		Character val = (Character)((target is Character) ? target : null);
		if ((Object)(object)val != (Object)null)
		{
			return IsHostile(val);
		}
		Component val2 = (Component)((target is Component) ? target : null);
		if ((Object)(object)val2 == (Object)null)
		{
			return true;
		}
		if ((Object)(object)val2.GetComponentInParent<RuneTurret>() != (Object)null || (Object)(object)val2.GetComponentInParent<WearNTear>() != (Object)null || (Object)(object)val2.GetComponentInParent<Plant>() != (Object)null || (Object)(object)val2.GetComponentInParent<Pickable>() != (Object)null)
		{
			return false;
		}
		Piece componentInParent = val2.GetComponentInParent<Piece>();
		if ((Object)(object)componentInParent != (Object)null && componentInParent.IsPlacedByPlayer())
		{
			return false;
		}
		Character componentInParent2 = val2.GetComponentInParent<Character>();
		if (!((Object)(object)componentInParent2 == (Object)null))
		{
			return IsHostile(componentInParent2);
		}
		return true;
	}
}
internal static class Shot
{
	internal const HitType Marker = (HitType)150;

	internal static readonly ItemData Tag = MakeTag();

	private static ItemData MakeTag()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Expected O, but got Unknown
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Expected O, but got Unknown
		ItemData val = new ItemData();
		val.m_shared = new SharedData();
		val.m_shared.m_name = "$danpe_sentinel_shot";
		val.m_shared.m_attack = new Attack();
		val.m_shared.m_secondaryAttack = new Attack();
		return val;
	}
}
public class RuneTurret : MonoBehaviour
{
	private const string RpcTarget = "danpe_Sentinel_Target";

	public int ElementIndex;

	private static int _sightMask = -1;

	private static float _nextErrorLog;

	private ZNetView _nview;

	private Element _el;

	private Transform _pivot;

	private Transform _orb;

	private Light _light;

	private float _lightBase = 2.5f;

	private Character _target;

	private float _retarget;

	private bool _ghost;

	private float _phase;

	private float _idleYaw;

	private void Awake()
	{
		_ghost = ZNetView.m_forceDisableInit;
		_el = ((ElementIndex >= 0 && ElementIndex < SentinelsPlugin.Elements.Length) ? SentinelsPlugin.Elements[ElementIndex] : null);
		_pivot = ((Component)this).transform.Find("OrbPivot");
		_orb = (((Object)(object)_pivot != (Object)null) ? _pivot.Find("Orb") : null);
		Transform val = (((Object)(object)_pivot != (Object)null) ? _pivot.Find("SentinelLight") : null);
		_light = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<Light>() : null);
		if ((Object)(object)_light != (Object)null)
		{
			_lightBase = _light.intensity;
		}
		_phase = Random.Range(0f, 10f);
		_idleYaw = Random.Range(0f, 360f);
		if (!_ghost)
		{
			_nview = ((Component)this).GetComponent<ZNetView>();
			if (!((Object)(object)_nview == (Object)null) && _nview.GetZDO() != null)
			{
				_nview.Register<ZDOID>("danpe_Sentinel_Target", (Action<long, ZDOID>)RPC_Target);
				_retarget = Random.Range(0f, 1f);
			}
		}
	}

	private Vector3 Eye()
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)_pivot != (Object)null))
		{
			return ((Component)this).transform.position + Vector3.up * 2.6f;
		}
		return _pivot.position;
	}

	private void FixedUpdate()
	{
		if (_ghost || !SentinelsPlugin.Armed || _el == null || _el.Failed || (Object)(object)_el.Projectile == (Object)null || (Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner() || (Object)(object)ZNet.instance == (Object)null || !Tuning.HostAllows())
		{
			return;
		}
		try
		{
			Tuning.Values current = Tuning.Current;
			UpdateTarget(Time.fixedDeltaTime, current);
			TryShoot(current);
		}
		catch (Exception ex)
		{
			_retarget = 5f;
			if (Time.time >= _nextErrorLog)
			{
				_nextErrorLog = Time.time + 60f;
				SentinelsPlugin.Log.LogWarning((object)("Sentinel error: " + ex));
			}
		}
	}

	private void Update()
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: 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_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
		float num = Time.time + _phase;
		if ((Object)(object)_orb != (Object)null)
		{
			_orb.localPosition = new Vector3(0f, Mathf.Sin(num * 1.8f) * 0.08f, 0f);
		}
		if ((Object)(object)_pivot != (Object)null)
		{
			Character target = _target;
			Quaternion val2;
			if ((Object)(object)target != (Object)null && !target.IsDead())
			{
				Vector3 val = target.GetCenterPoint() - _pivot.position;
				val2 = ((((Vector3)(ref val)).sqrMagnitude > 0.01f) ? Quaternion.LookRotation(val) : _pivot.rotation);
			}
			else
			{
				_idleYaw += 25f * Time.deltaTime;
				val2 = Quaternion.Euler(0f, _idleYaw, 0f);
			}
			_pivot.rotation = Quaternion.RotateTowards(_pivot.rotation, val2, 270f * Time.deltaTime);
		}
		if ((Object)(object)_light != (Object)null && _el != null && _el.Flicker)
		{
			_light.intensity = _lightBase * (0.55f + 0.9f * Mathf.PerlinNoise(num * 9f, _phase));
		}
	}

	private void RPC_Target(long sender, ZDOID id)
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		if (((ZDOID)(ref id)).IsNone() || (Object)(object)ZNetScene.instance == (Object)null)
		{
			_target = null;
			return;
		}
		GameObject val = ZNetScene.instance.FindInstance(id);
		_target = (((Object)(object)val != (Object)null) ? val.GetComponent<Character>() : null);
	}

	private void SetTarget(Character c)
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		_target = c;
		_nview.InvokeRPC(ZNetView.Everybody, "danpe_Sentinel_Target", new object[1] { ((Object)(object)c != (Object)null) ? c.GetZDOID() : ZDOID.None });
	}

	private void UpdateTarget(float dt, Tuning.Values v)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = Eye();
		float range = v.Range;
		if ((Object)(object)_target != (Object)null && (!Hostility.IsHostile(_target) || Vector3.Distance(val, _target.GetCenterPoint()) > range + 2f))
		{
			SetTarget(null);
		}
		_retarget -= dt;
		if (_retarget > 0f)
		{
			return;
		}
		_retarget = (Character.IsCharacterInRange(((Component)this).transform.position, 40f) ? 1f : 4f);
		Character val2 = null;
		float num = float.MaxValue;
		List<Character> allCharacters = Character.GetAllCharacters();
		for (int i = 0; i < allCharacters.Count; i++)
		{
			Character val3 = allCharacters[i];
			if (!Hostility.IsHostile(val3))
			{
				continue;
			}
			float num2 = Vector3.Distance(val, val3.GetCenterPoint());
			if (!(num2 > range) && !(num2 >= num))
			{
				BaseAI baseAI = val3.GetBaseAI();
				if ((!((Object)(object)baseAI != (Object)null) || !baseAI.IsSleeping()) && CanSee(val, val3))
				{
					val2 = val3;
					num = num2;
				}
			}
		}
		if ((Object)(object)val2 != (Object)(object)_target)
		{
			SetTarget(val2);
		}
	}

	private bool CanSee(Vector3 eye, Character c)
	{
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		if (_sightMask < 0)
		{
			_sightMask = LayerMask.GetMask(new string[7] { "Default", "static_solid", "Default_small", "piece", "terrain", "viewblock", "vehicle" });
		}
		Vector3 val = c.GetCenterPoint() - eye;
		float magnitude = ((Vector3)(ref val)).magnitude;
		if (magnitude < 0.05f)
		{
			return true;
		}
		RaycastHit[] array = Physics.RaycastAll(eye, val / magnitude, magnitude, _sightMask, (QueryTriggerInteraction)1);
		for (int i = 0; i < array.Length; i++)
		{
			Collider collider = ((RaycastHit)(ref array[i])).collider;
			if (!((Object)(object)collider == (Object)null) && !((Component)collider).transform.IsChildOf(((Component)this).transform) && !((Object)(object)((Component)collider).GetComponentInParent<Character>() == (Object)(object)c) && Hostility.AllowHit(collider))
			{
				return false;
			}
		}
		return true;
	}

	private void TryShoot(Tuning.Values v)
	{
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: 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_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: 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)
		//IL_016d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: 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_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_013a: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0161: Unknown result type (might be due to invalid IL or missing references)
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		Character target = _target;
		if ((Object)(object)target == (Object)null || !Hostility.IsHostile(target))
		{
			return;
		}
		int elementIndex = ElementIndex;
		ZDO zDO = _nview.GetZDO();
		double timeSeconds = ZNet.instance.GetTimeSeconds();
		float num = zDO.GetFloat(ZDOVars.s_lastAttack, 0f);
		if ((double)(num + v.Cooldown[elementIndex]) > timeSeconds && (double)num <= timeSeconds + 1.0)
		{
			return;
		}
		zDO.Set(ZDOVars.s_lastAttack, (float)timeSeconds);
		Vector3 val = Eye();
		Vector3 val2 = Aim(val, target);
		int num2 = v.Shots[elementIndex];
		float num3 = Vector3.Distance(val, target.GetCenterPoint());
		float num4 = ((num3 > 0.5f) ? Mathf.Min(v.Spread[elementIndex], Mathf.Atan2(0.35f, num3) * 57.29578f) : v.Spread[elementIndex]);
		DamageTypes damage = _el.DamageTypes(v.Damage[elementIndex], v.Physical[elementIndex]);
		for (int i = 0; i < num2; i++)
		{
			Vector3 val3 = val2;
			if (num4 > 0.01f)
			{
				Vector3 val4 = Vector3.Cross(Vector3.up, val3);
				if (((Vector3)(ref val4)).sqrMagnitude < 0.0001f)
				{
					val4 = Vector3.right;
				}
				val3 = Quaternion.AngleAxis(Random.Range(0f - num4, num4), Vector3.up) * (Quaternion.AngleAxis(Random.Range(0f - num4, num4), ((Vector3)(ref val4)).normalized) * val3);
			}
			Fire(val, ((Vector3)(ref val3)).normalized, damage, v.Range);
		}
	}

	private Vector3 Aim(Vector3 eye, Character target)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: 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_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		Vector3 centerPoint = target.GetCenterPoint();
		Vector3 velocity = target.GetVelocity();
		if (!target.IsFlying())
		{
			Vector3 val = new Vector3(velocity.x, 0f, velocity.z);
			float magnitude = ((Vector3)(ref val)).magnitude;
			velocity.y = Mathf.Clamp(velocity.y, 0f - magnitude, magnitude);
		}
		float speed = _el.Speed;
		float gravity = _el.Gravity;
		Vector3 val2 = centerPoint;
		Vector3 val3 = val2 - eye;
		Vector3 dir = ((Vector3)(ref val3)).normalized;
		for (int i = 0; i < 3; i++)
		{
			if (!Solve(eye, val2, speed, gravity, out dir, out var t))
			{
				t = Vector3.Distance(eye, val2) / speed;
			}
			val2 = centerPoint + velocity * t;
		}
		Solve(eye, val2, speed, gravity, out dir, out var _);
		return dir;
	}

	private static bool Solve(Vector3 eye, Vector3 point, float v, float g, out Vector3 dir, out float t)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: 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)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: 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)
		Vector3 val = point - eye;
		Vector3 val2 = default(Vector3);
		((Vector3)(ref val2))..ctor(val.x, 0f, val.z);
		float magnitude = ((Vector3)(ref val2)).magnitude;
		if (g < 0.001f || magnitude < 0.05f)
		{
			dir = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val)).normalized : Vector3.forward);
			t = ((Vector3)(ref val)).magnitude / v;
			return true;
		}
		float y = val.y;
		float num = v * v;
		float num2 = num * num - g * (g * magnitude * magnitude + 2f * y * num);
		Vector3 val3 = val2 / magnitude;
		if (num2 < 0f)
		{
			Vector3 val4 = val3 + Vector3.up;
			dir = ((Vector3)(ref val4)).normalized;
			t = magnitude / (v * 0.7071f);
			return false;
		}
		float num3 = Mathf.Atan((num - Mathf.Sqrt(num2)) / (g * magnitude));
		dir = val3 * Mathf.Cos(num3) + Vector3.up * Mathf.Sin(num3);
		t = magnitude / Mathf.Max(0.01f, v * Mathf.Cos(num3));
		return true;
	}

	private void Fire(Vector3 eye, Vector3 dir, DamageTypes damage, float range)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: 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)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Expected O, but got Unknown
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0117: 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_0156: 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)
		float speed = _el.Speed;
		Vector3 val = eye + dir * (0.5f * speed * Time.fixedDeltaTime + Mathf.Min(_el.RayRadius, 0.25f));
		GameObject val2 = Object.Instantiate<GameObject>(_el.Projectile, val, Quaternion.LookRotation(dir));
		Projectile component = val2.GetComponent<Projectile>();
		if ((Object)(object)component != (Object)null)
		{
			component.m_onHit = null;
			component.m_spawnOnHit = null;
			component.m_randomSpawnOnHit = new List<GameObject>();
			component.m_spawnOnTtl = false;
			component.m_respawnItemOnHit = false;
			component.m_aoeSkipWearNTear = true;
			component.m_noDamageFriendly = false;
			component.m_rayRadius = Mathf.Min(component.m_rayRadius, 0.25f);
			component.m_ttl = Mathf.Max(component.m_ttl, range / speed + 1f);
		}
		IProjectile component2 = val2.GetComponent<IProjectile>();
		if (component2 == null)
		{
			Object.Destroy((Object)(object)val2);
			return;
		}
		HitData val3 = new HitData();
		val3.m_damage = damage;
		val3.m_pushForce = 10f;
		val3.m_backstabBonus = 1f;
		val3.m_blockable = true;
		val3.m_dodgeable = true;
		val3.m_skill = (SkillType)0;
		val3.m_hitType = (HitType)150;
		val3.m_statusEffectHash = (((Object)(object)component != (Object)null && !string.IsNullOrEmpty(component.m_statusEffect)) ? StringExtensionMethods.GetStableHashCode(component.m_statusEffect) : 0);
		try
		{
			component2.Setup((Character)null, dir * speed, 0f, val3, (ItemData)null, Shot.Tag);
		}
		catch (Exception ex)
		{
			if (!((Object)(object)component != (Object)null) || Patches.ProjectileAmmo == null || !object.ReferenceEquals(Patches.ProjectileAmmo(component), Shot.Tag))
			{
				if ((Object)(object)ZNetScene.instance != (Object)null)
				{
					ZNetScene.instance.Destroy(val2);
				}
				else
				{
					Object.Destroy((Object)(object)val2);
				}
			}
			if (Time.time >= _nextErrorLog)
			{
				_nextErrorLog = Time.time + 60f;
				SentinelsPlugin.Log.LogWarning((object)("Another mod failed while a sentinel shot was set up (the volley goes on): " + ex.Message));
			}
		}
	}
}
public static class Patches
{
	internal static Func<Projectile, ItemData> ProjectileAmmo;

	public static void IsUnlockablePostfix(Piece piece, ref bool __result)
	{
		if (!__result && SentinelsPlugin.IndexFor(piece) >= 0)
		{
			__result = true;
		}
	}

	public static void IsUnlockedPostfix(Piece piece, ref bool __result)
	{
		if (SentinelsPlugin.IndexFor(piece) >= 0)
		{
			__result = true;
		}
	}

	public static void EnergyCostPostfix(Piece piece, ref float __result)
	{
		if (SentinelsPlugin.IndexFor(piece) >= 0)
		{
			__result = Tuning.Current.Cost;
		}
	}

	public static bool ValidTargetPrefix(IDestructible destr, ItemData ___m_ammo, ref bool __result)
	{
		if (!object.ReferenceEquals(___m_ammo, Shot.Tag))
		{
			return true;
		}
		try
		{
			if (!Hostility.AllowHit(destr))
			{
				__result = false;
				return false;
			}
		}
		catch (Exception)
		{
			__result = false;
			return false;
		}
		return true;
	}

	public static bool ShouldHitPrefix(Collider collider, ItemData ___m_ammo, ref bool __result)
	{
		if (!object.ReferenceEquals(___m_ammo, Shot.Tag))
		{
			return true;
		}
		try
		{
			GameObject val = (((Object)(object)collider != (Object)null) ? Projectile.FindHitObject(collider) : null);
			if ((Object)(object)val != (Object)null)
			{
				Character component = val.GetComponent<Character>();
				object target = (((Object)(object)component != (Object)null) ? ((object)component) : ((object)val.transform));
				if (!Hostility.AllowHit(target))
				{
					__result = false;
					return false;
				}
			}
		}
		catch (Exception)
		{
			__result = false;
			return false;
		}
		return true;
	}

	public static bool CharacterDamagePrefix(Character __instance, HitData hit)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Invalid comparison between Unknown and I4
		if (hit != null && (int)hit.m_hitType == 150 && !Hostility.IsHostile(__instance))
		{
			return false;
		}
		return true;
	}

	public static bool WearNTearDamagePrefix(HitData hit)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Invalid comparison between Unknown and I4
		if (hit != null)
		{
			return (int)hit.m_hitType != 150;
		}
		return true;
	}

	public static bool ShieldCheckPrefix(Projectile projectile)
	{
		try
		{
			return (Object)(object)projectile == (Object)null || ProjectileAmmo == null || !object.ReferenceEquals(ProjectileAmmo(projectile), Shot.Tag);
		}
		catch (Exception)
		{
			return true;
		}
	}

	public static void ZNetSceneAwakePrefix(ZNetScene __instance)
	{
		try
		{
			SentinelsPlugin.OnZNetSceneAwake(__instance);
		}
		catch (Exception ex)
		{
			SentinelsPlugin.Log.LogError((object)("The sentinels could not be prepared for this world: " + ex));
		}
	}

	public static void BoulderSetupPostfix()
	{
		try
		{
			SentinelsPlugin.TryFinishPieceSetup();
		}
		catch (Exception ex)
		{
			SentinelsPlugin.Log.LogError((object)("The sentinels could not be added to the menu: " + ex));
		}
	}
}
internal static class Icon
{
	private const int Size = 128;

	internal static Sprite Compose(Sprite back, Sprite front)
	{
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Expected O, but got Unknown
		//IL_00e5: 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)
		if ((Object)(object)back == (Object)null || (Object)(object)back.texture == (Object)null || Application.isBatchMode)
		{
			if (!((Object)(object)front != (Object)null))
			{
				return back;
			}
			return front;
		}
		try
		{
			int width;
			int height;
			Color[] src = ReadSprite(back, out width, out height);
			Color[] array = (Color[])(object)new Color[16384];
			Stamp(array, src, width, height, 51.2f, 71.68f, 107.52f);
			if ((Object)(object)front != (Object)null && (Object)(object)front.texture != (Object)null)
			{
				int width2;
				int height2;
				Color[] src2 = ReadSprite(front, out width2, out height2);
				Stamp(array, src2, width2, height2, 92.16f, 38.4f, 74.24f);
			}
			Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false);
			((Object)val).name = "SentinelIcon";
			((Texture)val).wrapMode = (TextureWrapMode)1;
			val.SetPixels(array);
			val.Apply(false, false);
			return Sprite.Create(val, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f), 100f);
		}
		catch (Exception ex)
		{
			SentinelsPlugin.Log.LogWarning((object)("Could not draw a sentinel icon: " + ex.Message));
			return ((Object)(object)front != (Object)null) ? front : back;
		}
	}

	private static Color[] ReadSprite(Sprite sprite, out int width, out int height)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Expected O, but got Unknown
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		Texture texture = (Texture)(object)sprite.texture;
		Rect textureRect = sprite.textureRect;
		width = Mathf.Max(1, Mathf.RoundToInt(((Rect)(ref textureRect)).width));
		height = Mathf.Max(1, Mathf.RoundToInt(((Rect)(ref textureRect)).height));
		RenderTexture temporary = RenderTexture.GetTemporary(texture.width, texture.height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
		RenderTexture active = RenderTexture.active;
		Texture2D val = null;
		try
		{
			Graphics.Blit(texture, temporary);
			RenderTexture.active = temporary;
			val = new Texture2D(width, height, (TextureFormat)4, false);
			val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)width, (float)height), 0, 0);
			val.Apply();
			return val.GetPixels();
		}
		finally
		{
			RenderTexture.active = active;
			RenderTexture.ReleaseTemporary(temporary);
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)val);
			}
		}
	}

	private static void Stamp(Color[] dst, Color[] src, int sw, int sh, float cx, float cy, float target)
	{
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
		float num = (float)sw / (float)sh;
		float num2 = ((num >= 1f) ? target : (target * num));
		float num3 = ((num >= 1f) ? (target / num) : target);
		float num4 = cx - num2 / 2f;
		float num5 = cy - num3 / 2f;
		int num6 = Mathf.Max(0, Mathf.FloorToInt(num4));
		int num7 = Mathf.Min(128, Mathf.CeilToInt(num4 + num2));
		int num8 = Mathf.Max(0, Mathf.FloorToInt(num5));
		int num9 = Mathf.Min(128, Mathf.CeilToInt(num5 + num3));
		for (int i = num8; i < num9; i++)
		{
			float num10 = ((float)i + 0.5f - num5) / num3;
			if (num10 < 0f || num10 >= 1f)
			{
				continue;
			}
			for (int j = num6; j < num7; j++)
			{
				float num11 = ((float)j + 0.5f - num4) / num2;
				if (num11 < 0f || num11 >= 1f)
				{
					continue;
				}
				Color val = Sample(src, sw, sh, num11, num10);
				if (!(val.a <= 0f))
				{
					int num12 = i * 128 + j;
					Color val2 = dst[num12];
					float num13 = val.a + val2.a * (1f - val.a);
					if (!(num13 <= 0f))
					{
						ref Color reference = ref dst[num12];
						reference = new Color((val.r * val.a + val2.r * val2.a * (1f - val.a)) / num13, (val.g * val.a + val2.g * val2.a * (1f - val.a)) / num13, (val.b * val.a + val2.b * val2.a * (1f - val.a)) / num13, num13);
					}
				}
			}
		}
	}

	private static Color Sample(Color[] src, int sw, int sh, float u, float v)
	{
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: 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_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		float num = u * (float)sw - 0.5f;
		float num2 = v * (float)sh - 0.5f;
		int num3 = Mathf.Clamp(Mathf.FloorToInt(num), 0, sw - 1);
		int num4 = Mathf.Clamp(Mathf.FloorToInt(num2), 0, sh - 1);
		int num5 = Mathf.Min(num3 + 1, sw - 1);
		int num6 = Mathf.Min(num4 + 1, sh - 1);
		float num7 = Mathf.Clamp01(num - (float)num3);
		float num8 = Mathf.Clamp01(num2 - (float)num4);
		Color val = Color.Lerp(src[num4 * sw + num3], src[num4 * sw + num5], num7);
		Color val2 = Color.Lerp(src[num6 * sw + num3], src[num6 * sw + num5], num7);
		return Color.Lerp(val, val2, num8);
	}
}

plugins/Waygate.dll

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

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

[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("danpe.RuneMagicWaygate", "Rune Magic - Waygate", "1.0.1")]
public class WaygatePlugin : BaseUnityPlugin
{
	public enum Side
	{
		Right,
		Left
	}

	public const string PluginGuid = "danpe.RuneMagicWaygate";

	public const string PluginName = "Rune Magic - Waygate";

	public const string PluginVersion = "1.0.1";

	internal const string RuneMagicGuid = "hyleanlegend.RuneMagic";

	internal const string PortalPrefab = "portal_wood";

	internal const string BenchPrefab = "piece_workbench";

	internal const string RuneName = "runemagic_waygate";

	internal const string RuneCloneName = "runemagic_waygate(Clone)";

	internal const int MaxTagLength = 10;

	private const string RuneFocusItemName = "$item_runemagic_runefocus";

	private const int TestedMajor = 1;

	private const int TestedMinor = 5;

	internal const string KeyCreator = "danpe_waygate_creator";

	internal const string KeyTime = "danpe_waygate_time";

	internal const string KeyCamp = "danpe_waygate_camp";

	internal const string KeyTag = "danpe_waygate_tag";

	internal const string KeyReleased = "danpe_waygate_released";

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<string> PortalTag;

	internal static ConfigEntry<bool> ReplacePrevious;

	internal static ConfigEntry<bool> Workbench;

	internal static ConfigEntry<Side> BenchSide;

	internal static ConfigEntry<float> BenchGap;

	internal static ConfigEntry<float> BenchTurn;

	internal static ConfigEntry<bool> NoRoof;

	internal static ConfigEntry<bool> AlignToView;

	internal static ConfigEntry<bool> AimHome;

	internal static ConfigEntry<bool> NeedPortalRecipe;

	internal static ConfigEntry<float> EnergyCost;

	internal static ConfigEntry<bool> AllowUntestedVersion;

	private static Harmony _harmony;

	private static GameObject _container;

	private static GameObject _prefab;

	private static GameObject _portal;

	private static GameObject _bench;

	private static PieceTable _table;

	private static bool _pieceConfigured;

	private static bool _tagWarned;

	private static Player _describedFor;

	internal static string PortalPieceName = "";

	private void Awake()
	{
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Expected O, but got Unknown
		//IL_013c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0146: Expected O, but got Unknown
		//IL_01da: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e4: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When false the plugin does nothing at all (restart required). The player who places the rune needs this add-on; replacing the previous Waygate is done by the host (or dedicated server), so it needs the add-on too. What the rune leaves in the world is an ordinary portal and workbench that everyone can use. Conjured pieces give back no materials when removed; a player without this add-on who happens to be in charge of one (the one nearby after its raiser has left) gets a third back.");
		PortalTag = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Portal name", "Waygate", "The name the raised portal gets. With XPortal it is the name shown in the portal list. Without XPortal portals link by name, whoever built them: the Waygate links with the portal of the same name at home (build one there and give it this name), and in multiplayer each player should use their own name ({player} is replaced by your character's name). At most 10 characters, the most a portal's own name box accepts. Empty = the portal is left unnamed.");
		AimHome = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Aim home at the new Waygate", true, "XPortal only: the Waygate leads to your XPortal default portal, and this also aims that default portal back at the new Waygate, so stepping through it at home brings you straight back. Off: pick the Waygate in the default portal's list yourself.");
		ReplacePrevious = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Replace previous Waygate", true, "Raising a new Waygate lets your previous one crumble (its portal and workbench). With XPortal, portals that led to the old one are re-aimed at the new one first. Without XPortal your home portal of that name then links with the new one; your home is a portal of that name the rune did not raise that you built or named yourself - if there is none, the first Waygate you raised is the home and stays, and it crumbles too once you build or name a home. Rename a Waygate (to a new name, not an empty one) to keep it for good. Carried out by the host or dedicated server, which needs this add-on.");
		Workbench = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Workbench", true, "Also raise a workbench beside the portal.");
		BenchSide = ((BaseUnityPlugin)this).Config.Bind<Side>("General", "Workbench side", Side.Right, "Which side of the portal the workbench stands on, seen from where you stand.");
		BenchGap = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Workbench gap", 1f, new ConfigDescription("Metres of space between the portal and the workbench.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), new object[0]));
		BenchTurn = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Workbench turn", 0f, new ConfigDescription("Extra turn of the workbench in degrees. At 0 it faces you like the portal.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-180f, 180f), new object[0]));
		NoRoof = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Workbench needs no roof", true, "A Waygate workbench works in the open. Applies for every player who has this add-on; players without it see a normal workbench that wants a roof.");
		AlignToView = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Align to your view", true, "The portal faces you and the workbench stands beside it each time you select the rune; the scroll wheel turns them in steps from there. Off: Valheim's fixed world orientation, turned only by the scroll wheel.");
		NeedPortalRecipe = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Requires portal recipe", true, "The rune appears in the Rune Focus menu once you know how to build a portal. Off: always available.");
		EnergyCost = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Energy cost", 200f, new ConfigDescription("Runic energy to raise a Waygate.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f), new object[0]));
		AllowUntestedVersion = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Allow untested Rune Magic version", false, "This add-on was verified against Rune Magic 1.5.x. With any other version it stays off unless this is true.");
		if (!Enabled.Value)
		{
			Log.LogInfo((object)"Waygate is OFF.");
			return;
		}
		PortalTag.SettingChanged += RefreshDescription;
		ReplacePrevious.SettingChanged += RefreshDescription;
		Workbench.SettingChanged += RefreshDescription;
		AimHome.SettingChanged += RefreshDescription;
		try
		{
			Setup();
			Log.LogInfo((object)"Waygate registered; the rune appears in the Rune Focus menu once a world is loaded.");
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Setup failed - the Waygate rune will not be available. Nothing else is affected. " + ex));
			Teardown();
		}
	}

	private void Update()
	{
		if (_harmony != null)
		{
			if ((Object)(object)Player.m_localPlayer != (Object)(object)_describedFor)
			{
				_describedFor = Player.m_localPlayer;
				RefreshDescription(null, EventArgs.Empty);
			}
			Crumbler.Tick();
		}
	}

	private void OnDestroy()
	{
		Teardown();
	}

	private static void Teardown()
	{
		if (PortalTag != null)
		{
			PortalTag.SettingChanged -= RefreshDescription;
			ReplacePrevious.SettingChanged -= RefreshDescription;
			Workbench.SettingChanged -= RefreshDescription;
			AimHome.SettingChanged -= RefreshDescription;
		}
		try
		{
			if ((Object)(object)_table != (Object)null && (Object)(object)_prefab != (Object)null)
			{
				_table.m_pieces.Remove(_prefab);
			}
			if ((Object)(object)ZNetScene.instance != (Object)null && (Object)(object)_prefab != (Object)null)
			{
				ZNetScene.instance.m_prefabs.Remove(_prefab);
			}
			if ((Object)(object)_container != (Object)null)
			{
				Object.Destroy((Object)(object)_container);
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Unregister failed: " + ex.Message));
		}
		_prefab = null;
		_portal = null;
		_bench = null;
		_container = null;
		_table = null;
		_pieceConfigured = false;
		_describedFor = null;
		if (_harmony != null)
		{
			List<MethodBase> list;
			try
			{
				list = new List<MethodBase>(_harmony.GetPatchedMethods());
			}
			catch (Exception)
			{
				list = new List<MethodBase>();
			}
			foreach (MethodBase item in list)
			{
				try
				{
					_harmony.Unpatch(item, (HarmonyPatchType)0, "danpe.RuneMagicWaygate");
				}
				catch (Exception ex3)
				{
					Log.LogWarning((object)("Unpatch failed for " + item.Name + ": " + ex3.Message));
				}
			}
			_harmony = null;
		}
		Patches.Reset();
	}

	private static void CheckRuneMagicVersion()
	{
		if (!Chainloader.PluginInfos.TryGetValue("hyleanlegend.RuneMagic", out var value) || value == null)
		{
			throw new InvalidOperationException("Rune Magic is not loaded");
		}
		Version version = value.Metadata.Version;
		if (version.Major != 1 || version.Minor != 5)
		{
			if (!AllowUntestedVersion.Value)
			{
				throw new InvalidOperationException(string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x). Set 'Allow untested Rune Magic version' to true to try anyway."));
			}
			Log.LogWarning((object)string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x); continuing because the config allows it."));
		}
	}

	private static Type RequireType(string name)
	{
		Type type = AccessTools.TypeByName(name);
		if (type == null)
		{
			throw new InvalidOperationException("Rune Magic type not found: " + name);
		}
		return type;
	}

	private static MethodInfo RequireMethod(Type t, string name, Type[] args)
	{
		MethodInfo methodInfo = ((args == null) ? AccessTools.Method(t, name, (Type[])null, (Type[])null) : AccessTools.Method(t, name, args, (Type[])null));
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Method not found: " + t.FullName + "." + name);
		}
		return methodInfo;
	}

	private static FieldInfo RequireField(Type t, string name)
	{
		FieldInfo fieldInfo = AccessTools.Field(t, name);
		if (fieldInfo == null)
		{
			throw new InvalidOperationException("Field not found: " + t.FullName + "." + name);
		}
		return fieldInfo;
	}

	private static HarmonyMethod H(string name)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(typeof(Patches), name, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Patch method missing: " + name);
		}
		return new HarmonyMethod(methodInfo);
	}

	private static void Setup()
	{
		//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dd: Expected O, but got Unknown
		//IL_03ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f8: Expected O, but got Unknown
		CheckRuneMagicVersion();
		Type t = RequireType("ValheimMod.ValheimMod");
		MethodInfo methodInfo = RequireMethod(t, "get_isModAwake", Type.EmptyTypes);
		if (!(bool)methodInfo.Invoke(null, null))
		{
			throw new InvalidOperationException("Rune Magic did not finish initialising (isModAwake is false)");
		}
		Type t2 = RequireType("ValheimMod.UnlockManager");
		Type t3 = RequireType("ValheimMod.RunemagicPieceConfig");
		Type t4 = RequireType("ValheimMod.CustomContentSetupHandler");
		Type t5 = RequireType("ValheimMod.BoulderSetupHandler");
		Type t6 = RequireType("ValheimMod.PlayerPatch");
		MethodInfo methodInfo2 = RequireMethod(t2, "isUnlockable", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo3 = RequireMethod(t2, "isUnlocked", new Type[2]
		{
			typeof(Player),
			typeof(Piece)
		});
		MethodInfo methodInfo4 = RequireMethod(t3, "getEnergyCost", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo5 = RequireMethod(t5, "SetUpCustomBoulderFeatures", Type.EmptyTypes);
		FieldInfo fieldInfo = RequireField(t6, "PlayerPlacing");
		if (fieldInfo.FieldType != typeof(bool) || !fieldInfo.IsStatic)
		{
			throw new InvalidOperationException("PlayerPatch.PlayerPlacing has an unexpected shape");
		}
		MethodInfo methodInfo6 = RequireMethod(typeof(ZNetScene), "Awake", Type.EmptyTypes);
		MethodInfo methodInfo7 = RequireMethod(typeof(Player), "UpdatePlacementGhost", new Type[1] { typeof(bool) });
		MethodInfo methodInfo8 = RequireMethod(typeof(Player), "SetupPlacementGhost", Type.EmptyTypes);
		MethodInfo methodInfo9 = RequireMethod(typeof(Piece), "DropResources", new Type[1] { typeof(HitData) });
		MethodInfo methodInfo10 = RequireMethod(typeof(CraftingStation), "Start", Type.EmptyTypes);
		if (!(RequireField(t4, "RegisteredItemPrefabs").GetValue(null) is List<GameObject> list))
		{
			throw new InvalidOperationException("Rune Magic's item prefab list has an unexpected type");
		}
		PieceTable val = null;
		foreach (GameObject item in list)
		{
			ItemDrop val2 = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null && val2.m_itemData.m_shared.m_name == "$item_runemagic_runefocus")
			{
				val = val2.m_itemData.m_shared.m_buildPieces;
				break;
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			throw new InvalidOperationException("Rune Focus piece table not found");
		}
		Patches.PlayerPlacingField = fieldInfo;
		XPortalBridge.Init();
		_harmony = new Harmony("danpe.RuneMagicWaygate");
		_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, H("IsUnlockablePostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, H("IsUnlockedPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, H("EnergyCostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, H("BoulderSetupPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, H("PlacementGhostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo8, H("SetupPlacementGhostPrefix"), H("SetupPlacementGhostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo9, H("DropResourcesPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo10, (HarmonyMethod)null, H("StationStartPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		HarmonyMethod val3 = H("ZNetSceneAwakePrefix");
		val3.priority = 800;
		_harmony.Patch((MethodBase)methodInfo6, val3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_container = new GameObject("RuneMagicWaygate_Prefabs");
		_container.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)_container);
		_table = val;
	}

	internal static void OnZNetSceneAwake(ZNetScene scene)
	{
		if ((Object)(object)scene == (Object)null || scene.m_prefabs == null || (Object)(object)_container == (Object)null)
		{
			return;
		}
		if ((Object)(object)_prefab == (Object)null)
		{
			GameObject val = null;
			GameObject val2 = null;
			List<GameObject> prefabs = scene.m_prefabs;
			for (int i = 0; i < prefabs.Count; i++)
			{
				GameObject val3 = prefabs[i];
				if (!((Object)(object)val3 == (Object)null))
				{
					if (((Object)val3).name == "portal_wood")
					{
						val = val3;
					}
					else if (((Object)val3).name == "piece_workbench")
					{
						val2 = val3;
					}
				}
			}
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val.GetComponent<Piece>() == (Object)null || (Object)(object)val2.GetComponent<Piece>() == (Object)null || (Object)(object)val.GetComponent<TeleportWorld>() == (Object)null)
			{
				Log.LogWarning((object)"The vanilla portal (portal_wood) or workbench (piece_workbench) was not found in this scene; the Waygate rune is unavailable.");
				return;
			}
			_portal = val;
			_bench = val2;
			PortalPieceName = val.GetComponent<Piece>().m_name;
			_prefab = Prefabs.Build(val, val2, _container.transform);
		}
		if (!scene.m_prefabs.Contains(_prefab))
		{
			scene.m_prefabs.Add(_prefab);
		}
		TryFinishPieceSetup();
	}

	internal static void TryFinishPieceSetup()
	{
		if ((Object)(object)_prefab == (Object)null || (Object)(object)_portal == (Object)null || (Object)(object)_bench == (Object)null || (Object)(object)_table == (Object)null)
		{
			return;
		}
		Piece component = _prefab.GetComponent<Piece>();
		if ((Object)(object)component == (Object)null)
		{
			return;
		}
		if (!_pieceConfigured)
		{
			Prefabs.ConfigurePiece(component, _portal.GetComponent<Piece>(), _bench.GetComponent<Piece>(), _table);
			_pieceConfigured = true;
		}
		List<GameObject> pieces = _table.m_pieces;
		for (int num = pieces.Count - 1; num >= 0; num--)
		{
			GameObject val = pieces[num];
			if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)_prefab && ((Object)val).name == "runemagic_waygate")
			{
				pieces.RemoveAt(num);
			}
		}
		if (pieces.Count == 0 || (Object)(object)pieces[pieces.Count - 1] != (Object)(object)_prefab)
		{
			bool flag = !pieces.Contains(_prefab);
			pieces.Remove(_prefab);
			pieces.Add(_prefab);
			if (flag)
			{
				Log.LogInfo((object)"Waygate added to the Rune Focus menu.");
			}
		}
	}

	internal static string TagFor(Player player)
	{
		string text = ((PortalTag != null && PortalTag.Value != null) ? PortalTag.Value : "");
		if (text.IndexOf("{player}", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			string with = (((Object)(object)player != (Object)null) ? player.GetPlayerName() : "");
			text = ReplaceIgnoreCase(text, "{player}", with);
		}
		text = text.Trim();
		if (text.Length > 10)
		{
			if (!_tagWarned)
			{
				_tagWarned = true;
				Log.LogWarning((object)("Portal name '" + text + "' is longer than the " + 10 + " characters a portal's name box accepts; using '" + text.Substring(0, 10) + "'. Name your home portal the same."));
			}
			text = text.Substring(0, 10).TrimEnd(new char[0]);
		}
		return text;
	}

	private static string ReplaceIgnoreCase(string s, string what, string with)
	{
		for (int num = s.IndexOf(what, StringComparison.OrdinalIgnoreCase); num >= 0; num = s.IndexOf(what, num + with.Length, StringComparison.OrdinalIgnoreCase))
		{
			s = s.Substring(0, num) + with + s.Substring(num + what.Length);
		}
		return s;
	}

	internal static string Description()
	{
		string text = ((Workbench == null || Workbench.Value) ? "a portal with a workbench beside it" : "a portal");
		string text2 = "Raises " + text + ". ";
		string text3 = ((ReplacePrevious == null || ReplacePrevious.Value) ? " Your previous Waygate crumbles." : "");
		if (XPortalBridge.Present)
		{
			text2 += "It leads to your XPortal default portal";
			text2 += ((AimHome == null || AimHome.Value) ? ", which is aimed back at it." : "; pick it there to come back.");
			return text2 + text3;
		}
		string text4 = ((PortalTag != null && PortalTag.Value != null) ? PortalTag.Value : "");
		string text5 = TagFor(Player.m_localPlayer);
		if ((Object)(object)Player.m_localPlayer == (Object)null && text4.IndexOf("{player}", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return text2 + "The portal is named after your character and links with your portal of that name at home." + text3;
		}
		if (text5.Length > 0)
		{
			string text6 = text2;
			return text6 + "The portal is named \"" + text5 + "\" and links with your portal of that name at home." + text3;
		}
		return text2 + "Name the portal yourself to link it.";
	}

	private static void RefreshDescription(object sender, EventArgs e)
	{
		if (!((Object)(object)_prefab == (Object)null))
		{
			Piece component = _prefab.GetComponent<Piece>();
			if ((Object)(object)component != (Object)null)
			{
				component.m_description = Description();
			}
		}
	}
}
internal static class Prefabs
{
	internal static Bounds PortalBounds = new Bounds(new Vector3(0f, 1.65f, 0f), new Vector3(4.2f, 3.3f, 1.2f));

	internal static Bounds BenchBounds = new Bounds(new Vector3(0f, 0.6f, 0f), new Vector3(3f, 1.2f, 1.3f));

	internal static GameObject Build(GameObject portal, GameObject bench, Transform container)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: 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_0085: Expected O, but got Unknown
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_0151: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
		PortalBounds = MeasureBounds(portal, PortalBounds);
		BenchBounds = MeasureBounds(bench, BenchBounds);
		WaygatePlugin.Log.LogInfo((object)("Portal " + Metres(((Bounds)(ref PortalBounds)).size) + ", workbench " + Metres(((Bounds)(ref BenchBounds)).size) + " (width x height x depth)."));
		GameObject val = new GameObject("runemagic_waygate");
		val.transform.SetParent(container, false);
		ZNetView val2 = val.AddComponent<ZNetView>();
		val2.m_persistent = false;
		val2.m_distant = false;
		val2.m_type = (ObjectType)0;
		val2.m_syncInitialScale = false;
		Piece val3 = val.AddComponent<Piece>();
		val3.m_name = "Rune of the Wayfarer: Waygate";
		val3.m_enabled = false;
		val.AddComponent<WaygateRune>();
		GameObject val4 = Object.Instantiate<GameObject>(portal, val.transform, false);
		((Object)val4).name = "Portal";
		Strip(val4);
		val4.transform.localPosition = Vector3.zero;
		val4.transform.localRotation = Quaternion.Euler(0f, 180f, 0f);
		GameObject val5 = Object.Instantiate<GameObject>(bench, val.transform, false);
		((Object)val5).name = "Bench";
		Strip(val5);
		val5.transform.localPosition = new Vector3(((Bounds)(ref PortalBounds)).size.x * 0.5f + 1f + ((Bounds)(ref BenchBounds)).size.x * 0.5f, 0f, 0f);
		val5.transform.localRotation = Quaternion.Euler(0f, 180f, 0f);
		return val;
	}

	private static string Metres(Vector3 v)
	{
		return v.x.ToString("F2") + " x " + v.y.ToString("F2") + " x " + v.z.ToString("F2") + " m";
	}

	internal static void ConfigurePiece(Piece piece, Piece portal, Piece bench, PieceTable table)
	{
		//IL_001b: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fd: Expected O, but got Unknown
		piece.m_category = (PieceCategory)((table.m_categoryLabels != null && table.m_categoryLabels.Count > 3) ? 3 : 0);
		piece.m_groundPiece = false;
		piece.m_clipGround = false;
		piece.m_clipEverything = true;
		piece.m_noClipping = false;
		piece.m_groundOnly = portal.m_groundOnly;
		piece.m_cultivatedGroundOnly = portal.m_cultivatedGroundOnly;
		piece.m_waterPiece = portal.m_waterPiece;
		piece.m_noInWater = portal.m_noInWater;
		piece.m_notOnWood = portal.m_notOnWood;
		piece.m_notOnTiltingSurface = portal.m_notOnTiltingSurface;
		piece.m_inCeilingOnly = portal.m_inCeilingOnly;
		piece.m_notOnFloor = portal.m_notOnFloor;
		piece.m_onlyInTeleportArea = portal.m_onlyInTeleportArea;
		piece.m_allowedInDungeons = portal.m_allowedInDungeons;
		piece.m_vegetationGroundOnly = portal.m_vegetationGroundOnly;
		piece.m_onlyInBiome = portal.m_onlyInBiome;
		piece.m_allowRotatedOverlap = portal.m_allowRotatedOverlap;
		piece.m_randomInitBuildRotation = false;
		piece.m_craftingStation = null;
		piece.m_resources = (Requirement[])(object)new Requirement[0];
		piece.m_placeEffect = new EffectList();
		piece.m_comfort = 0;
		piece.m_description = WaygatePlugin.Description();
		piece.m_icon = Icon.Compose(portal.m_icon, bench.m_icon);
		piece.m_enabled = true;
	}

	private static Bounds MeasureBounds(GameObject prefab, Bounds fallback)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_022d: Unknown result type (might be due to invalid IL or missing references)
		//IL_024d: 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)
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_0161: Unknown result type (might be due to invalid IL or missing references)
		//IL_0166: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: 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)
		//IL_00a6: 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_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_024f: 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_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: 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_0127: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: 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_0138: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			MeshFilter[] componentsInChildren = prefab.GetComponentsInChildren<MeshFilter>(true);
			Matrix4x4 worldToLocalMatrix = prefab.transform.worldToLocalMatrix;
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(float.MaxValue, float.MaxValue, float.MaxValue);
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(float.MinValue, float.MinValue, float.MinValue);
			bool flag = false;
			MeshFilter[] array = componentsInChildren;
			Vector3 val5 = default(Vector3);
			foreach (MeshFilter val3 in array)
			{
				if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3.sharedMesh == (Object)null) && ActiveInPrefab(((Component)val3).transform, prefab.transform))
				{
					Bounds bounds = val3.sharedMesh.bounds;
					Matrix4x4 val4 = worldToLocalMatrix * ((Component)val3).transform.localToWorldMatrix;
					for (int j = 0; j < 8; j++)
					{
						((Vector3)(ref val5))..ctor(((j & 1) == 0) ? ((Bounds)(ref bounds)).min.x : ((Bounds)(ref bounds)).max.x, ((j & 2) == 0) ? ((Bounds)(ref bounds)).min.y : ((Bounds)(ref bounds)).max.y, ((j & 4) == 0) ? ((Bounds)(ref bounds)).min.z : ((Bounds)(ref bounds)).max.z);
						Vector3 val6 = ((Matrix4x4)(ref val4)).MultiplyPoint3x4(val5);
						val = Vector3.Min(val, val6);
						val2 = Vector3.Max(val2, val6);
						flag = true;
					}
				}
			}
			if (flag)
			{
				Vector3 val7 = val2 - val;
				if (val7.x > 0.1f && val7.z > 0.05f && val7.y > 0.1f && val7.x < 20f && val7.z < 20f && val7.y < 20f)
				{
					Bounds result = default(Bounds);
					((Bounds)(ref result)).SetMinMax(val, val2);
					return result;
				}
			}
		}
		catch (Exception ex)
		{
			WaygatePlugin.Log.LogWarning((object)("Could not measure " + ((Object)prefab).name + ": " + ex.Message));
		}
		WaygatePlugin.Log.LogWarning((object)("Could not measure " + ((Object)prefab).name + "'s meshes; assuming " + Metres(((Bounds)(ref fallback)).size) + "."));
		return fallback;
	}

	private static bool ActiveInPrefab(Transform t, Transform root)
	{
		Transform val = t;
		while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
		{
			if (!((Component)val).gameObject.activeSelf)
			{
				return false;
			}
			val = val.parent;
		}
		return true;
	}

	private static void Strip(GameObject go)
	{
		Transform[] componentsInChildren = go.GetComponentsInChildren<Transform>(true);
		Transform[] array = componentsInChildren;
		foreach (Transform val in array)
		{
			if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)go.transform && !((Component)val).gameObject.activeSelf)
			{
				Object.DestroyImmediate((Object)(object)((Component)val).gameObject);
			}
		}
		for (int j = 0; j < 8; j++)
		{
			bool flag = false;
			bool flag2 = false;
			Component[] componentsInChildren2 = go.GetComponentsInChildren<Component>(true);
			Component[] array2 = componentsInChildren2;
			foreach (Component val2 in array2)
			{
				if ((Object)(object)val2 == (Object)null || Keep(val2))
				{
					continue;
				}
				if (j < 2 && !(val2 is MonoBehaviour))
				{
					flag2 = true;
					continue;
				}
				try
				{
					Object.DestroyImmediate((Object)(object)val2);
				}
				catch (Exception)
				{
				}
				if ((Object)(object)val2 == (Object)null)
				{
					flag = true;
				}
				else
				{
					flag2 = true;
				}
			}
			if (!flag2)
			{
				return;
			}
			if (!flag && j >= 2)
			{
				break;
			}
		}
		Component[] componentsInChildren3 = go.GetComponentsInChildren<Component>(true);
		Component[] array3 = componentsInChildren3;
		foreach (Component val3 in array3)
		{
			if ((Object)(object)val3 != (Object)null && !Keep(val3))
			{
				throw new InvalidOperationException("Could not strip " + ((object)val3).GetType().Name + " from the " + ((Object)go).name + " visual copy");
			}
		}
	}

	private static bool Keep(Component c)
	{
		if (!(c is Transform) && !(c is MeshFilter) && !(c is MeshRenderer))
		{
			return c is LODGroup;
		}
		return true;
	}
}
internal static class Layout
{
	private static int _mask = -1;

	internal static Quaternion BaseRotation(Vector3 rootPos, Quaternion rootRot)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: 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)
		if (WaygatePlugin.AlignToView != null && !WaygatePlugin.AlignToView.Value)
		{
			return rootRot;
		}
		Player localPlayer = Player.m_localPlayer;
		Vector3 val = Vector3.zero;
		if ((Object)(object)GameCamera.instance != (Object)null)
		{
			val = ((Component)GameCamera.instance).transform.forward;
			val.y = 0f;
		}
		if (((Vector3)(ref val)).sqrMagnitude < 0.0001f && (Object)(object)localPlayer != (Object)null)
		{
			val = rootPos - ((Component)localPlayer).transform.position;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude < 0.25f)
			{
				val = ((Component)localPlayer).transform.forward;
				val.y = 0f;
			}
		}
		if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
		{
			return rootRot;
		}
		float num = Mathf.Atan2(val.x, val.z) * 57.29578f;
		return Quaternion.Euler(0f, num + ((Quaternion)(ref rootRot)).eulerAngles.y, 0f);
	}

	internal static void Poses(Vector3 aimed, Quaternion pieceRot, out Vector3 portalPos, out Quaternion portalRot, out Vector3 benchPos, out Quaternion benchRot)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//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_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: 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)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: 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_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		Quaternion val = BaseRotation(aimed, pieceRot);
		portalPos = aimed;
		portalRot = val * Quaternion.Euler(0f, 180f, 0f);
		float num = ((WaygatePlugin.BenchTurn != null) ? WaygatePlugin.BenchTurn.Value : 0f);
		benchRot = val * Quaternion.Euler(0f, 180f + num, 0f);
		float num2 = num * ((float)Math.PI / 180f);
		Vector3 size = ((Bounds)(ref Prefabs.BenchBounds)).size;
		float num3 = 0.5f * (Mathf.Abs(Mathf.Cos(num2)) * size.x + Mathf.Abs(Mathf.Sin(num2)) * size.z);
		float num4 = ((WaygatePlugin.BenchGap != null) ? WaygatePlugin.BenchGap.Value : 1f);
		float num5 = ((WaygatePlugin.BenchSide != null && WaygatePlugin.BenchSide.Value == WaygatePlugin.Side.Left) ? (-1f) : 1f);
		float num6 = ((Bounds)(ref Prefabs.PortalBounds)).size.x * 0.5f + Mathf.Max(0f, num4) + num3;
		Vector3 world = aimed + val * new Vector3(num5 * num6, 0f, 0f);
		benchPos = new Vector3(world.x, GroundHeight(world, aimed.y), world.z);
	}

	internal static float GroundHeight(Vector3 world, float rootY)
	{
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		if (_mask < 0)
		{
			_mask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "terrain", "vehicle" });
		}
		RaycastHit[] array = Physics.RaycastAll(new Vector3(world.x, rootY + 2f, world.z), Vector3.down, 30f, _mask);
		bool flag = false;
		float num = 0f;
		for (int i = 0; i < array.Length; i++)
		{
			Collider collider = ((RaycastHit)(ref array[i])).collider;
			if (!((Object)(object)collider == (Object)null) && !((Object)(object)collider.attachedRigidbody != (Object)null) && (!flag || ((RaycastHit)(ref array[i])).point.y > num))
			{
				num = ((RaycastHit)(ref array[i])).point.y;
				flag = true;
			}
		}
		if (flag)
		{
			return num;
		}
		float result = default(float);
		if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGroundHeight(world, ref result))
		{
			return result;
		}
		return rootY;
	}
}
public class WaygateRune : MonoBehaviour
{
	private bool _ghost;

	private bool _done;

	private float _created;

	private ZNetView _nview;

	private Transform _portalVisual;

	private Transform _benchVisual;

	private Renderer[] _benchRenderers;

	private bool _benchShown = true;

	private void Awake()
	{
		_ghost = ZNetView.m_forceDisableInit;
		_portalVisual = ((Component)this).transform.Find("Portal");
		_benchVisual = ((Component)this).transform.Find("Bench");
		_benchRenderers = (Renderer[])(((Object)(object)_benchVisual != (Object)null) ? ((Array)((Component)_benchVisual).GetComponentsInChildren<Renderer>(true)) : ((Array)new Renderer[0]));
		if (_ghost)
		{
			return;
		}
		if ((Object)(object)_portalVisual != (Object)null)
		{
			((Component)_portalVisual).gameObject.SetActive(false);
		}
		if ((Object)(object)_benchVisual != (Object)null)
		{
			((Component)_benchVisual).gameObject.SetActive(false);
		}
		_created = Time.time;
		_nview = ((Component)this).GetComponent<ZNetView>();
		try
		{
			if (Patches.GetPlayerPlacing() && (Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.IsOwner())
			{
				_done = true;
				Raise();
			}
		}
		catch (Exception ex)
		{
			_done = true;
			WaygatePlugin.Log.LogError((object)("Raising the Waygate failed: " + ex));
		}
	}

	private void Update()
	{
		if (!_ghost && !((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner() && (_done || Time.time - _created > 2f))
		{
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				ZNetScene.instance.Destroy(((Component)this).gameObject);
			}
			else
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}

	private void LateUpdate()
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
		if (!_ghost)
		{
			return;
		}
		Layout.Poses(((Component)this).transform.position, ((Component)this).transform.rotation, out var portalPos, out var portalRot, out var benchPos, out var benchRot);
		if ((Object)(object)_portalVisual != (Object)null)
		{
			_portalVisual.SetPositionAndRotation(portalPos, portalRot);
		}
		bool flag = WaygatePlugin.Workbench == null || WaygatePlugin.Workbench.Value;
		if (flag != _benchShown)
		{
			_benchShown = flag;
			for (int i = 0; i < _benchRenderers.Length; i++)
			{
				if ((Object)(object)_benchRenderers[i] != (Object)null)
				{
					_benchRenderers[i].enabled = flag;
				}
			}
		}
		if ((Object)(object)_benchVisual != (Object)null)
		{
			_benchVisual.SetPositionAndRotation(benchPos, benchRot);
		}
	}

	private unsafe void Raise()
	{
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		//IL_018d: Unknown result type (might be due to invalid IL or missing references)
		//IL_018f: 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_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: 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_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: 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_0232: Unknown result type (might be due to invalid IL or missing references)
		//IL_0237: Unknown result type (might be due to invalid IL or missing references)
		//IL_0239: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_024e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0253: Unknown result type (might be due to invalid IL or missing references)
		//IL_0255: Unknown result type (might be due to invalid IL or missing references)
		//IL_0286: Unknown result type (might be due to invalid IL or missing references)
		//IL_0288: Unknown result type (might be due to invalid IL or missing references)
		ZNetScene instance = ZNetScene.instance;
		GameObject val = (((Object)(object)instance != (Object)null) ? instance.GetPrefab("portal_wood") : null);
		GameObject val2 = (((Object)(object)instance != (Object)null) ? instance.GetPrefab("piece_workbench") : null);
		if ((Object)(object)val == (Object)null)
		{
			WaygatePlugin.Log.LogError((object)"The vanilla portal prefab is missing; nothing was raised.");
			return;
		}
		Layout.Poses(((Component)this).transform.position, ((Component)this).transform.rotation, out var portalPos, out var portalRot, out var benchPos, out var benchRot);
		Player localPlayer = Player.m_localPlayer;
		long playerId = (((Object)(object)localPlayer != (Object)null) ? localPlayer.GetPlayerID() : 0);
		ZDOID playerZdo = (((Object)(object)localPlayer != (Object)null) ? ((Character)localPlayer).GetZDOID() : ZDOID.None);
		PlatformUserID userId = default(PlatformUserID);
		try
		{
			userId = ((IUser)PlatformManager.DistributionPlatform.LocalUser).PlatformUserID;
		}
		catch (Exception)
		{
		}
		long now = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTime().Ticks : DateTime.UtcNow.Ticks);
		long num;
		for (num = 0L; num == 0; num = BitConverter.ToInt64(Guid.NewGuid().ToByteArray(), 0))
		{
		}
		GameObject val3 = null;
		if ((WaygatePlugin.Workbench == null || WaygatePlugin.Workbench.Value) && (Object)(object)val2 != (Object)null)
		{
			val3 = Object.Instantiate<GameObject>(val2, benchPos, benchRot);
			Finish(val3, playerId, userId, playerZdo, now, num);
			CraftingStation component = val3.GetComponent<CraftingStation>();
			if ((Object)(object)component != (Object)null && (Object)(object)localPlayer != (Object)null)
			{
				localPlayer.AddKnownStation(component);
			}
		}
		GameObject val4 = Object.Instantiate<GameObject>(val, portalPos, portalRot);
		Finish(val4, playerId, userId, playerZdo, now, num);
		ZNetView component2 = val4.GetComponent<ZNetView>();
		string text = WaygatePlugin.TagFor(localPlayer);
		ZDO val5 = (((Object)(object)component2 != (Object)null && component2.IsValid()) ? component2.GetZDO() : null);
		if (val5 != null && text.Length > 0)
		{
			val5.Set(ZDOVars.s_tag, text);
			val5.Set(ZDOVars.s_tagauthor, ((object)(*(PlatformUserID*)(&userId))/*cast due to .constrained prefix*/).ToString());
			val5.Set("danpe_waygate_tag", text);
		}
		string text2;
		if (XPortalBridge.Present)
		{
			text2 = "Waygate raised";
			if (val5 != null && XPortalBridge.Ready)
			{
				try
				{
					ZDOID uid = val5.m_uid;
					XPortalBridge.Announce(uid, val4.transform.position, text);
					ZDOID val6 = XPortalBridge.DefaultPortal();
					string text3 = XPortalBridge.NameOf(val6);
					text2 = (((ZDOID)(ref val6)).IsNone() ? "Waygate raised: choose where it leads in its portal list (you have no XPortal default portal)" : ((WaygatePlugin.AimHome != null && !WaygatePlugin.AimHome.Value) ? ("Waygate raised: it leads to " + text3 + "; pick it at " + text3 + " to come back") : (XPortalBridge.Aim(val6, uid) ? ("Waygate raised: it leads to " + text3 + ", and " + text3 + " now leads here") : ("Waygate raised: it leads to " + text3))));
				}
				catch (Exception e)
				{
					WaygatePlugin.Log.LogWarning((object)("Could not set up the Waygate in XPortal: " + XPortalBridge.Root(e)));
				}
			}
		}
		else
		{
			text2 = ((text.Length > 0) ? ("Waygate raised: it links with your portal named \"" + text + "\"") : "Waygate raised: name the portal to link it");
		}
		if ((Object)(object)localPlayer != (Object)null)
		{
			((Character)localPlayer).Message((MessageType)2, text2, 0, (Sprite)null, false);
		}
	}

	private static void Finish(GameObject go, long playerId, PlatformUserID userId, ZDOID playerZdo, long now, long camp)
	{
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		ZNetView component = go.GetComponent<ZNetView>();
		if (!((Object)(object)component == (Object)null) && component.IsValid())
		{
			Piece component2 = go.GetComponent<Piece>();
			WearNTear component3 = go.GetComponent<WearNTear>();
			if ((Object)(object)component3 != (Object)null)
			{
				component3.OnPlaced();
			}
			ZDO zDO = component.GetZDO();
			zDO.Set("danpe_waygate_creator", playerId);
			zDO.Set("danpe_waygate_time", now);
			zDO.Set("danpe_waygate_camp", camp);
			if ((Object)(object)component2 != (Object)null && component2.m_placeEffect != null)
			{
				component2.m_placeEffect.Create(go.transform.position, go.transform.rotation, go.transform, 1f, -1, playerZdo);
			}
		}
	}
}
internal static class Crumbler
{
	private sealed class Entry
	{
		internal ZDO Zdo;

		internal long Time;

		internal string Tag;

		internal long Creator;

		internal string Author;
	}

	private static float _next;

	private static bool _failed;

	private static bool _xportalWarned;

	private static bool _handoverFailed;

	internal static void Tick()
	{
		if (_failed || Time.time < _next)
		{
			return;
		}
		_next = Time.time + 5f;
		if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || ZDOMan.instance == null)
		{
			return;
		}
		if (XPortalBridge.Present && (!XPortalBridge.Ready || _handoverFailed))
		{
			if (!_xportalWarned)
			{
				_xportalWarned = true;
				WaygatePlugin.Log.LogWarning((object)"XPortal could not be reached; previous Waygates are left standing so XPortal never points at a portal that is gone.");
			}
			return;
		}
		try
		{
			if (XPortalBridge.Present)
			{
				RestoreNames();
			}
			if (WaygatePlugin.ReplacePrevious != null && WaygatePlugin.ReplacePrevious.Value)
			{
				Sweep();
			}
		}
		catch (Exception e)
		{
			_failed = true;
			WaygatePlugin.Log.LogError((object)("Waygate upkeep is disabled for this session after an error: " + XPortalBridge.Root(e)));
		}
	}

	private static void RestoreNames()
	{
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		List<ZDO> portalList = ZDOMan.instance.GetPortalList();
		if (portalList == null)
		{
			return;
		}
		for (int i = 0; i < portalList.Count; i++)
		{
			ZDO val = portalList[i];
			if (val == null || !val.IsValid() || val.GetLong("danpe_waygate_creator", 0L) == 0)
			{
				continue;
			}
			TrackRename(val);
			if (IsLineMember(val) && val.GetString(ZDOVars.s_tag, "").Length <= 0)
			{
				string text = val.GetString("danpe_waygate_tag", "");
				if (text.Length > 0)
				{
					XPortalBridge.Rename(val.m_uid, text);
				}
			}
		}
	}

	internal static bool IsLineMember(ZDO z)
	{
		if (z == null || z.GetLong("danpe_waygate_creator", 0L) == 0 || z.GetLong("danpe_waygate_released", 0L) != 0)
		{
			return false;
		}
		string text = z.GetString("danpe_waygate_tag", "");
		string text2 = z.GetString(ZDOVars.s_tag, "");
		if (XPortalBridge.Present)
		{
			if (text2.Length != 0)
			{
				return text2 == text;
			}
			return true;
		}
		if (text.Length > 0)
		{
			return text2 == text;
		}
		return false;
	}

	private static void TrackRename(ZDO z)
	{
		if (z.GetLong("danpe_waygate_released", 0L) != 0)
		{
			return;
		}
		string text = z.GetString("danpe_waygate_tag", "");
		string text2 = z.GetString(ZDOVars.s_tag, "");
		bool num;
		if (!XPortalBridge.Present)
		{
			if (text.Length <= 0)
			{
				return;
			}
			num = text2 != text;
		}
		else
		{
			if (text2.Length <= 0)
			{
				return;
			}
			num = text2 != text;
		}
		if (num)
		{
			z.SetOwner(ZDOMan.GetSessionID());
			z.Set("danpe_waygate_released", 1L);
		}
	}

	private static void Sweep()
	{
		//IL_0276: Unknown result type (might be due to invalid IL or missing references)
		//IL_028d: Unknown result type (might be due to invalid IL or missing references)
		//IL_029b: Unknown result type (might be due to invalid IL or missing references)
		List<ZDO> portalList = ZDOMan.instance.GetPortalList();
		if (portalList == null || portalList.Count == 0)
		{
			return;
		}
		bool present = XPortalBridge.Present;
		Dictionary<string, List<Entry>> dictionary = null;
		List<ZDO> list = null;
		for (int i = 0; i < portalList.Count; i++)
		{
			ZDO val = portalList[i];
			if (val == null || !val.IsValid())
			{
				continue;
			}
			long num = val.GetLong("danpe_waygate_creator", 0L);
			if (num != 0)
			{
				TrackRename(val);
			}
			string text = val.GetString(ZDOVars.s_tag, "");
			if (!IsLineMember(val))
			{
				if (!present && text.Length > 0)
				{
					if (list == null)
					{
						list = new List<ZDO>();
					}
					list.Add(val);
				}
				continue;
			}
			if (dictionary == null)
			{
				dictionary = new Dictionary<string, List<Entry>>();
			}
			string key = (present ? num.ToString() : (num + "\n" + text));
			if (!dictionary.TryGetValue(key, out var value))
			{
				value = (dictionary[key] = new List<Entry>());
			}
			Entry entry = new Entry();
			entry.Zdo = val;
			entry.Time = val.GetLong("danpe_waygate_time", 0L);
			entry.Tag = text;
			entry.Creator = num;
			entry.Author = val.GetString(ZDOVars.s_tagauthor, "");
			value.Add(entry);
		}
		if (dictionary == null)
		{
			return;
		}
		List<ZDO> list3 = null;
		List<ZDO> list4 = null;
		foreach (List<Entry> value2 in dictionary.Values)
		{
			if (value2.Count < 2)
			{
				continue;
			}
			value2.Sort((Entry a, Entry b) => a.Time.CompareTo(b.Time));
			Entry entry2 = value2[value2.Count - 1];
			bool flag = present || HasHome(list, value2[0]);
			for (int num2 = 0; num2 < value2.Count - 1; num2++)
			{
				if (value2[num2].Time != entry2.Time && (num2 != 0 || flag))
				{
					if (list3 == null)
					{
						list3 = new List<ZDO>();
						list4 = new List<ZDO>();
					}
					list3.Add(value2[num2].Zdo);
					list4.Add(entry2.Zdo);
				}
			}
		}
		if (list3 == null)
		{
			return;
		}
		for (int num3 = 0; num3 < list3.Count; num3++)
		{
			if (present)
			{
				try
				{
					if (!XPortalBridge.Knows(list4[num3].m_uid))
					{
						continue;
					}
					XPortalBridge.Retire(list3[num3].m_uid, list4[num3].m_uid);
					goto IL_02d1;
				}
				catch (Exception e)
				{
					_handoverFailed = true;
					WaygatePlugin.Log.LogWarning((object)("XPortal did not take the hand-over (" + XPortalBridge.Root(e) + "); previous Waygates are left standing."));
					break;
				}
			}
			goto IL_02d1;
			IL_02d1:
			Crumble(list3[num3]);
		}
	}

	private static bool HasHome(List<ZDO> homes, Entry first)
	{
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: 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)
		if (homes == null)
		{
			return false;
		}
		for (int i = 0; i < homes.Count; i++)
		{
			ZDO val = homes[i];
			if (!(val.GetString(ZDOVars.s_tag, "") != first.Tag) && (val.GetLong(ZDOVars.s_creator, 0L) == first.Creator || (first.Author.Length > 0 && val.GetString(ZDOVars.s_tagauthor, "") == first.Author)))
			{
				ZDOID connectionZDOID = val.GetConnectionZDOID((ConnectionType)1);
				ZDO val2 = (((ZDOID)(ref connectionZDOID)).IsNone() ? null : ZDOMan.instance.GetZDO(connectionZDOID));
				if (val2 == null || IsLineMember(val2))
				{
					return true;
				}
			}
		}
		return false;
	}

	private static void Crumble(ZDO portal)
	{
		//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)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		long num = portal.GetLong("danpe_waygate_creator", 0L);
		long num2 = portal.GetLong("danpe_waygate_camp", 0L);
		Vector3 position = portal.GetPosition();
		if (num2 != 0)
		{
			List<ZDO> list = new List<ZDO>();
			ZDOMan.instance.FindSectorObjects(ZoneSystem.GetZone(position), new SimulationDistance(1, 0, true), list, (List<ZDO>)null);
			for (int i = 0; i < list.Count; i++)
			{
				ZDO val = list[i];
				if (val != null && val != portal && val.IsValid() && val.GetLong("danpe_waygate_camp", 0L) == num2 && val.GetLong("danpe_waygate_creator", 0L) == num)
				{
					Remove(val);
				}
			}
		}
		Remove(portal);
		WaygatePlugin.Log.LogInfo((object)("A previous Waygate at (" + position.x.ToString("F0") + ", " + position.z.ToString("F0") + ") crumbled; its name is free for the newest one."));
	}

	private static void Remove(ZDO zdo)
	{
		zdo.SetOwner(ZDOMan.GetSessionID());
		ZNetView val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.FindInstance(zdo) : null);
		if ((Object)(object)val != (Object)null)
		{
			ZNetScene.instance.Destroy(((Component)val).gameObject);
		}
		else
		{
			ZDOMan.instance.DestroyZDO(zdo);
		}
	}
}
internal static class XPortalBridge
{
	internal const string Guid = "yay.spikehimself.xportal";

	internal static bool Present;

	internal static bool Ready;

	private static MethodInfo _instance;

	private static MethodInfo _findDefault;

	private static MethodInfo _containsId;

	private static MethodInfo _getById;

	private static MethodInfo _withTarget;

	private static MethodInfo _addOrUpdate;

	private static MethodInfo _remove;

	private static ConstructorInfo _ctor;

	private static PropertyInfo _id;

	private static PropertyInfo _name;

	private static PropertyInfo _target;

	internal static void Init()
	{
		Present = Chainloader.PluginInfos.ContainsKey("yay.spikehimself.xportal");
		Ready = false;
		if (!Present)
		{
			return;
		}
		try
		{
			Type type = AccessTools.TypeByName("XPortal.KnownPortalsManager");
			Type type2 = AccessTools.TypeByName("XPortal.KnownPortal");
			Type type3 = AccessTools.TypeByName("XPortal.RPC.SendToServer");
			if (type == null || type2 == null || type3 == null)
			{
				throw new InvalidOperationException("XPortal types not found");
			}
			_instance = Need(AccessTools.Method(type, "get_Instance", Type.EmptyTypes, (Type[])null), "KnownPortalsManager.Instance");
			_findDefault = Need(AccessTools.Method(type, "FindDefaultPortal", Type.EmptyTypes, (Type[])null), "FindDefaultPortal");
			_containsId = Need(AccessTools.Method(type, "ContainsId", new Type[1] { typeof(ZDOID) }, (Type[])null), "ContainsId");
			_getById = Need(AccessTools.Method(type, "GetKnownPortalById", new Type[1] { typeof(ZDOID) }, (Type[])null), "GetKnownPortalById");
			_withTarget = Need(AccessTools.Method(type, "GetPortalsWithTarget", new Type[1] { typeof(ZDOID) }, (Type[])null), "GetPortalsWithTarget");
			_addOrUpdate = Need(AccessTools.Method(type3, "AddOrUpdateRequest", new Type[1] { type2 }, (Type[])null), "SendToServer.AddOrUpdateRequest");
			_remove = Need(AccessTools.Method(type3, "RemoveRequest", new Type[1] { typeof(ZDOID) }, (Type[])null), "SendToServer.RemoveRequest");
			_ctor = type2.GetConstructor(new Type[2]
			{
				typeof(ZDOID),
				typeof(Vector3)
			});
			if (_ctor == null)
			{
				throw new InvalidOperationException("KnownPortal(ZDOID, Vector3) not found");
			}
			_id = NeedProperty(type2, "Id", typeof(ZDOID));
			_name = NeedProperty(type2, "Name", typeof(string));
			_target = NeedProperty(type2, "Target", typeof(ZDOID));
			if (_findDefault.ReturnType != typeof(ZDOID) || !typeof(IEnumerable).IsAssignableFrom(_withTarget.ReturnType))
			{
				throw new InvalidOperationException("XPortal members have an unexpected shape");
			}
			Ready = true;
			WaygatePlugin.Log.LogInfo((object)"XPortal found: Waygates lead to your XPortal default portal and are kept in its portal list.");
		}
		catch (Exception ex)
		{
			WaygatePlugin.Log.LogWarning((object)("XPortal is loaded but its internals were not recognised (" + ex.Message + "); Waygates still lead to your default portal, but they are not named or aimed from home, and previous Waygates are not replaced."));
		}
	}

	internal static string Root(Exception e)
	{
		Exception ex = e;
		while (ex is TargetInvocationException && ex.InnerException != null)
		{
			ex = ex.InnerException;
		}
		return ex.GetType().Name + ": " + ex.Message;
	}

	internal static bool Knows(ZDOID id)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		object obj = Manager();
		if (obj != null)
		{
			return (bool)_containsId.Invoke(obj, new object[1] { id });
		}
		return false;
	}

	internal static bool Rename(ZDOID id, string name)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		object obj = Known(id);
		if (obj == null)
		{
			return false;
		}
		string text = _name.GetValue(obj, null) as string;
		if (!string.IsNullOrEmpty(text) && text != name)
		{
			return false;
		}
		_name.SetValue(obj, name, null);
		_addOrUpdate.Invoke(null, new object[1] { obj });
		return true;
	}

	private static MethodInfo Need(MethodInfo m, string what)
	{
		if (m == null)
		{
			throw new InvalidOperationException(what + " not found");
		}
		return m;
	}

	private static PropertyInfo NeedProperty(Type t, string name, Type type)
	{
		PropertyInfo propertyInfo = AccessTools.Property(t, name);
		if (propertyInfo == null || propertyInfo.PropertyType != type || !propertyInfo.CanRead || !propertyInfo.CanWrite)
		{
			throw new InvalidOperationException("KnownPortal." + name + " not found");
		}
		return propertyInfo;
	}

	private static object Manager()
	{
		return _instance.Invoke(null, null);
	}

	private static object Known(ZDOID id)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		object obj = Manager();
		if (obj == null || !(bool)_containsId.Invoke(obj, new object[1] { id }))
		{
			return null;
		}
		return _getById.Invoke(obj, new object[1] { id });
	}

	internal static ZDOID DefaultPortal()
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		object obj = Manager();
		if (obj == null)
		{
			return ZDOID.None;
		}
		return (ZDOID)_findDefault.Invoke(obj, null);
	}

	internal static string NameOf(ZDOID id)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		object obj = (((ZDOID)(ref id)).IsNone() ? null : Known(id));
		string text = ((obj != null) ? (_name.GetValue(obj, null) as string) : null);
		if (!string.IsNullOrEmpty(text))
		{
			return text;
		}
		return "your default portal";
	}

	internal static void Announce(ZDOID gate, Vector3 position, string name)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		object obj = _ctor.Invoke(new object[2] { gate, position });
		_name.SetValue(obj, name ?? "", null);
		_addOrUpdate.Invoke(null, new object[1] { obj });
	}

	internal static bool Aim(ZDOID portal, ZDOID target)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		object obj = Known(portal);
		if (obj == null)
		{
			return false;
		}
		_target.SetValue(obj, target, null);
		_addOrUpdate.Invoke(null, new object[1] { obj });
		return true;
	}

	internal static void Retire(ZDOID old, ZDOID newest)
	{
		//IL_0025: 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_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		object obj = Manager();
		if (obj == null)
		{
			throw new InvalidOperationException("KnownPortalsManager.Instance is null");
		}
		if (_withTarget.Invoke(obj, new object[1] { old }) is IEnumerable enumerable)
		{
			List<object> list = new List<object>();
			foreach (object item in enumerable)
			{
				list.Add(item);
			}
			for (int i = 0; i < list.Count; i++)
			{
				object obj2 = list[i];
				if (obj2 != null && !((ZDOID)_id.GetValue(obj2, null) == old) && !((ZDOID)_id.GetValue(obj2, null) == newest))
				{
					_target.SetValue(obj2, newest, null);
					_addOrUpdate.Invoke(null, new object[1] { obj2 });
				}
			}
		}
		_remove.Invoke(null, new object[1] { old });
	}
}
public static class Patches
{
	internal static FieldInfo PlayerPlacingField;

	private static bool _ghostWarned;

	private static readonly Collider[] _clipHits = (Collider[])(object)new Collider[8];

	private static int _clipMask = -1;

	private static int _groundMask = -1;

	internal static void Reset()
	{
		PlayerPlacingField = null;
		_ghostWarned = false;
	}

	internal static bool GetPlayerPlacing()
	{
		if (PlayerPlacingField != null)
		{
			return (bool)PlayerPlacingField.GetValue(null);
		}
		return false;
	}

	private static bool IsWaygate(Piece piece)
	{
		if ((Object)(object)piece == (Object)null)
		{
			return false;
		}
		string name = ((Object)((Component)piece).gameObject).name;
		if (!(name == "runemagic_waygate"))
		{
			return name == "runemagic_waygate(Clone)";
		}
		return true;
	}

	private static bool IsConjured(Component c)
	{
		ZNetView val = (((Object)(object)c != (Object)null) ? c.GetComponent<ZNetView>() : null);
		if ((Object)(object)val != (Object)null && val.IsValid())
		{
			return val.GetZDO().GetLong("danpe_waygate_creator", 0L) != 0;
		}
		return false;
	}

	public static void IsUnlockablePostfix(Piece piece, ref bool __result)
	{
		if (!__result && IsWaygate(piece))
		{
			__result = true;
		}
	}

	public static void IsUnlockedPostfix(Player player, Piece piece, ref bool __result)
	{
		if (IsWaygate(piece))
		{
			if (WaygatePlugin.NeedPortalRecipe != null && !WaygatePlugin.NeedPortalRecipe.Value)
			{
				__result = true;
			}
			else
			{
				__result = (Object)(object)player != (Object)null && WaygatePlugin.PortalPieceName.Length > 0 && player.IsRecipeKnown(WaygatePlugin.PortalPieceName);
			}
		}
	}

	public static void EnergyCostPostfix(Piece piece, ref float __result)
	{
		if (IsWaygate(piece) && WaygatePlugin.EnergyCost != null)
		{
			__result = Mathf.Max(0f, WaygatePlugin.EnergyCost.Value);
		}
	}

	public static void SetupPlacementGhostPrefix(GameObject ___m_placementGhost, out bool __state)
	{
		__state = (Object)(object)___m_placementGhost != (Object)null && (Object)(object)___m_placementGhost.GetComponent<WaygateRune>() != (Object)null;
	}

	public static void SetupPlacementGhostPostfix(GameObject ___m_placementGhost, ref int ___m_placeRotation, bool __state)
	{
		if (!__state && !((Object)(object)___m_placementGhost == (Object)null) && !((Object)(object)___m_placementGhost.GetComponent<WaygateRune>() == (Object)null) && (WaygatePlugin.AlignToView == null || WaygatePlugin.AlignToView.Value))
		{
			___m_placeRotation = 0;
		}
	}

	private static bool Clips(Vector3 pos, Quaternion rot, Bounds local)
	{
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: 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_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: 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)
		//IL_00ee: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: 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_015b: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: 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)
		//IL_016d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0172: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: 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_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_0191: Unknown result type (might be due to invalid IL or missing references)
		if (_clipMask < 0)
		{
			_clipMask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "vehicle" });
		}
		Vector3 val = default(Vector3);
		((Vector3)(ref val))..ctor(((Bounds)(ref local)).min.x + 0.2f, Mathf.Max(((Bounds)(ref local)).min.y, 0f) + 0.2f, ((Bounds)(ref local)).min.z + 0.2f);
		Vector3 val2 = ((Bounds)(ref local)).max - new Vector3(0.2f, 0.2f, 0.2f);
		if (val2.x <= val.x || val2.y <= val.y || val2.z <= val.z)
		{
			return false;
		}
		Collider val3 = null;
		RaycastHit val4 = default(RaycastHit);
		if (Physics.Raycast(pos + Vector3.up * 0.5f, Vector3.down, ref val4, 1f, _clipMask, (QueryTriggerInteraction)1) && Mathf.Abs(((RaycastHit)(ref val4)).distance - 0.5f) < 0.05f)
		{
			val3 = ((RaycastHit)(ref val4)).collider;
			ZNetView componentInParent = ((Component)val3).GetComponentInParent<ZNetView>();
			if ((Object)(object)componentInParent != (Object)null && IsConjured((Component)(object)componentInParent))
			{
				return true;
			}
		}
		Vector3 val5 = pos + rot * ((val + val2) * 0.5f);
		int num = Physics.OverlapBoxNonAlloc(val5, (val2 - val) * 0.5f, _clipHits, rot, _clipMask, (QueryTriggerInteraction)1);
		for (int i = 0; i < num; i++)
		{
			if ((Object)(object)_clipHits[i] != (Object)null && (Object)(object)_clipHits[i] != (Object)(object)val3)
			{
				return true;
			}
		}
		return false;
	}

	private static bool BlocksCharacter(Vector3 pos, Quaternion rot, Bounds local)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		List<Character> allCharacters = Character.GetAllCharacters();
		if (allCharacters == null)
		{
			return false;
		}
		Quaternion val = Quaternion.Inverse(rot);
		for (int i = 0; i < allCharacters.Count; i++)
		{
			Character val2 = allCharacters[i];
			if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.GetCollider() == (Object)null))
			{
				float num = Mathf.Max(0.4f, val2.GetRadius());
				Vector3 val3 = val * (((Component)val2).transform.position - pos);
				if (val3.x > ((Bounds)(ref local)).min.x - num && val3.x < ((Bounds)(ref local)).max.x + num && val3.z > ((Bounds)(ref local)).min.z - num && val3.z < ((Bounds)(ref local)).max.z + num && val3.y > ((Bounds)(ref local)).min.y - 2f && val3.y < ((Bounds)(ref local)).max.y)
				{
					return true;
				}
			}
		}
		return false;
	}

	private static bool Tilted(Vector3 pos)
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		if (_groundMask < 0)
		{
			_groundMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "terrain" });
		}
		RaycastHit val = default(RaycastHit);
		if (Physics.Raycast(pos + Vector3.up * 0.5f, Vector3.down, ref val, 1.5f, _groundMask, (QueryTriggerInteraction)1))
		{
			return ((RaycastHit)(ref val)).normal.y < 0.8f;
		}
		return false;
	}

	public static void PlacementGhostPostfix(bool flashGuardStone, GameObject ___m_placementGhost, ref PlacementStatus ___m_placementStatus)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: 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_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Expected I4, but got Unknown
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: 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_00f5: 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_0103: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (___m_placementStatus || (Object)(object)___m_placementGhost == (Object)null || !___m_placementGhost.activeSelf || (Object)(object)___m_placementGhost.GetComponent<WaygateRune>() == (Object)null)
			{
				return;
			}
			Layout.Poses(___m_placementGhost.transform.position, ___m_placementGhost.transform.rotation, out var portalPos, out var portalRot, out var benchPos, out var benchRot);
			PlacementStatus val = (PlacementStatus)0;
			if (Clips(portalPos, portalRot, Prefabs.PortalBounds))
			{
				val = (PlacementStatus)1;
			}
			else if (BlocksCharacter(portalPos, portalRot, Prefabs.PortalBounds))
			{
				val = (PlacementStatus)2;
			}
			else if (WaygatePlugin.Workbench == null || WaygatePlugin.Workbench.Value)
			{
				if (Location.IsInsideNoBuildLocation(benchPos))
				{
					val = (PlacementStatus)3;
				}
				else if (!PrivateArea.CheckAccess(benchPos, 0f, flashGuardStone, false))
				{
					val = (PlacementStatus)4;
				}
				else if ((Object)(object)ZoneSystem.instance != (Object)null && benchPos.y < ZoneSystem.instance.m_waterLevel - 0.3f)
				{
					val = (PlacementStatus)1;
				}
				else if (Clips(benchPos, benchRot, Prefabs.BenchBounds) || Tilted(benchPos))
				{
					val = (PlacementStatus)1;
				}
				else if (BlocksCharacter(benchPos, benchRot, Prefabs.BenchBounds))
				{
					val = (PlacementStatus)2;
				}
			}
			if ((int)val != 0)
			{
				___m_placementStatus = (PlacementStatus)(int)val;
				Piece component = ___m_placementGhost.GetComponent<Piece>();
				if ((Object)(object)component != (Object)null)
				{
					component.SetInvalidPlacementHeightlight(true);
				}
			}
		}
		catch (Exception ex)
		{
			if (!_ghostWarned)
			{
				_ghostWarned = true;
				WaygatePlugin.Log.LogWarning((object)("Waygate placement check failed: " + ex.Message));
			}
		}
	}

	public static bool DropResourcesPrefix(Piece __instance)
	{
		try
		{
			if (IsConjured((Component)(object)__instance))
			{
				return false;
			}
		}
		catch (Exception)
		{
		}
		return true;
	}

	public static void StationStartPostfix(CraftingStation __instance)
	{
		try
		{
			if ((Object)(object)__instance != (Object)null && __instance.m_craftRequireRoof && WaygatePlugin.NoRoof != null && WaygatePlugin.NoRoof.Value && IsConjured((Component)(object)__instance))
			{
				__instance.m_craftRequireRoof = false;
			}
		}
		catch (Exception)
		{
		}
	}

	public static void ZNetSceneAwakePrefix(ZNetScene __instance)
	{
		try
		{
			WaygatePlugin.OnZNetSceneAwake(__instance);
		}
		catch (Exception ex)
		{
			WaygatePlugin.Log.LogError((object)("The Waygate rune could not be prepared for this world: " + ex));
		}
	}

	public static void BoulderSetupPostfix()
	{
		try
		{
			WaygatePlugin.TryFinishPieceSetup();
		}
		catch (Exception ex)
		{
			WaygatePlugin.Log.LogError((object)("The Waygate rune could not be added to the menu: " + ex));
		}
	}
}
internal static class Icon
{
	private const int Size = 128;

	internal static Sprite Compose(Sprite portal, Sprite bench)
	{
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Expected O, but got Unknown
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)portal == (Object)null || (Object)(object)portal.texture == (Object)null || Application.isBatchMode)
		{
			return portal;
		}
		try
		{
			int width;
			int height;
			Color[] src = ReadSprite(portal, out width, out height);
			Color[] array = (Color[])(object)new Color[16384];
			Stamp(array, src, width, height, 53.76f, 71.68f, 107.52f);
			if ((Object)(object)bench != (Object)null && (Object)(object)bench.texture != (Object)null)
			{
				int width2;
				int height2;
				Color[] src2 = ReadSprite(bench, out width2, out height2);
				Stamp(array, src2, width2, height2, 94.72f, 34.56f, 66.56f);
			}
			Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false);
			((Object)val).name = "WaygateIcon";
			((Texture)val).wrapMode = (TextureWrapMode)1;
			val.SetPixels(array);
			val.Apply(false, false);
			return Sprite.Create(val, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f), 100f);
		}
		catch (Exception ex)
		{
			WaygatePlugin.Log.LogWarning((object)("Could not draw the Waygate icon, using the portal's: " + ex.Message));
			return portal;
		}
	}

	private static Color[] ReadSprite(Sprite sprite, out int width, out int height)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Expected O, but got Unknown
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		Texture texture = (Texture)(object)sprite.texture;
		Rect textureRect = sprite.textureRect;
		width = Mathf.Max(1, Mathf.RoundToInt(((Rect)(ref textureRect)).width));
		height = Mathf.Max(1, Mathf.RoundToInt(((Rect)(ref textureRect)).height));
		RenderTexture temporary = RenderTexture.GetTemporary(texture.width, texture.height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
		RenderTexture active = RenderTexture.active;
		Texture2D val = null;
		try
		{
			Graphics.Blit(texture, temporary);
			RenderTexture.active = temporary;
			val = new Texture2D(width, height, (TextureFormat)4, false);
			val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)width, (float)height), 0, 0);
			val.Apply();
			return val.GetPixels();
		}
		finally
		{
			RenderTexture.active = active;
			RenderTexture.ReleaseTemporary(temporary);
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)val);
			}
		}
	}

	private static void Stamp(Color[] dst, Color[] src, int sw, int sh, float cx, float cy, float target)
	{
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
		float num = (float)sw / (float)sh;
		float num2 = ((num >= 1f) ? target : (target * num));
		float num3 = ((num >= 1f) ? (target / num) : target);
		float num4 = cx - num2 / 2f;
		float num5 = cy - num3 / 2f;
		int num6 = Mathf.Max(0, Mathf.FloorToInt(num4));
		int num7 = Mathf.Min(128, Mathf.CeilToInt(num4 + num2));
		int num8 = Mathf.Max(0, Mathf.FloorToInt(num5));
		int num9 = Mathf.Min(128, Mathf.CeilToInt(num5 + num3));
		for (int i = num8; i < num9; i++)
		{
			float num10 = ((float)i + 0.5f - num5) / num3;
			if (num10 < 0f || num10 >= 1f)
			{
				continue;
			}
			for (int j = num6; j < num7; j++)
			{
				float num11 = ((float)j + 0.5f - num4) / num2;
				if (num11 < 0f || num11 >= 1f)
				{
					continue;
				}
				Color val = Sample(src, sw, sh, num11, num10);
				if (!(val.a <= 0f))
				{
					int num12 = i * 128 + j;
					Color val2 = dst[num12];
					float num13 = val.a + val2.a * (1f - val.a);
					if (!(num13 <= 0f))
					{
						ref Color reference = ref dst[num12];
						reference = new Color((val.r * val.a + val2.r * val2.a * (1f - val.a)) / num13, (val.g * val.a + val2.g * val2.a * (1f - val.a)) / num13, (val.b * val.a + val2.b * val2.a * (1f - val.a)) / num13, num13);
					}
				}
			}
		}
	}

	private static Color Sample(Color[] src, int sw, int sh, float u, float v)
	{
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: 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_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		float num = u * (float)sw - 0.5f;
		float num2 = v * (float)sh - 0.5f;
		int num3 = Mathf.Clamp(Mathf.FloorToInt(num), 0, sw - 1);
		int num4 = Mathf.Clamp(Mathf.FloorToInt(num2), 0, sh - 1);
		int num5 = Mathf.Min(num3 + 1, sw - 1);
		int num6 = Mathf.Min(num4 + 1, sh - 1);
		float num7 = Mathf.Clamp01(num - (float)num3);
		float num8 = Mathf.Clamp01(num2 - (float)num4);
		Color val = Color.Lerp(src[num4 * sw + num3], src[num4 * sw + num5], num7);
		Color val2 = Color.Lerp(src[num6 * sw + num3], src[num6 * sw + num5], num7);
		return Color.Lerp(val, val2, num8);
	}
}

plugins/StoneFortress.dll

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

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

[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("danpe.RuneMagicStoneFortress", "Rune Magic - Stone Fortress", "1.1.0")]
public class FortressPlugin : BaseUnityPlugin
{
	public enum ArchSide
	{
		Long,
		Short
	}

	public enum RockStyle
	{
		Megalith,
		Capstone,
		Arch
	}

	public const string PluginGuid = "danpe.RuneMagicStoneFortress";

	public const string PluginName = "Rune Magic - Stone Fortress";

	public const string PluginVersion = "1.1.0";

	internal const string RuneMagicGuid = "hyleanlegend.RuneMagic";

	internal const string CapstonePrefab = "widestone";

	internal const string CapstoneFracPrefab = "widestone_frac";

	internal const string MegalithPrefab = "HeathRockPillar";

	internal const string MegalithFracPrefab = "HeathRockPillar_frac";

	internal const string ArchPrefab = "cliff_ashlands3_Arch_1";

	internal const string CapstoneConfigName = "runemagic_stone_capstone";

	internal const string RuneName = "runemagic_stone_fortress";

	internal const string RuneCloneName = "runemagic_stone_fortress(Clone)";

	private const string RuneFocusItemName = "$item_runemagic_runefocus";

	private const int TestedMajor = 1;

	private const int TestedMinor = 5;

	internal const string DescriptionBody = "Engrave the ground where the gate should stand and a fortress of living rock rises: walls two metres thick and ten high around a twelve by eight metre hall, an arched gateway facing you and a roof of stone. Like the Capstone, it can only be undone piece by piece with a pickaxe. ";

	internal static readonly string[] FortressNames = new string[4] { "runemagic_fortress_long", "runemagic_fortress_short", "runemagic_fortress_long_roof", "runemagic_fortress_short_roof" };

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<ArchSide> GateSide;

	internal static ConfigEntry<bool> Roof;

	internal static ConfigEntry<RockStyle> Style;

	internal static ConfigEntry<bool> AlignToView;

	internal static ConfigEntry<bool> Settle;

	internal static ConfigEntry<float> RiseSeconds;

	internal static ConfigEntry<float> EnergyCost;

	internal static ConfigEntry<float> BlockHealth;

	internal static ConfigEntry<bool> DropStone;

	internal static ConfigEntry<bool> AllowUntestedVersion;

	internal static readonly Blueprint[] Plans = new Blueprint[4];

	internal static GameObject DustTemplate;

	internal static MineRock5 CapstoneRock;

	private static Harmony _harmony;

	private static GameObject _container;

	private static GameObject _runePrefab;

	private static readonly GameObject[] _fortressPrefabs = (GameObject[])(object)new GameObject[4];

	private static GameObject _capstone;

	private static Material[] _capstoneMaterials;

	private static PieceTable _table;

	private static bool _pieceConfigured;

	private static MethodInfo _getBundlePrefab;

	private static readonly DropTable NoDrops;

	private static readonly Dictionary<RockStyle, Material[]> _styleMaterials;

	private static List<GameObject> _scenePrefabs;

	internal static string CostSentence()
	{
		float num = ((EnergyCost != null) ? EnergyCost.Value : 0f);
		if (!(num > 0f))
		{
			return "Costs no runic energy.";
		}
		return "Costs " + Mathf.CeilToInt(num) + " runic energy.";
	}

	internal static int VariantIndex(ArchSide side, bool roof)
	{
		return (roof ? 2 : 0) + ((side == ArchSide.Short) ? 1 : 0);
	}

	internal static int CurrentVariant()
	{
		ArchSide side = ((GateSide != null) ? GateSide.Value : ArchSide.Long);
		bool roof = Roof == null || Roof.Value;
		return VariantIndex(side, roof);
	}

	internal static Blueprint Plan(int variant)
	{
		if (variant < 0 || variant >= Plans.Length)
		{
			return null;
		}
		return Plans[variant];
	}

	private void Awake()
	{
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Expected O, but got Unknown
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_0142: Expected O, but got Unknown
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When false the plugin does nothing at all (restart required). Multiplayer: the host AND every player need this add-on, in the same version (the rock's chunk layout must match). A host without it permanently deletes raised fortresses when their area loads (unknown prefab); a player without it sees nothing there, and while the game hands them the fortress (they are nearest) nobody's pickaxe hits on it count.");
		GateSide = ((BaseUnityPlugin)this).Config.Bind<ArchSide>("General", "Gateway in the", ArchSide.Long, "Long: the gateway is in one of the 12 m walls, so the hall is 12 m wide and 8 m deep. Short: the gateway is in one of the 8 m walls, so the hall is 8 m wide and 12 m deep. Applies to the next placement.");
		Roof = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Roof", true, "Raise the fortress with a rock roof (about 1.6 m thick, slightly domed) over the walls. Off: an open courtyard. Applies to the next placement.");
		Style = ((BaseUnityPlugin)this).Config.Bind<RockStyle>("General", "Rock style", RockStyle.Megalith, "Which natural rock the fortress looks like: Megalith (the Plains heath rock of the Megalith rune), Capstone (grey mountain rock) or Arch (the dark Ashlands rock of the Arch rune). Only the look changes - mining and drops stay the Capstone's - and each player sees their own choice. Applies to fortresses that load after the change.");
		AlignToView = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Align to your view", true, "Each time you select the rune, the gateway faces you and the fortress stretches away along your view; the scroll wheel turns it in steps from there. Off: the piece keeps Valheim's fixed world orientation and only the scroll wheel turns it.");
		Settle = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Settle to the lowest ground", true, "The walls start at the lowest ground under them, but never more than 1 m below the gate threshold (the point you aim at), so the gateway stays open; a 4 m footing buried under the walls reaches lower ground on slopes, and uphill the walls are partly buried. Off: they start exactly at the height of the point you aim at.");
		RiseSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Rise seconds", 8f, new ConfigDescription("How long the fortress takes to rise out of the ground. Everyone nearby sees the same rise.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), new object[0]));
		EnergyCost = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Energy cost", 200f, new ConfigDescription("Runic energy needed to raise the fortress (a Rune Focus holds 100 per quality level). 0 = free.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 400f), new object[0]));
		BlockHealth = ((BaseUnityPlugin)this).Config.Bind<float>("Stone", "Block health", 0f, new ConfigDescription("Health of each rock chunk. 0 = the same as a Capstone piece (30, raised by world level like any rock). Hits are settled by whichever machine currently owns the fortress (usually the player nearest it, or the host), so keep this the same for everyone. The first hit stores every chunk's health with the fortress, so a change only affects fortresses nobody has mined yet.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f), new object[0]));
		DropStone = ((BaseUnityPlugin)this).Config.Bind<bool>("Stone", "Drop stone when mined", true, "Each mined chunk drops stone like a Capstone piece (2-3). Off: mining a fortress yields nothing. Settled by whichever machine owns the fortress at the time, so keep it the same for everyone.");
		AllowUntestedVersion = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Allow untested Rune Magic version", false, "This add-on was verified against Rune Magic 1.5.x. With any other version it stays off unless this is true.");
		if (!Enabled.Value)
		{
			Log.LogWarning((object)"Stone Fortress is OFF on this game instance. If this instance is the host or server, raised fortresses are permanently deleted when their area loads.");
			return;
		}
		EnergyCost.SettingChanged += RefreshDescription;
		BlockHealth.SettingChanged += RefreshRockSettings;
		DropStone.SettingChanged += RefreshRockSettings;
		Style.SettingChanged += RefreshStyle;
		try
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			Setup();
			Log.LogInfo((object)("Stone Fortress registered (" + Plans[0].Blocks.Count + " / " + Plans[1].Blocks.Count + " / " + Plans[2].Blocks.Count + " / " + Plans[3].Blocks.Count + " chunks, layout checksum " + Geo.Checksum(Plans).ToString("X8") + ", built in " + Mathf.RoundToInt((Time.realtimeSinceStartup - realtimeSinceStartup) * 1000f) + " ms); the piece appears after the Capstone once a world is loaded. The host and every player need this add-on."));
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Setup failed - the Stone Fortress rune will not be available. Nothing else is affected. " + ex));
			Teardown();
			Log.LogWarning((object)"If this instance is the host or server, raised fortresses are permanently deleted when their area loads.");
		}
	}

	private void OnDestroy()
	{
		Teardown();
	}

	private static void Teardown()
	{
		if (EnergyCost != null)
		{
			EnergyCost.SettingChanged -= RefreshDescription;
		}
		if (BlockHealth != null)
		{
			BlockHealth.SettingChanged -= RefreshRockSettings;
		}
		if (DropStone != null)
		{
			DropStone.SettingChanged -= RefreshRockSettings;
		}
		if (Style != null)
		{
			Style.SettingChanged -= RefreshStyle;
		}
		try
		{
			if ((Object)(object)_table != (Object)null && (Object)(object)_runePrefab != (Object)null)
			{
				_table.m_pieces.Remove(_runePrefab);
			}
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				foreach (GameObject item in AllPrefabs())
				{
					ZNetScene.instance.m_prefabs.Remove(item);
				}
			}
			if ((Object)(object)_container != (Object)null)
			{
				Object.Destroy((Object)(object)_container);
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Unregister failed: " + ex.Message));
		}
		_runePrefab = null;
		for (int i = 0; i < _fortressPrefabs.Length; i++)
		{
			_fortressPrefabs[i] = null;
		}
		_capstone = null;
		_container = null;
		_table = null;
		_pieceConfigured = false;
		_styleMaterials.Clear();
		_scenePrefabs = null;
		_capstoneMaterials = null;
		DustTemplate = null;
		CapstoneRock = null;
		if (_harmony != null)
		{
			List<MethodBase> list;
			try
			{
				list = new List<MethodBase>(_harmony.GetPatchedMethods());
			}
			catch (Exception)
			{
				list = new List<MethodBase>();
			}
			foreach (MethodBase item2 in list)
			{
				try
				{
					_harmony.Unpatch(item2, (HarmonyPatchType)0, "danpe.RuneMagicStoneFortress");
				}
				catch (Exception ex3)
				{
					Log.LogWarning((object)("Unpatch failed for " + item2.Name + ": " + ex3.Message));
				}
			}
		}
		Patches.Reset();
	}

	private static List<GameObject> AllPrefabs()
	{
		List<GameObject> list = new List<GameObject>();
		if ((Object)(object)_runePrefab != (Object)null)
		{
			list.Add(_runePrefab);
		}
		for (int i = 0; i < _fortressPrefabs.Length; i++)
		{
			if ((Object)(object)_fortressPrefabs[i] != (Object)null)
			{
				list.Add(_fortressPrefabs[i]);
			}
		}
		return list;
	}

	private static void CheckRuneMagicVersion()
	{
		if (!Chainloader.PluginInfos.TryGetValue("hyleanlegend.RuneMagic", out var value) || value == null)
		{
			throw new InvalidOperationException("Rune Magic is not loaded");
		}
		Version version = value.Metadata.Version;
		if (version.Major != 1 || version.Minor != 5)
		{
			if (!AllowUntestedVersion.Value)
			{
				throw new InvalidOperationException(string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x). Set 'Allow untested Rune Magic version' to true to try anyway."));
			}
			Log.LogWarning((object)string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x); continuing because the config allows it."));
		}
	}

	private static Type RequireType(string name)
	{
		Type type = AccessTools.TypeByName(name);
		if (type == null)
		{
			throw new InvalidOperationException("Rune Magic type not found: " + name);
		}
		return type;
	}

	private static MethodInfo RequireMethod(Type t, string name, Type[] args)
	{
		MethodInfo methodInfo = ((args == null) ? AccessTools.Method(t, name, (Type[])null, (Type[])null) : AccessTools.Method(t, name, args, (Type[])null));
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Method not found: " + t.FullName + "." + name);
		}
		return methodInfo;
	}

	private static FieldInfo RequireField(Type t, string name)
	{
		FieldInfo fieldInfo = AccessTools.Field(t, name);
		if (fieldInfo == null)
		{
			throw new InvalidOperationException("Field not found: " + t.FullName + "." + name);
		}
		return fieldInfo;
	}

	private static HarmonyMethod H(string name)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(typeof(Patches), name, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Patch method missing: " + name);
		}
		return new HarmonyMethod(methodInfo);
	}

	private static void Setup()
	{
		//IL_03ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b8: Expected O, but got Unknown
		//IL_04ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b8: Expected O, but got Unknown
		CheckRuneMagicVersion();
		Type t = RequireType("ValheimMod.ValheimMod");
		MethodInfo methodInfo = RequireMethod(t, "get_isModAwake", Type.EmptyTypes);
		if (!(bool)methodInfo.Invoke(null, null))
		{
			throw new InvalidOperationException("Rune Magic did not finish initialising (isModAwake is false)");
		}
		Type t2 = RequireType("ValheimMod.UnlockManager");
		Type type = RequireType("ValheimMod.RunemagicPieceConfig");
		Type t3 = RequireType("ValheimMod.CustomContentSetupHandler");
		Type t4 = RequireType("ValheimMod.BoulderSetupHandler");
		Type t5 = RequireType("ValheimMod.PlayerPatch");
		MethodInfo methodInfo2 = RequireMethod(t2, "isUnlockable", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo3 = RequireMethod(t2, "isUnlocked", new Type[2]
		{
			typeof(Player),
			typeof(Piece)
		});
		MethodInfo methodInfo4 = RequireMethod(type, "getEnergyCost", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo5 = RequireMethod(t4, "SetUpCustomBoulderFeatures", Type.EmptyTypes);
		FieldInfo fieldInfo = RequireField(t5, "PlayerPlacing");
		if (fieldInfo.FieldType != typeof(bool) || !fieldInfo.IsStatic)
		{
			throw new InvalidOperationException("PlayerPatch.PlayerPlacing has an unexpected shape");
		}
		MethodInfo methodInfo6 = RequireMethod(typeof(ZNetScene), "Awake", Type.EmptyTypes);
		MethodInfo methodInfo7 = RequireMethod(typeof(Player), "UpdatePlacementGhost", new Type[1] { typeof(bool) });
		MethodInfo methodInfo8 = RequireMethod(typeof(Player), "SetupPlacementGhost", Type.EmptyTypes);
		MethodInfo methodInfo9 = RequireMethod(typeof(MineRock5), "RPC_Damage", new Type[3]
		{
			typeof(long),
			typeof(HitData),
			typeof(int)
		});
		ConstructorInfo constructor = type.GetConstructor(new Type[3]
		{
			typeof(Biome),
			typeof(string),
			typeof(string)
		});
		if (constructor == null)
		{
			throw new InvalidOperationException("RunemagicPieceConfig(Biome, string, string) constructor not found");
		}
		if (!(RequireField(t3, "RegisteredItemPrefabs").GetValue(null) is List<GameObject> list))
		{
			throw new InvalidOperationException("Rune Magic's item prefab list has an unexpected type");
		}
		Type type2 = AccessTools.TypeByName("ValheimMod.AssetLoader");
		_getBundlePrefab = ((type2 != null) ? AccessTools.Method(type2, "GetPrefabFromAssetBundle", new Type[1] { typeof(string) }, (Type[])null) : null);
		PieceTable val = null;
		foreach (GameObject item in list)
		{
			ItemDrop val2 = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null && val2.m_itemData.m_shared.m_name == "$item_runemagic_runefocus")
			{
				val = val2.m_itemData.m_shared.m_buildPieces;
				break;
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			throw new InvalidOperationException("Rune Focus piece table not found");
		}
		for (int i = 0; i < 4; i++)
		{
			Plans[i] = Geo.Build(((i & 1) == 1) ? ArchSide.Short : ArchSide.Long, i >= 2);
		}
		Patches.IsUnlockedOriginal = (Func<Player, Piece, bool>)Delegate.CreateDelegate(typeof(Func<Player, Piece, bool>), methodInfo3);
		Patches.PlayerPlacingField = fieldInfo;
		_harmony = new Harmony("danpe.RuneMagicStoneFortress");
		_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, H("IsUnlockablePostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, H("IsUnlockedPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, H("EnergyCostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, H("BoulderSetupPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, H("PlacementGhostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo8, H("SetupPlacementGhostPrefix"), H("SetupPlacementGhostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo9, H("MineRockDamagePrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		HarmonyMethod val3 = H("ZNetSceneAwakePrefix");
		val3.priority = 800;
		_harmony.Patch((MethodBase)methodInfo6, val3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_container = new GameObject("RuneMagicStoneFortress_Prefabs");
		_container.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)_container);
		_table = val;
		constructor.Invoke(new object[3]
		{
			(object)(Biome)8,
			"runemagic_stone_fortress",
			"runemagic_stone_capstone"
		});
	}

	internal static GameObject FindPrefab(string name)
	{
		List<GameObject> scenePrefabs = _scenePrefabs;
		if (scenePrefabs == null)
		{
			return null;
		}
		for (int i = 0; i < scenePrefabs.Count; i++)
		{
			if ((Object)(object)scenePrefabs[i] != (Object)null && ((Object)scenePrefabs[i]).name == name)
			{
				return scenePrefabs[i];
			}
		}
		return null;
	}

	internal static void OnZNetSceneAwake(ZNetScene scene)
	{
		if ((Object)(object)scene == (Object)null || scene.m_prefabs == null || (Object)(object)_container == (Object)null)
		{
			return;
		}
		_scenePrefabs = scene.m_prefabs;
		if ((Object)(object)_runePrefab == (Object)null)
		{
			GameObject val = FindPrefab("widestone");
			GameObject val2 = FindPrefab("widestone_frac");
			if ((Object)(object)val2 == (Object)null && (Object)(object)val != (Object)null)
			{
				Destructible component = val.GetComponent<Destructible>();
				val2 = (((Object)(object)component != (Object)null) ? component.m_spawnWhenDestroyed : null);
			}
			MineRock5 val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<MineRock5>() : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val3 == (Object)null || Prefabs.RendererMaterials(val2) == null)
			{
				Log.LogWarning((object)"The vanilla Capstone (widestone / widestone_frac) was not found in this scene; the Stone Fortress rune is unavailable.");
				return;
			}
			_capstone = val;
			CapstoneRock = val3;
			_capstoneMaterials = Prefabs.RendererMaterials(val2);
			Material[] array = StyleMaterials(Style.Value);
			if (array == null)
			{
				Log.LogWarning((object)"The Capstone's materials were not found; the Stone Fortress rune is unavailable.");
				_capstone = null;
				CapstoneRock = null;
				return;
			}
			GameObject[] array2 = (GameObject[])(object)new GameObject[4];
			GameObject val4 = null;
			try
			{
				for (int i = 0; i < 4; i++)
				{
					array2[i] = Prefabs.BuildFortress(FortressNames[i], Plans[i], i, array, val3, val2.layer, _container.transform);
				}
				val4 = Prefabs.BuildRune(array, _container.transform);
			}
			catch (Exception)
			{
				GameObject[] array3 = array2;
				foreach (GameObject val5 in array3)
				{
					if ((Object)(object)val5 != (Object)null)
					{
						Object.Destroy((Object)(object)val5);
					}
				}
				if ((Object)(object)val4 != (Object)null)
				{
					Object.Destroy((Object)(object)val4);
				}
				_capstone = null;
				CapstoneRock = null;
				throw;
			}
			for (int k = 0; k < 4; k++)
			{
				_fortressPrefabs[k] = array2[k];
			}
			_runePrefab = val4;
			DustTemplate = Prefabs.BuildDust(_getBundlePrefab, _container.transform);
			Log.LogInfo((object)string.Concat("Stone Fortress prefabs built (", Style.Value, " rock)", ((Object)(object)DustTemplate == (Object)null) ? "; no dust effect: Rune Magic's vfx_DustCloud not found." : "."));
		}
		foreach (GameObject item in AllPrefabs())
		{
			if (!scene.m_prefabs.Contains(item))
			{
				scene.m_prefabs.Add(item);
			}
		}
		TryFinishPieceSetup();
	}

	internal static void TryFinishPieceSetup()
	{
		if ((Object)(object)_runePrefab == (Object)null || (Object)(object)_capstone == (Object)null || (Object)(object)_table == (Object)null)
		{
			return;
		}
		Piece component = _capstone.GetComponent<Piece>();
		if ((Object)(object)component == (Object)null)
		{
			return;
		}
		Piece component2 = _runePrefab.GetComponent<Piece>();
		if ((Object)(object)component2 == (Object)null)
		{
			return;
		}
		if (!_pieceConfigured)
		{
			Prefabs.ConfigurePiece(component2, component, StyleIcon(Style.Value, component.m_icon));
			_pieceConfigured = true;
		}
		List<GameObject> pieces = _table.m_pieces;
		int num = pieces.IndexOf(_capstone);
		if (num < 0)
		{
			return;
		}
		for (int num2 = pieces.Count - 1; num2 >= 0; num2--)
		{
			GameObject val = pieces[num2];
			if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)_runePrefab && ((Object)val).name == "runemagic_stone_fortress")
			{
				pieces.RemoveAt(num2);
			}
		}
		if (!pieces.Contains(_runePrefab))
		{
			num = pieces.IndexOf(_capstone);
			pieces.Insert(num + 1, _runePrefab);
			Log.LogInfo((object)"Stone Fortress added to the Rune Focus menu after the Capstone.");
		}
	}

	internal static GameObject FortressPrefab(int variant)
	{
		if (variant < 0 || variant >= _fortressPrefabs.Length)
		{
			return null;
		}
		return _fortressPrefabs[variant];
	}

	internal static Material[] StyleMaterials(RockStyle style)
	{
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Expected O, but got Unknown
		//IL_0115: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		if (_styleMaterials.TryGetValue(style, out var value))
		{
			return value;
		}
		Material[] capstoneMaterials = _capstoneMaterials;
		if (capstoneMaterials == null)
		{
			return null;
		}
		Material val = null;
		float num = 11f;
		Material val2 = ((capstoneMaterials.Length > 1) ? capstoneMaterials[1] : capstoneMaterials[0]);
		switch (style)
		{
		case RockStyle.Megalith:
		{
			Material[] array2 = Prefabs.RendererMaterials(FindPrefab("HeathRockPillar_frac"));
			if (array2 == null)
			{
				array2 = Prefabs.RendererMaterials(FindPrefab("HeathRockPillar"));
			}
			if (array2 != null)
			{
				val = array2[0];
				num = 59f;
			}
			break;
		}
		case RockStyle.Arch:
		{
			Material[] array = Prefabs.RendererMaterials(FindPrefab("cliff_ashlands3_Arch_1"));
			if (array != null)
			{
				val = array[0];
				num = 59f;
			}
			break;
		}
		}
		if ((Object)(object)val == (Object)null)
		{
			if (style != RockStyle.Capstone)
			{
				Log.LogWarning((object)string.Concat("The ", style, " rock was not found; using the Capstone's look."));
			}
			val = capstoneMaterials[0];
			num = 11f;
		}
		Material val3 = new Material(val);
		((Object)val3).name = ((Object)val).name + " (Stone Fortress)";
		float num2 = 10f / num;
		string[] texturePropertyNames = val.GetTexturePropertyNames();
		foreach (string text in texturePropertyNames)
		{
			if (val.HasProperty(text))
			{
				val3.SetTextureScale(text, val.GetTextureScale(text) * num2);
			}
		}
		Material[] array3 = (Material[])(object)new Material[2]
		{
			val3,
			(style == RockStyle.Arch) ? val3 : val2
		};
		_styleMaterials[style] = array3;
		return array3;
	}

	private static Sprite StyleIcon(RockStyle style, Sprite fallback)
	{
		GameObject val = FindPrefab(style switch
		{
			RockStyle.Arch => "cliff_ashlands3_Arch_1", 
			RockStyle.Megalith => "HeathRockPillar", 
			_ => "widestone", 
		});
		Piece val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Piece>() : null);
		Sprite source = (((Object)(object)val2 != (Object)null && (Object)(object)val2.m_icon != (Object)null) ? val2.m_icon : fallback);
		return Icon.Compose(source);
	}

	private static void RefreshStyle(object sender, EventArgs e)
	{
		try
		{
			if ((Object)(object)_runePrefab == (Object)null)
			{
				return;
			}
			Material[] array = StyleMaterials(Style.Value);
			if (array == null)
			{
				return;
			}
			foreach (GameObject item in AllPrefabs())
			{
				MeshRenderer[] componentsInChildren = item.GetComponentsInChildren<MeshRenderer>(true);
				foreach (MeshRenderer val in componentsInChildren)
				{
					((Renderer)val).sharedMaterials = array;
				}
			}
			Piece component = _runePrefab.GetComponent<Piece>();
			if ((Object)(object)component != (Object)null && _pieceConfigured && (Object)(object)_capstone != (Object)null)
			{
				Piece component2 = _capstone.GetComponent<Piece>();
				component.m_icon = StyleIcon(Style.Value, ((Object)(object)component2 != (Object)null) ? component2.m_icon : component.m_icon);
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Could not switch the rock style: " + ex.Message));
		}
	}

	private static void RefreshDescription(object sender, EventArgs e)
	{
		if (!((Object)(object)_runePrefab == (Object)null))
		{
			Piece component = _runePrefab.GetComponent<Piece>();
			if ((Object)(object)component != (Object)null && _pieceConfigured)
			{
				component.m_description = "Engrave the ground where the gate should stand and a fortress of living rock rises: walls two metres thick and ten high around a twelve by eight metre hall, an arched gateway facing you and a roof of stone. Like the Capstone, it can only be undone piece by piece with a pickaxe. " + CostSentence();
			}
		}
	}

	private static void RefreshRockSettings(object sender, EventArgs e)
	{
		GameObject[] fortressPrefabs = _fortressPrefabs;
		foreach (GameObject val in fortressPrefabs)
		{
			MineRock5 val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<MineRock5>() : null);
			if ((Object)(object)val2 != (Object)null && (Object)(object)CapstoneRock != (Object)null)
			{
				ApplyRockSettings(val2, CapstoneRock);
			}
		}
	}

	internal static void ApplyRockSettings(MineRock5 target, MineRock5 capstone)
	{
		float num = ((BlockHealth != null) ? BlockHealth.Value : 0f);
		target.m_health = ((num > 0f) ? num : capstone.m_health);
		target.m_dropItems = ((DropStone == null || DropStone.Value) ? capstone.m_dropItems : NoDrops);
	}

	static FortressPlugin()
	{
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Expected O, but got Unknown
		DropTable val = new DropTable();
		val.m_dropMin = 0;
		val.m_dropMax = 0;
		NoDrops = val;
		_styleMaterials = new Dictionary<RockStyle, Material[]>();
	}
}
internal sealed class MeshData
{
	internal sealed class OuterFan
	{
		internal int Start;

		internal int Count;

		internal Vector3 FaceNormal;

		internal Vector3[] Weights;
	}

	internal readonly List<Vector3> Verts = new List<Vector3>();

	internal readonly List<Vector3> Normals = new List<Vector3>();

	internal readonly List<Vector2> Uvs = new List<Vector2>();

	internal readonly List<int> Outer = new List<int>();

	internal readonly List<int> Inner = new List<int>();

	internal readonly List<OuterFan> Fans = new List<OuterFan>();

	internal void AddPolygon(List<Vector3> pts, Vector3 n, bool outer, Blueprint bp)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: 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)
		//IL_0049: 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)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: 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_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_011b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_0159: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0191: Unknown result type (might be due to invalid IL or missing references)
		//IL_019e: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_029c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0297: Unknown result type (might be due to invalid IL or missing references)
		//IL_0201: Unknown result type (might be due to invalid IL or missing references)
		//IL_0203: Unknown result type (might be due to invalid IL or missing references)
		//IL_0205: Unknown result type (might be due to invalid IL or missing references)
		//IL_020a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0215: Unknown result type (might be due to invalid IL or missing references)
		//IL_021a: Unknown result type (might be due to invalid IL or missing references)
		//IL_021c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0221: Unknown result type (might be due to invalid IL or missing references)
		//IL_0230: Unknown result type (might be due to invalid IL or missing references)
		//IL_0235: Unknown result type (might be due to invalid IL or missing references)
		//IL_0237: Unknown result type (might be due to invalid IL or missing references)
		//IL_023c: Unknown result type (might be due to invalid IL or missing references)
		//IL_024b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0250: Unknown result type (might be due to invalid IL or missing references)
		//IL_0252: Unknown result type (might be due to invalid IL or missing references)
		//IL_0257: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
		int count = pts.Count;
		if (count < 3)
		{
			return;
		}
		Vector3 val = Vector3.zero;
		for (int i = 0; i < count; i++)
		{
			val += pts[i];
		}
		val /= (float)count;
		Vector3 val2 = Vector3.zero;
		for (int j = 0; j < count; j++)
		{
			val2 += Vector3.Cross(pts[j] - val, pts[(j + 1) % count] - val);
		}
		bool flag = Vector3.Dot(val2, n) < 0f;
		int count2 = Verts.Count;
		Vector3[] array = (Vector3[])(object)new Vector3[count + 1];
		ref Vector3 reference = ref array[0];
		reference = Geo.Deform(bp, val);
		for (int k = 0; k < count; k++)
		{
			ref Vector3 reference2 = ref array[k + 1];
			reference2 = Geo.Deform(bp, pts[k]);
		}
		for (int l = 0; l <= count; l++)
		{
			Verts.Add(array[l]);
			Normals.Add(n);
			Uvs.Add(Uv(array[l], n));
		}
		List<int> list = (outer ? Outer : Inner);
		Vector3[] array2 = (Vector3[])(object)(outer ? new Vector3[count + 1] : null);
		Vector3 val3 = Vector3.zero;
		for (int m = 0; m < count; m++)
		{
			int num = 1 + m;
			int num2 = 1 + (m + 1) % count;
			if (flag)
			{
				int num3 = num;
				num = num2;
				num2 = num3;
			}
			Vector3 val4 = Vector3.Cross(array[num] - array[0], array[num2] - array[0]);
			if (!(((Vector3)(ref val4)).sqrMagnitude < 1E-12f))
			{
				list.Add(count2);
				list.Add(count2 + num);
				list.Add(count2 + num2);
				if (outer)
				{
					val3 += val4;
					ref Vector3 reference3 = ref array2[0];
					reference3 += val4;
					ref Vector3 reference4 = ref array2[num];
					reference4 += val4;
					ref Vector3 reference5 = ref array2[num2];
					reference5 += val4;
				}
			}
		}
		if (outer)
		{
			OuterFan outerFan = new OuterFan();
			outerFan.Start = count2;
			outerFan.Count = count + 1;
			outerFan.FaceNormal = ((((Vector3)(ref val3)).sqrMagnitude > 1E-12f) ? ((Vector3)(ref val3)).normalized : n);
			outerFan.Weights = array2;
			Fans.Add(outerFan);
		}
	}

	private static Vector2 Uv(Vector3 p, Vector3 n)
	{
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		float num = Mathf.Abs(n.x);
		float num2 = Mathf.Abs(n.y);
		float num3 = Mathf.Abs(n.z);
		float num4 = 0.1f;
		if (num2 >= num && num2 >= num3)
		{
			return new Vector2(p.x * num4, p.z * num4);
		}
		if (num >= num3)
		{
			return new Vector2(p.z * num4, p.y * num4);
		}
		return new Vector2(p.x * num4, p.y * num4);
	}

	internal void Append(MeshData other)
	{
		int count = Verts.Count;
		Verts.AddRange(other.Verts);
		Normals.AddRange(other.Normals);
		Uvs.AddRange(other.Uvs);
		for (int i = 0; i < other.Outer.Count; i++)
		{
			Outer.Add(other.Outer[i] + count);
		}
		for (int j = 0; j < other.Inner.Count; j++)
		{
			Inner.Add(other.Inner[j] + count);
		}
	}

	internal Bounds GetBounds()
	{
		//IL_001e: 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_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		Bounds result = default(Bounds);
		((Bounds)(ref result))..ctor((Verts.Count > 0) ? Verts[0] : Vector3.zero, Vector3.zero);
		for (int i = 1; i < Verts.Count; i++)
		{
			((Bounds)(ref result)).Encapsulate(Verts[i]);
		}
		return result;
	}

	internal Mesh ToMesh(string name)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		Mesh val = new Mesh();
		((Object)val).name = name;
		if (Verts.Count > 65000)
		{
			val.indexFormat = (IndexFormat)1;
		}
		val.SetVertices(Verts);
		val.SetNormals(Normals);
		val.SetUVs(0, Uvs);
		val.subMeshCount = 2;
		val.SetTriangles(Outer, 0);
		val.SetTriangles(Inner, 1);
		val.RecalculateBounds();
		val.RecalculateTangents();
		return val;
	}
}
internal sealed class PolyFace
{
	internal const int Surface = -1;

	internal const int Seam = -2;

	internal List<Vector3> Pts;

	internal Vector3 N;

	internal int Tag;

	internal PolyFace(List<Vector3> pts, Vector3 n, int tag)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		Pts = pts;
		N = n;
		Tag = tag;
	}
}
internal sealed class Poly
{
	private const float Eps = 1E-05f;

	internal List<PolyFace> Faces = new List<PolyFace>();

	internal Bounds Box;

	internal Poly Clone()
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		Poly poly = new Poly();
		poly.Box = Box;
		for (int i = 0; i < Faces.Count; i++)
		{
			poly.Faces.Add(new PolyFace(new List<Vector3>(Faces[i].Pts), Faces[i].N, Faces[i].Tag));
		}
		return poly;
	}

	internal static Poly FromBox(Vector3 min, Vector3 max)
	{
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: 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)
		//IL_00b4: 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)
		//IL_00cc: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: 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_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0144: 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_0156: Unknown result type (might be due to invalid IL or missing references)
		//IL_0172: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: Unknown result type (might be due to invalid IL or missing references)
		//IL_018b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0204: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_021d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0222: Unknown result type (might be due to invalid IL or missing references)
		//IL_0236: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_0264: Unknown result type (might be due to invalid IL or missing references)
		//IL_0269: Unknown result type (might be due to invalid IL or missing references)
		//IL_027d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0282: Unknown result type (might be due to invalid IL or missing references)
		//IL_0296: Unknown result type (might be due to invalid IL or missing references)
		//IL_029b: Unknown result type (might be due to invalid IL or missing references)
		//IL_02af: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0314: Unknown result type (might be due to invalid IL or missing references)
		//IL_0328: Unknown result type (might be due to invalid IL or missing references)
		//IL_032d: Unknown result type (might be due to invalid IL or missing references)
		//IL_033a: Unknown result type (might be due to invalid IL or missing references)
		//IL_033b: Unknown result type (might be due to invalid IL or missing references)
		//IL_033c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0346: Unknown result type (might be due to invalid IL or missing references)
		//IL_034b: Unknown result type (might be due to invalid IL or missing references)
		//IL_034c: Unknown result type (might be due to invalid IL or missing references)
		//IL_034d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0352: Unknown result type (might be due to invalid IL or missing references)
		//IL_0357: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		Poly poly = new Poly();
		Vector3[] array = (Vector3[])(object)new Vector3[8];
		for (int i = 0; i < 8; i++)
		{
			ref Vector3 reference = ref array[i];
			reference = new Vector3(((i & 1) == 0) ? min.x : max.x, ((i & 2) == 0) ? min.y : max.y, ((i & 4) == 0) ? min.z : max.z);
		}
		poly.Add(Vector3.left, array[0], array[2], array[6], array[4]);
		poly.Add(Vector3.right, array[1], array[5], array[7], array[3]);
		poly.Add(Vector3.down, array[0], array[4], array[5], array[1]);
		poly.Add(Vector3.up, array[2], array[3], array[7], array[6]);
		poly.Add(Vector3.back, array[0], array[1], array[3], array[2]);
		poly.Add(Vector3.forward, array[4], array[6], array[7], array[5]);
		poly.Box = new Bounds((min + max) * 0.5f, max - min);
		return poly;
	}

	internal static Poly FromPrism(Vector2 a, Vector2 b, Vector2 c, float z0, float z1)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//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_0113: 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_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_013a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0154: Unknown result type (might be due to invalid IL or missing references)
		//IL_0159: Unknown result type (might be due to invalid IL or missing references)
		//IL_0166: Unknown result type (might be due to invalid IL or missing references)
		//IL_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_016d: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Unknown result type (might be due to invalid IL or missing references)
		//IL_0195: 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_0199: Unknown result type (might be due to invalid IL or missing references)
		//IL_019b: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_0291: Unknown result type (might be due to invalid IL or missing references)
		//IL_0296: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cd: 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_02f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01db: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0204: Unknown result type (might be due to invalid IL or missing references)
		//IL_0220: Unknown result type (might be due to invalid IL or missing references)
		//IL_0225: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0247: Unknown result type (might be due to invalid IL or missing references)
		//IL_0264: Unknown result type (might be due to invalid IL or missing references)
		//IL_0269: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
		Poly poly = new Poly();
		Vector2[] array = (Vector2[])(object)new Vector2[3] { a, b, c };
		Vector2 val = (a + b + c) / 3f;
		poly.Add(Vector3.back, new Vector3(a.x, a.y, z0), new Vector3(b.x, b.y, z0), new Vector3(c.x, c.y, z0));
		poly.Add(Vector3.forward, new Vector3(a.x, a.y, z1), new Vector3(c.x, c.y, z1), new Vector3(b.x, b.y, z1));
		for (int i = 0; i < 3; i++)
		{
			Vector2 val2 = array[i];
			Vector2 val3 = array[(i + 1) % 3];
			Vector2 val4 = val3 - val2;
			Vector2 val5 = new Vector2(val4.y, 0f - val4.x);
			Vector2 val6 = ((Vector2)(ref val5)).normalized;
			if (Vector2.Dot(val6, (val2 + val3) * 0.5f - val) < 0f)
			{
				val6 = -val6;
			}
			poly.Add(new Vector3(val6.x, val6.y, 0f), new Vector3(val2.x, val2.y, z0), new Vector3(val3.x, val3.y, z0), new Vector3(val3.x, val3.y, z1), new Vector3(val2.x, val2.y, z1));
		}
		Bounds box = default(Bounds);
		((Bounds)(ref box))..ctor(new Vector3(a.x, a.y, z0), Vector3.zero);
		((Bounds)(ref box)).Encapsulate(new Vector3(b.x, b.y, z0));
		((Bounds)(ref box)).Encapsulate(new Vector3(c.x, c.y, z1));
		((Bounds)(ref box)).Encapsulate(new Vector3(a.x, a.y, z1));
		poly.Box = box;
		return poly;
	}

	private void Add(Vector3 n, params Vector3[] pts)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		Faces.Add(new PolyFace(new List<Vector3>(pts), n, -1));
	}

	internal bool Clip(Vector3 n, float d, int tag)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: 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)
		//IL_00cb: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a1: 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_013d: 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_0141: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: 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_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		bool flag = false;
		bool flag2 = false;
		for (int i = 0; i < Faces.Count; i++)
		{
			List<Vector3> pts = Faces[i].Pts;
			for (int j = 0; j < pts.Count; j++)
			{
				float num = Vector3.Dot(n, pts[j]) - d;
				if (num > 1E-05f)
				{
					flag = true;
				}
				else if (num < -1E-05f)
				{
					flag2 = true;
				}
			}
		}
		if (!flag)
		{
			return true;
		}
		if (!flag2)
		{
			Faces.Clear();
			return false;
		}
		List<PolyFace> list = new List<PolyFace>();
		List<Vector3> list2 = new List<Vector3>();
		for (int k = 0; k < Faces.Count; k++)
		{
			List<Vector3> pts2 = Faces[k].Pts;
			List<Vector3> list3 = new List<Vector3>();
			int count = pts2.Count;
			for (int l = 0; l < count; l++)
			{
				Vector3 val = pts2[l];
				Vector3 val2 = pts2[(l + 1) % count];
				float num2 = Vector3.Dot(n, val) - d;
				float num3 = Vector3.Dot(n, val2) - d;
				if (num2 <= 1E-05f)
				{
					list3.Add(val);
					if (num2 >= -1E-05f)
					{
						list2.Add(val);
					}
				}
				if ((num2 < -1E-05f && num3 > 1E-05f) || (num2 > 1E-05f && num3 < -1E-05f))
				{
					Vector3 item = val + (val2 - val) * (num2 / (num2 - num3));
					list3.Add(item);
					list2.Add(item);
				}
			}
			list3 = Unique(list3);
			if (list3.Count >= 3)
			{
				list.Add(new PolyFace(list3, Faces[k].N, Faces[k].Tag));
			}
		}
		list2 = Unique(list2);
		if (list2.Count >= 3)
		{
			Order(list2, n);
			list.Add(new PolyFace(list2, n, tag));
		}
		Faces = list;
		return Faces.Count >= 4;
	}

	private static List<Vector3> Unique(List<Vector3> pts)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: 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)
		List<Vector3> list = new List<Vector3>();
		for (int i = 0; i < pts.Count; i++)
		{
			bool flag = false;
			for (int j = 0; j < list.Count; j++)
			{
				Vector3 val = list[j] - pts[i];
				if (((Vector3)(ref val)).sqrMagnitude < 1E-08f)
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				list.Add(pts[i]);
			}
		}
		return list;
	}

	private static void Order(List<Vector3> pts, Vector3 n)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: 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_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: 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_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: 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_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: 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_009e: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = Vector3.zero;
		for (int i = 0; i < pts.Count; i++)
		{
			val += pts[i];
		}
		val /= (float)pts.Count;
		Vector3 val2 = Vector3.Cross(n, (Mathf.Abs(n.y) < 0.9f) ? Vector3.up : Vector3.right);
		Vector3 normalized = ((Vector3)(ref val2)).normalized;
		Vector3 val3 = Vector3.Cross(n, normalized);
		float[] array = new float[pts.Count];
		Vector3[] array2 = pts.ToArray();
		for (int j = 0; j < array2.Length; j++)
		{
			Vector3 val4 = array2[j] - val;
			array[j] = Mathf.Atan2(Vector3.Dot(val4, val3), Vector3.Dot(val4, normalized));
		}
		Array.Sort(array, array2);
		pts.Clear();
		pts.AddRange(array2);
	}
}
internal sealed class Welder
{
	private readonly float _tol;

	private readonly float _cell;

	private readonly Dictionary<long, List<Vector3>> _grid = new Dictionary<long, List<Vector3>>();

	internal Welder(float tolerance)
	{
		_tol = tolerance;
		_cell = tolerance * 2f;
	}

	private long Key(int x, int y, int z)
	{
		return ((long)x * 73856093L) ^ ((long)y * 19349663L) ^ ((long)z * 83492791L);
	}

	internal Vector3 Weld(Vector3 p)
	{
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: 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)
		int num = Mathf.FloorToInt(p.x / _cell);
		int num2 = Mathf.FloorToInt(p.y / _cell);
		int num3 = Mathf.FloorToInt(p.z / _cell);
		float num4 = _tol * _tol;
		for (int i = -1; i <= 1; i++)
		{
			for (int j = -1; j <= 1; j++)
			{
				for (int k = -1; k <= 1; k++)
				{
					if (!_grid.TryGetValue(Key(num + i, num2 + j, num3 + k), out var value))
					{
						continue;
					}
					for (int l = 0; l < value.Count; l++)
					{
						Vector3 val = value[l] - p;
						if (((Vector3)(ref val)).sqrMagnitude <= num4)
						{
							return value[l];
						}
					}
				}
			}
		}
		long key = Key(num, num2, num3);
		if (!_grid.TryGetValue(key, out var value2))
		{
			value2 = new List<Vector3>();
			_grid[key] = value2;
		}
		value2.Add(p);
		return p;
	}

	internal List<Vector3> WeldPolygon(List<Vector3> pts)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		List<Vector3> list = new List<Vector3>();
		for (int i = 0; i < pts.Count; i++)
		{
			Vector3 val = Weld(pts[i]);
			if (list.Count == 0 || list[list.Count - 1] != val)
			{
				list.Add(val);
			}
		}
		while (list.Count > 1 && list[0] == list[list.Count - 1])
		{
			list.RemoveAt(list.Count - 1);
		}
		return list;
	}
}
internal sealed class BlockDef
{
	internal MeshData Data;

	internal Mesh Mesh;
}
internal sealed class Blueprint
{
	internal FortressPlugin.ArchSide Side;

	internal bool Roof;

	internal float HalfX;

	internal float HalfZ;

	internal float Top;

	internal readonly List<BlockDef> Blocks = new List<BlockDef>();

	internal readonly List<Vector3> GroundSamples = new List<Vector3>();

	internal readonly List<Vector3> WardSamples = new List<Vector3>();

	internal readonly List<Vector3> DustPoints = new List<Vector3>();

	internal Mesh GhostMesh;

	internal float MinY;

	internal float MaxY;

	internal float OuterHalfX => HalfX + 2f;

	internal float OuterHalfZ => HalfZ + 2f;

	internal float RiseDepth => MaxY - MinY;
}
internal static class Geo
{
	private struct PosKey : IEquatable<PosKey>
	{
		private readonly int _x;

		private readonly int _y;

		private readonly int _z;

		internal PosKey(Vector3 p)
		{
			_x = Mathf.RoundToInt(p.x * 1000f);
			_y = Mathf.RoundToInt(p.y * 1000f);
			_z = Mathf.RoundToInt(p.z * 1000f);
		}

		public bool Equals(PosKey o)
		{
			if (_x == o._x && _y == o._y)
			{
				return _z == o._z;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj is PosKey)
			{
				return Equals((PosKey)obj);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (_x * 73856093) ^ (_y * 19349663) ^ (_z * 83492791);
		}
	}

	private struct Contribution
	{
		internal Vector3 Face;

		internal Vector3 Weight;
	}

	internal const float Thickness = 2f;

	internal const float Height = 10f;

	internal const float Footing = 4f;

	internal const float RoofThickness = 1.6f;

	internal const float GateHalf = 2f;

	internal const float Spring = 3f;

	internal const float GateRadius = 2f;

	internal const int ArcSegments = 8;

	internal const float RoundRadius = 1.2f;

	internal const float Dome = 1f;

	internal const float UvMetres = 10f;

	private const float NoiseAmp1 = 0.45f;

	private const float NoiseScale1 = 3.2f;

	private const float NoiseAmp2 = 0.13f;

	private const float NoiseScale2 = 1.3f;

	private const float MaxReach = 3.3f;

	internal static bool DebugNoDeform;

	internal static uint Checksum(Blueprint[] plans)
	{
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: 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)
		uint num = 2166136261u;
		for (int i = 0; i < plans.Length; i++)
		{
			List<BlockDef> blocks = plans[i].Blocks;
			num = (num ^ (uint)blocks.Count) * 16777619;
			for (int j = 0; j < blocks.Count; j++)
			{
				List<Vector3> verts = blocks[j].Data.Verts;
				num = (num ^ (uint)verts.Count) * 16777619;
				for (int k = 0; k < verts.Count; k += 7)
				{
					num = (num ^ (uint)Mathf.RoundToInt(verts[k].x * 1000f)) * 16777619;
					num = (num ^ (uint)Mathf.RoundToInt(verts[k].y * 1000f)) * 16777619;
					num = (num ^ (uint)Mathf.RoundToInt(verts[k].z * 1000f)) * 16777619;
				}
			}
		}
		return num;
	}

	internal static Blueprint Build(FortressPlugin.ArchSide side, bool roof)
	{
		Blueprint blueprint = Layout(side, roof);
		MeshData meshData = new MeshData();
		string text = ((side == FortressPlugin.ArchSide.Long) ? "L" : "S") + (roof ? "R" : "");
		for (int i = 0; i < blueprint.Blocks.Count; i++)
		{
			BlockDef blockDef = blueprint.Blocks[i];
			blockDef.Mesh = blockDef.Data.ToMesh("FortressRock_" + text + "_" + i.ToString("D3"));
			meshData.Append(blockDef.Data);
		}
		blueprint.GhostMesh = meshData.ToMesh("FortressGhost_" + text);
		return blueprint;
	}

	internal static Blueprint Layout(FortressPlugin.ArchSide side, bool roof)
	{
		//IL_0093: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: 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_0283: Unknown result type (might be due to invalid IL or missing references)
		//IL_0346: Unknown result type (might be due to invalid IL or missing references)
		//IL_0365: Unknown result type (might be due to invalid IL or missing references)
		//IL_048c: Unknown result type (might be due to invalid IL or missing references)
		//IL_049b: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_04be: Unknown result type (might be due to invalid IL or missing references)
		//IL_04d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0506: 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)
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_016e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0173: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: Unknown result type (might be due to invalid IL or missing references)
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_0188: 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)
		//IL_0408: Unknown result type (might be due to invalid IL or missing references)
		//IL_0428: Unknown result type (might be due to invalid IL or missing references)
		Blueprint blueprint = new Blueprint();
		blueprint.Side = side;
		blueprint.Roof = roof;
		blueprint.HalfX = ((side == FortressPlugin.ArchSide.Long) ? 6f : 4f);
		blueprint.HalfZ = ((side == FortressPlugin.ArchSide.Long) ? 4f : 6f);
		blueprint.Top = (roof ? 11.6f : 10f);
		List<Poly> list = Pieces(blueprint);
		List<Vector3> list2 = Seeds(blueprint, ((side == FortressPlugin.ArchSide.Long) ? 1301 : 1733) + (roof ? 57 : 0));
		float num = Reach(blueprint, list2);
		List<List<PolyFace>> list3 = new List<List<PolyFace>>();
		for (int i = 0; i < list2.Count; i++)
		{
			Vector3 val = list2[i];
			List<int> list4 = new List<int>();
			List<float> list5 = new List<float>();
			for (int j = 0; j < list2.Count; j++)
			{
				Vector3 val2 = list2[j] - val;
				float magnitude = ((Vector3)(ref val2)).magnitude;
				if (j != i && magnitude <= 2f * num + 0.2f)
				{
					list4.Add(j);
					list5.Add(magnitude);
				}
			}
			int[] array = list4.ToArray();
			Array.Sort(list5.ToArray(), array);
			List<PolyFace> list6 = new List<PolyFace>();
			for (int k = 0; k < list.Count; k++)
			{
				if (DistanceToBox(list[k].Box, val) > num + 0.1f)
				{
					continue;
				}
				Poly poly = list[k].Clone();
				bool flag = true;
				for (int l = 0; l < array.Length; l++)
				{
					if (!flag)
					{
						break;
					}
					Vector3 val3 = list2[array[l]];
					Vector3 val4 = val3 - val;
					Vector3 normalized = ((Vector3)(ref val4)).normalized;
					flag = poly.Clip(normalized, Vector3.Dot(normalized, (val3 + val) * 0.5f), array[l]);
				}
				if (flag)
				{
					list6.AddRange(poly.Faces);
				}
			}
			list6.RemoveAll((PolyFace face) => face.Tag == -2);
			if (list6.Count > 0)
			{
				list3.Add(list6);
			}
		}
		Welder welder = new Welder(0.002f);
		for (int num2 = 0; num2 < list3.Count; num2++)
		{
			MeshData meshData = new MeshData();
			List<PolyFace> list7 = list3[num2];
			for (int num3 = 0; num3 < list7.Count; num3++)
			{
				List<Vector3> list8 = welder.WeldPolygon(list7[num3].Pts);
				if (list8.Count >= 3)
				{
					meshData.AddPolygon(list8, list7[num3].N, list7[num3].Tag == -1, blueprint);
				}
			}
			if (meshData.Outer.Count + meshData.Inner.Count != 0)
			{
				BlockDef blockDef = new BlockDef();
				blockDef.Data = meshData;
				blueprint.Blocks.Add(blockDef);
			}
		}
		SmoothSurface(blueprint);
		blueprint.MinY = float.MaxValue;
		blueprint.MaxY = float.MinValue;
		for (int num4 = 0; num4 < blueprint.Blocks.Count; num4++)
		{
			List<Vector3> verts = blueprint.Blocks[num4].Data.Verts;
			for (int num5 = 0; num5 < verts.Count; num5++)
			{
				blueprint.MinY = Mathf.Min(blueprint.MinY, verts[num5].y);
				blueprint.MaxY = Mathf.Max(blueprint.MaxY, verts[num5].y);
			}
		}
		float outerHalfX = blueprint.OuterHalfX;
		float outerHalfZ = blueprint.OuterHalfZ;
		for (float num6 = 0f - outerHalfX; num6 <= outerHalfX + 0.01f; num6 += 2f)
		{
			for (float num7 = 0f - outerHalfZ; num7 <= outerHalfZ + 0.01f; num7 += 2f)
			{
				bool flag2 = Mathf.Abs(num6) >= blueprint.HalfX - 0.01f || Mathf.Abs(num7) >= blueprint.HalfZ - 0.01f;
				if (flag2)
				{
					blueprint.GroundSamples.Add(new Vector3(num6, 0f, num7));
				}
				if (flag2 || roof)
				{
					blueprint.WardSamples.Add(new Vector3(num6, 0f, num7));
				}
			}
		}
		float num8 = blueprint.HalfX + 1f;
		float num9 = blueprint.HalfZ + 1f;
		AddDustLine(blueprint, new Vector3(0f - num8, 0f, 0f - num9), new Vector3(num8, 0f, 0f - num9));
		AddDustLine(blueprint, new Vector3(num8, 0f, 0f - num9), new Vector3(num8, 0f, num9));
		AddDustLine(blueprint, new Vector3(num8, 0f, num9), new Vector3(0f - num8, 0f, num9));
		AddDustLine(blueprint, new Vector3(0f - num8, 0f, num9), new Vector3(0f - num8, 0f, 0f - num9));
		return blueprint;
	}

	private static void AddDustLine(Blueprint bp, Vector3 a, Vector3 b)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		int num = Mathf.Max(2, Mathf.RoundToInt(Vector3.Distance(a, b) / 3.5f));
		for (int i = 0; i < num; i++)
		{
			bp.DustPoints.Add(Vector3.Lerp(a, b, ((float)i + 0.5f) / (float)num));
		}
	}

	private static List<Poly> Pieces(Blueprint bp)
	{
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: 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_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: 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_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01af: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
		float halfX = bp.HalfX;
		float halfZ = bp.HalfZ;
		float outerHalfX = bp.OuterHalfX;
		float outerHalfZ = bp.OuterHalfZ;
		float[] array = new float[7]
		{
			0f - outerHalfX,
			0f - halfX,
			-2f,
			0f,
			2f,
			halfX,
			outerHalfX
		};
		float[] array2 = new float[4]
		{
			0f - outerHalfZ,
			0f - halfZ,
			halfZ,
			outerHalfZ
		};
		List<float> list = new List<float>(new float[4] { -4f, 3f, 5f, 10f });
		if (bp.Roof)
		{
			list.Add(bp.Top);
		}
		List<Poly> list2 = new List<Poly>();
		Vector3 val = default(Vector3);
		Vector3 val2 = default(Vector3);
		for (int i = 0; i + 1 < list.Count; i++)
		{
			for (int j = 0; j + 1 < array.Length; j++)
			{
				for (int k = 0; k + 1 < array2.Length; k++)
				{
					((Vector3)(ref val))..ctor(array[j], list[i], array2[k]);
					((Vector3)(ref val2))..ctor(array[j + 1], list[i + 1], array2[k + 1]);
					Vector3 val3 = (val + val2) * 0.5f;
					if (val3.y > 10f)
					{
						list2.Add(Poly.FromBox(val, val2));
					}
					else
					{
						if (Mathf.Abs(val3.x) < halfX && Mathf.Abs(val3.z) < halfZ)
						{
							continue;
						}
						if (val3.z < 0f - halfZ && Mathf.Abs(val3.x) < 2f)
						{
							if (val2.y <= 3f)
							{
								continue;
							}
							if (val.y < 5f)
							{
								AddSpandrel(list2, val3.x > 0f, val.z, val2.z);
								continue;
							}
						}
						list2.Add(Poly.FromBox(val, val2));
					}
				}
			}
		}
		MarkSeams(list2);
		return list2;
	}

	private static void MarkSeams(List<Poly> pieces)
	{
		Dictionary<string, int> dictionary = new Dictionary<string, int>();
		List<string> list = new List<string>();
		for (int i = 0; i < pieces.Count; i++)
		{
			for (int j = 0; j < pieces[i].Faces.Count; j++)
			{
				string text = FaceKey(pieces[i].Faces[j].Pts);
				list.Add(text);
				dictionary.TryGetValue(text, out var value);
				dictionary[text] = value + 1;
			}
		}
		int num = 0;
		for (int k = 0; k < pieces.Count; k++)
		{
			for (int l = 0; l < pieces[k].Faces.Count; l++)
			{
				if (dictionary[list[num++]] > 1)
				{
					pieces[k].Faces[l].Tag = -2;
				}
			}
		}
	}

	private static string FaceKey(List<Vector3> pts)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		List<string> list = new List<string>();
		for (int i = 0; i < pts.Count; i++)
		{
			list.Add(Mathf.RoundToInt(pts[i].x * 1000f) + "," + Mathf.RoundToInt(pts[i].y * 1000f) + "," + Mathf.RoundToInt(pts[i].z * 1000f));
		}
		list.Sort(StringComparer.Ordinal);
		return string.Join(";", list.ToArray());
	}

	private static void AddSpandrel(List<Poly> pieces, bool right, float z0, float z1)
	{
		//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_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: 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)
		Vector2 a = default(Vector2);
		((Vector2)(ref a))..ctor(right ? 2f : (-2f), 5f);
		for (int i = 0; i < 8; i++)
		{
			Vector2 b = ArcPoint(right ? i : (8 + i));
			Vector2 c = ArcPoint(right ? (i + 1) : (8 + i + 1));
			pieces.Add(Poly.FromPrism(a, b, c, z0, z1));
		}
	}

	private static Vector2 ArcPoint(int k)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		switch (k)
		{
		case 0:
			return new Vector2(2f, 3f);
		case 8:
			return new Vector2(0f, 5f);
		case 16:
			return new Vector2(-2f, 3f);
		default:
		{
			float num = (float)Math.PI * (float)k / 16f;
			return new Vector2(Mathf.Cos(num) * 2f, 3f + Mathf.Sin(num) * 2f);
		}
		}
	}

	internal static bool InSolid(Blueprint bp, Vector3 p)
	{
		if (p.y < -4f || p.y > bp.Top || Mathf.Abs(p.x) > bp.OuterHalfX || Mathf.Abs(p.z) > bp.OuterHalfZ)
		{
			return false;
		}
		if (p.y >= 10f)
		{
			return bp.Roof;
		}
		if (Mathf.Abs(p.x) < bp.HalfX && Mathf.Abs(p.z) < bp.HalfZ)
		{
			return false;
		}
		if (p.z < 0f - bp.HalfZ && InGateway(p.x, p.y))
		{
			return false;
		}
		return true;
	}

	private static bool InGateway(float x, float y)
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		if (Mathf.Abs(x) >= 2f)
		{
			return false;
		}
		if (y < 3f)
		{
			return true;
		}
		for (int i = 0; i < 16; i++)
		{
			Vector2 val = ArcPoint(i);
			Vector2 val2 = ArcPoint(i + 1);
			if ((val2.x - val.x) * (y - val.y) - (val2.y - val.y) * (x - val.x) < 0f)
			{
				return false;
			}
		}
		return true;
	}

	private static List<Vector3> Seeds(Blueprint bp, int randomSeed)
	{
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		Random rng = new Random(randomSeed);
		List<Vector3> list = new List<Vector3>();
		float num = 1f;
		float outerHalfX = bp.OuterHalfX;
		float outerHalfZ = bp.OuterHalfZ;
		float[] array = new float[6] { -2f, 1f, 3f, 5f, 7f, 9f };
		Vector3 p = default(Vector3);
		for (int i = 0; i < 4; i++)
		{
			float num2 = ((i < 2) ? outerHalfX : bp.HalfZ);
			for (float num3 = 0f - num2 + 1f; num3 < num2 - 0.5f; num3 += 2f)
			{
				for (int j = 0; j < array.Length; j++)
				{
					float num4 = Jitter(rng, 0.55f);
					float num5 = Jitter(rng, (j == 0) ? 0.6f : 0.55f);
					float num6 = Jitter(rng, 0.3f);
					float num7 = num3 + num4;
					float num8 = array[j] + num5;
					switch (i)
					{
					case 0:
						((Vector3)(ref p))..ctor(num7, num8, 0f - (bp.HalfZ + num) + num6);
						break;
					case 1:
						((Vector3)(ref p))..ctor(num7, num8, bp.HalfZ + num + num6);
						break;
					case 2:
						((Vector3)(ref p))..ctor(bp.HalfX + num + num6, num8, num7);
						break;
					default:
						((Vector3)(ref p))..ctor(0f - (bp.HalfX + num) + num6, num8, num7);
						break;
					}
					TryAddSeed(bp, list, p);
				}
			}
		}
		if (bp.Roof)
		{
			float num9 = 10.8f;
			for (float num10 = 0f - outerHalfX + 1.1f; num10 < outerHalfX - 0.5f; num10 += 2.2f)
			{
				for (float num11 = 0f - outerHalfZ + 1.1f; num11 < outerHalfZ - 0.5f; num11 += 2.2f)
				{
					float num12 = Jitter(rng, 0.6f);
					float num13 = Jitter(rng, 0.6f);
					float num14 = Jitter(rng, 0.2f);
					TryAddSeed(bp, list, new Vector3(num10 + num12, num9 + num14, num11 + num13));
				}
			}
		}
		return list;
	}

	private static float Jitter(Random rng, float amount)
	{
		return (float)(rng.NextDouble() * 2.0 - 1.0) * amount;
	}

	private static void TryAddSeed(Blueprint bp, List<Vector3> seeds, Vector3 p)
	{
		//IL_0001: 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_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		if (!InSolid(bp, p))
		{
			return;
		}
		for (int i = 0; i < seeds.Count; i++)
		{
			Vector3 val = seeds[i] - p;
			if (((Vector3)(ref val)).sqrMagnitude < 0.64000005f)
			{
				return;
			}
		}
		seeds.Add(p);
	}

	private static float Reach(Blueprint bp, List<Vector3> seeds)
	{
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: 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_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		float num = 0f;
		float outerHalfX = bp.OuterHalfX;
		float outerHalfZ = bp.OuterHalfZ;
		Vector3 val = default(Vector3);
		for (float num2 = 0f - outerHalfX + 0.25f; num2 < outerHalfX; num2 += 0.5f)
		{
			for (float num3 = 0f - outerHalfZ + 0.25f; num3 < outerHalfZ; num3 += 0.5f)
			{
				for (float num4 = -3.75f; num4 < bp.Top; num4 += 0.5f)
				{
					((Vector3)(ref val))..ctor(num2, num4, num3);
					if (!InSolid(bp, val))
					{
						continue;
					}
					float num5 = float.MaxValue;
					for (int i = 0; i < seeds.Count; i++)
					{
						Vector3 val2 = seeds[i] - val;
						float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
						if (sqrMagnitude < num5)
						{
							num5 = sqrMagnitude;
						}
					}
					num = Mathf.Max(num, num5);
				}
			}
		}
		float num6 = Mathf.Sqrt(num) + 0.4f;
		if (num6 > 3.3f)
		{
			throw new InvalidOperationException("Fortress seeds leave a gap (" + num6.ToString("F2") + " m)");
		}
		return num6;
	}

	private static int Nearest(List<Vector3> seeds, Vector3 p)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		int result = -1;
		float num = float.MaxValue;
		for (int i = 0; i < seeds.Count; i++)
		{
			Vector3 val = seeds[i] - p;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			if (sqrMagnitude < num)
			{
				num = sqrMagnitude;
				result = i;
			}
		}
		return result;
	}

	private static Vector3 Centroid(List<Vector3> pts)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: 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)
		Vector3 val = Vector3.zero;
		for (int i = 0; i < pts.Count; i++)
		{
			val += pts[i];
		}
		return val / (float)pts.Count;
	}

	private static float DistanceToBox(Bounds b, Vector3 p)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		Vector3 min = ((Bounds)(ref b)).min;
		Vector3 max = ((Bounds)(ref b)).max;
		Vector3 val = default(Vector3);
		((Vector3)(ref val))..ctor(Mathf.Clamp(p.x, min.x, max.x), Mathf.Clamp(p.y, min.y, max.y), Mathf.Clamp(p.z, min.z, max.z));
		Vector3 val2 = val - p;
		return ((Vector3)(ref val2)).magnitude;
	}

	internal static Vector3 Deform(Blueprint bp, Vector3 p)
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: 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_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//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_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Unknown result type (might be due to invalid IL or missing references)
		if (DebugNoDeform)
		{
			return p;
		}
		Vector3 val = Round(bp, p);
		Vector3 val2 = new Vector3(Noise(p / 3.2f, 11), Noise(p / 3.2f, 23), Noise(p / 3.2f, 37)) * 0.45f + new Vector3(Noise(p / 1.3f, 41), Noise(p / 1.3f, 53), Noise(p / 1.3f, 67)) * 0.13f;
		if (bp.Roof)
		{
			float num = p.x / bp.OuterHalfX;
			float num2 = p.z / bp.OuterHalfZ;
			float num3 = Mathf.Clamp01(1f - num * num) * Mathf.Clamp01(1f - num2 * num2);
			float num4 = Mathf.SmoothStep(0f, 1f, Mathf.Clamp01((p.y - 10f) / 1.6f));
			val2.y += 1f * num3 * num4;
		}
		return val + val2;
	}

	private static Vector3 Round(Blueprint bp, Vector3 p)
	{
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: 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_0080: 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)
		float num = bp.OuterHalfX - 1.2f;
		float num2 = bp.OuterHalfZ - 1.2f;
		float num3 = bp.Top - 1.2f;
		Vector3 val = default(Vector3);
		((Vector3)(ref val))..ctor(Mathf.Clamp(p.x, 0f - num, num), Mathf.Min(p.y, num3), Mathf.Clamp(p.z, 0f - num2, num2));
		Vector3 val2 = p - val;
		float magnitude = ((Vector3)(ref val2)).magnitude;
		if (magnitude <= 1.2f || magnitude < 1E-06f)
		{
			return p;
		}
		return val + val2 * (1.2f / magnitude);
	}

	private static float Noise(Vector3 p, int seed)
	{
		int num = Mathf.FloorToInt(p.x);
		int num2 = Mathf.FloorToInt(p.y);
		int num3 = Mathf.FloorToInt(p.z);
		float num4 = p.x - (float)num;
		float num5 = p.y - (float)num2;
		float num6 = p.z - (float)num3;
		float num7 = num4 * num4 * (3f - 2f * num4);
		float num8 = num5 * num5 * (3f - 2f * num5);
		float num9 = num6 * num6 * (3f - 2f * num6);
		float num10 = Hash(num, num2, num3, seed);
		float num11 = Hash(num + 1, num2, num3, seed);
		float num12 = Hash(num, num2 + 1, num3, seed);
		float num13 = Hash(num + 1, num2 + 1, num3, seed);
		float num14 = Hash(num, num2, num3 + 1, seed);
		float num15 = Hash(num + 1, num2, num3 + 1, seed);
		float num16 = Hash(num, num2 + 1, num3 + 1, seed);
		float num17 = Hash(num + 1, num2 + 1, num3 + 1, seed);
		float num18 = Mathf.Lerp(Mathf.Lerp(num10, num11, num7), Mathf.Lerp(num12, num13, num7), num8);
		float num19 = Mathf.Lerp(Mathf.Lerp(num14, num15, num7), Mathf.Lerp(num16, num17, num7), num8);
		return Mathf.Lerp(num18, num19, num9);
	}

	private static float Hash(int x, int y, int z, int seed)
	{
		uint num = (uint)(x * 374761393 + y * 668265263 + z * -2048144777 + seed * -1028477379);
		num = (num ^ (num >> 13)) * 1274126177;
		num ^= num >> 16;
		return (float)(num & 0xFFFFFF) / (26353588f / (float)Math.PI) - 1f;
	}

	private static void SmoothSurface(Blueprint bp)
	{
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: 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_0137: 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_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		//IL_0185: Unknown result type (might be due to invalid IL or missing references)
		//IL_018a: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		Dictionary<PosKey, List<Contribution>> dictionary = new Dictionary<PosKey, List<Contribution>>();
		for (int i = 0; i < bp.Blocks.Count; i++)
		{
			MeshData data = bp.Blocks[i].Data;
			for (int j = 0; j < data.Fans.Count; j++)
			{
				MeshData.OuterFan outerFan = data.Fans[j];
				for (int k = 0; k < outerFan.Count; k++)
				{
					PosKey key = new PosKey(data.Verts[outerFan.Start + k]);
					if (!dictionary.TryGetValue(key, out var value))
					{
						value = (dictionary[key] = new List<Contribution>());
					}
					Contribution item = new Contribution
					{
						Face = outerFan.FaceNormal,
						Weight = outerFan.Weights[k]
					};
					value.Add(item);
				}
			}
		}
		for (int l = 0; l < bp.Blocks.Count; l++)
		{
			MeshData data2 = bp.Blocks[l].Data;
			for (int m = 0; m < data2.Fans.Count; m++)
			{
				MeshData.OuterFan outerFan2 = data2.Fans[m];
				for (int n = 0; n < outerFan2.Count; n++)
				{
					List<Contribution> list2 = dictionary[new PosKey(data2.Verts[outerFan2.Start + n])];
					Vector3 val = Vector3.zero;
					for (int num = 0; num < list2.Count; num++)
					{
						if (Vector3.Dot(list2[num].Face, outerFan2.FaceNormal) > 0.5f)
						{
							val += list2[num].Weight;
						}
					}
					data2.Normals[outerFan2.Start + n] = ((((Vector3)(ref val)).sqrMagnitude > 1E-12f) ? ((Vector3)(ref val)).normalized : outerFan2.FaceNormal);
				}
			}
		}
	}
}
internal static class Prefabs
{
	internal static Material[] RendererMaterials(GameObject rock)
	{
		if ((Object)(object)rock == (Object)null)
		{
			return null;
		}
		Material[] array = null;
		MeshRenderer[] componentsInChildren = rock.GetComponentsInChildren<MeshRenderer>(true);
		foreach (MeshRenderer val in componentsInChildren)
		{
			Material[] array2 = (((Object)(object)val != (Object)null) ? ((Renderer)val).sharedMaterials : null);
			if (array2 != null && array2.Length != 0 && !((Object)(object)array2[0] == (Object)null) && (array == null || array2.Length > array.Length))
			{
				array = array2;
			}
		}
		return array;
	}

	internal static GameObject BuildFortress(string name, Blueprint plan, int variant, Material[] materials, MineRock5 capstone, int layer, Transform container)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: 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_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_017d: Expected O, but got Unknown
		GameObject val = new GameObject(name);
		val.transform.SetParent(container, false);
		val.layer = layer;
		ZNetView val2 = val.AddComponent<ZNetView>();
		val2.m_persistent = true;
		val2.m_distant = true;
		val2.m_type = (ObjectType)2;
		val2.m_syncInitialScale = false;
		FortressDamageGuard fortressDamageGuard = val.AddComponent<FortressDamageGuard>();
		fortressDamageGuard.ChunkCount = plan.Blocks.Count;
		MineRock5 val3 = val.AddComponent<MineRock5>();
		val3.m_name = "Fortress rock";
		val3.m_damageModifiers = capstone.m_damageModifiers;
		val3.m_minToolTier = capstone.m_minToolTier;
		val3.m_supportCheck = false;
		val3.m_triggerPrivateArea = capstone.m_triggerPrivateArea;
		val3.m_destroyedEffect = capstone.m_destroyedEffect;
		val3.m_hitEffect = capstone.m_hitEffect;
		val3.m_hitEffectAreaCenter = false;
		val3.m_hoverOffset = capstone.m_hoverOffset;
		FortressPlugin.ApplyRockSettings(val3, capstone);
		FortressRiser fortressRiser = val.AddComponent<FortressRiser>();
		fortressRiser.Variant = variant;
		LODGroup val4 = val.AddComponent<LODGroup>();
		val4.SetLODs((LOD[])(object)new LOD[1]
		{
			new LOD(0.01f, (Renderer[])(object)new Renderer[0])
		});
		val4.localReferencePoint = new Vector3(0f, (plan.MinY + plan.MaxY) * 0.5f, 0f);
		val4.size = 26f;
		for (int i = 0; i < plan.Blocks.Count; i++)
		{
			BlockDef blockDef = plan.Blocks[i];
			GameObject val5 = new GameObject("Rock_" + i.ToString("D3"));
			val5.transform.SetParent(val.transform, false);
			val5.layer = layer;
			MeshFilter val6 = val5.AddComponent<MeshFilter>();
			val6.sharedMesh = blockDef.Mesh;
			MeshRenderer val7 = val5.AddComponent<MeshRenderer>();
			((Renderer)val7).sharedMaterials = materials;
			MeshCollider val8 = val5.AddComponent<MeshCollider>();
			val8.sharedMesh = blockDef.Mesh;
			val8.convex = false;
			try
			{
				Physics.BakeMesh(((Object)blockDef.Mesh).GetInstanceID(), false);
			}
			catch (Exception)
			{
			}
		}
		return val;
	}

	internal static GameObject BuildRune(Material[] materials, Transform container)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Expected O, but got Unknown
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Expected O, but got Unknown
		GameObject val = new GameObject("runemagic_stone_fortress");
		val.transform.SetParent(container, false);
		ZNetView val2 = val.AddComponent<ZNetView>();
		val2.m_persistent = false;
		val2.m_distant = false;
		val2.m_type = (ObjectType)0;
		val2.m_syncInitialScale = false;
		Piece val3 = val.AddComponent<Piece>();
		val3.m_name = "Rune of the Stonecaller: Fortress";
		val3.m_enabled = false;
		val.AddComponent<FortressRune>();
		for (int i = 0; i < 4; i++)
		{
			GameObject val4 = new GameObject("Ghost_" + i);
			val4.transform.SetParent(val.transform, false);
			val4.AddComponent<MeshFilter>().sharedMesh = FortressPlugin.Plans[i].GhostMesh;
			((Renderer)val4.AddComponent<MeshRenderer>()).sharedMaterials = materials;
		}
		return val;
	}

	internal static GameObject BuildDust(MethodInfo getPrefab, Transform container)
	{
		if (getPrefab == null)
		{
			return null;
		}
		try
		{
			object? obj = getPrefab.Invoke(null, new object[1] { "vfx_DustCloud" });
			GameObject val = (GameObject)((obj is GameObject) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, container, false);
			((Object)val2).name = "StoneFortress_Dust";
			TimedDestruction[] componentsInChildren = val2.GetComponentsInChildren<TimedDestruction>(true);
			foreach (TimedDestruction val3 in componentsInChildren)
			{
				Object.DestroyImmediate((Object)(object)val3);
			}
			ZNetView[] componentsInChildren2 = val2.GetComponentsInChildren<ZNetView>(true);
			foreach (ZNetView val4 in componentsInChildren2)
			{
				Object.DestroyImmediate((Object)(object)val4);
			}
			return val2;
		}
		catch (Exception ex)
		{
			Exception ex2 = ((ex.InnerException != null) ? ex.InnerException : ex);
			FortressPlugin.Log.LogWarning((object)("Dust effect unavailable: " + ex2.Message));
			return null;
		}
	}

	internal static void ConfigurePiece(Piece piece, Piece capstone, Sprite icon)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Expected O, but got Unknown
		piece.m_category = capstone.m_category;
		piece.m_usage = capstone.m_usage;
		piece.m_groundPiece = capstone.m_groundPiece;
		piece.m_groundOnly = capstone.m_groundOnly;
		piece.m_allowedInDeepSnow = capstone.m_allowedInDeepSnow;
		

plugins/StoneRamp.dll

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

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

[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("danpe.RuneMagicStoneRamp", "Rune Magic - Stone Ramp", "1.0.1")]
public class RampPlugin : BaseUnityPlugin
{
	public enum RockStyle
	{
		Megalith,
		Capstone,
		Arch
	}

	public const string PluginGuid = "danpe.RuneMagicStoneRamp";

	public const string PluginName = "Rune Magic - Stone Ramp";

	public const string PluginVersion = "1.0.1";

	internal const string RuneMagicGuid = "hyleanlegend.RuneMagic";

	internal const string CapstonePrefab = "widestone";

	internal const string CapstoneFracPrefab = "widestone_frac";

	internal const string MegalithPrefab = "HeathRockPillar";

	internal const string MegalithFracPrefab = "HeathRockPillar_frac";

	internal const string ArchPrefab = "cliff_ashlands3_Arch_1";

	internal const string CapstoneConfigName = "runemagic_stone_capstone";

	internal const string FortressRuneName = "runemagic_stone_fortress";

	internal const string RuneName = "runemagic_stone_ramp";

	internal const string RuneCloneName = "runemagic_stone_ramp(Clone)";

	private const string RuneFocusItemName = "$item_runemagic_runefocus";

	private const int TestedMajor = 1;

	private const int TestedMinor = 5;

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<int> Height;

	internal static ConfigEntry<RockStyle> Style;

	internal static ConfigEntry<bool> AlignToView;

	internal static ConfigEntry<float> RiseSeconds;

	internal static ConfigEntry<float> EnergyCost;

	internal static ConfigEntry<float> BlockHealth;

	internal static ConfigEntry<bool> DropStone;

	internal static ConfigEntry<bool> AllowUntestedVersion;

	internal static readonly Blueprint[] Plans = new Blueprint[Geo.Heights.Length];

	internal static GameObject DustTemplate;

	internal static MineRock5 CapstoneRock;

	private static Harmony _harmony;

	private static GameObject _container;

	private static GameObject _runePrefab;

	private static readonly GameObject[] _rampPrefabs = (GameObject[])(object)new GameObject[Geo.Heights.Length];

	private static GameObject _capstone;

	private static Material[] _capstoneMaterials;

	private static PieceTable _table;

	private static bool _pieceConfigured;

	private static MethodInfo _getBundlePrefab;

	private static readonly DropTable NoDrops;

	private static readonly Dictionary<RockStyle, Material[]> _styleMaterials;

	private static List<GameObject> _scenePrefabs;

	internal static string RampName(int variant)
	{
		return "runemagic_ramp_" + Geo.Heights[variant];
	}

	internal static float Cost()
	{
		float num = ((EnergyCost != null) ? Mathf.Max(0f, EnergyCost.Value) : 0f);
		return num * (float)Geo.Heights[CurrentVariant()];
	}

	internal static string Description()
	{
		int num = Geo.Heights[CurrentVariant()];
		float num2 = Cost();
		return "Engrave the ground where the ramp should begin and a ramp of living rock rises, climbing at an easy slope to a flat top about " + num + " metres up. It is four metres wide, and like the Capstone it can only be undone piece by piece with a pickaxe. " + ((num2 > 0f) ? ("Costs " + Mathf.CeilToInt(num2) + " runic energy.") : "Costs no runic energy.");
	}

	internal static int CurrentVariant()
	{
		int value = ((Height != null) ? Height.Value : 15);
		int num = Array.IndexOf(Geo.Heights, value);
		if (num < 0)
		{
			return 1;
		}
		return num;
	}

	internal static Blueprint Plan(int variant)
	{
		if (variant < 0 || variant >= Plans.Length)
		{
			return null;
		}
		return Plans[variant];
	}

	private void Awake()
	{
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Expected O, but got Unknown
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Expected O, but got Unknown
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Expected O, but got Unknown
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0156: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When false the plugin does nothing at all (restart required). Multiplayer: the host AND every player need this add-on, in the same version (the rock's chunk layout must match). A host without it permanently deletes raised ramps when their area loads (unknown prefab); a player without it sees nothing there, and while the game hands them the ramp (they are nearest) nobody's pickaxe hits on it count.");
		Height = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Height", 15, new ConfigDescription("How high the ramp climbs, in metres: 10 (about 21 m long), 15 (30 m long) or 20 (39 m long), each at a 30 degree slope ending in a flat top. Measured from its foot, which starts 0.3 m into the ground where you aim. Any other value counts as 10. Applies to the next placement.", (AcceptableValueBase)(object)new AcceptableValueList<int>(Geo.Heights), new object[0]));
		Style = ((BaseUnityPlugin)this).Config.Bind<RockStyle>("General", "Rock style", RockStyle.Megalith, "Which natural rock the ramp looks like: Megalith (the Plains heath rock of the Megalith rune), Capstone (grey mountain rock) or Arch (the dark Ashlands rock of the Arch rune). Only the look changes - mining and drops stay the Capstone's - and each player sees their own choice. Applies to ramps that load after the change.");
		AlignToView = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Align to your view", true, "Each time you select the rune, the ramp climbs straight away from you along your view; the scroll wheel turns it in steps from there. Off: the piece keeps Valheim's fixed world orientation and only the scroll wheel turns it.");
		RiseSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Rise seconds", 8f, new ConfigDescription("How long the ramp takes to rise out of the ground. Everyone nearby sees the same rise.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), new object[0]));
		EnergyCost = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Energy cost per metre", 10f, new ConfigDescription("Runic energy per metre of height: the default 10 makes the 10 / 15 / 20 m ramps cost 100 / 150 / 200. 0 = free.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), new object[0]));
		BlockHealth = ((BaseUnityPlugin)this).Config.Bind<float>("Stone", "Block health", 0f, new ConfigDescription("Health of each rock chunk. 0 = the same as a Capstone piece (30, raised by world level like any rock). Hits are settled by whichever machine currently owns the ramp (usually the player nearest it, or the host), so keep this the same for everyone. The first hit stores every chunk's health with the ramp, so a change only affects ramps nobody has mined yet.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f), new object[0]));
		DropStone = ((BaseUnityPlugin)this).Config.Bind<bool>("Stone", "Drop stone when mined", true, "Each mined chunk drops stone like a Capstone piece (2-3). Off: mining a ramp yields nothing. Settled by whichever machine owns the ramp at the time, so keep it the same for everyone.");
		AllowUntestedVersion = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Allow untested Rune Magic version", false, "This add-on was verified against Rune Magic 1.5.x. With any other version it stays off unless this is true.");
		if (!Enabled.Value)
		{
			Log.LogWarning((object)"Stone Ramp is OFF on this game instance. If this instance is the host or server, raised ramps are permanently deleted when their area loads.");
			return;
		}
		EnergyCost.SettingChanged += RefreshDescription;
		Height.SettingChanged += RefreshDescription;
		BlockHealth.SettingChanged += RefreshRockSettings;
		DropStone.SettingChanged += RefreshRockSettings;
		Style.SettingChanged += RefreshStyle;
		try
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			Setup();
			List<string> list = new List<string>();
			for (int i = 0; i < Plans.Length; i++)
			{
				list.Add(Geo.Heights[i] + " m: " + Plans[i].Blocks.Count);
			}
			Log.LogInfo((object)("Stone Ramp registered (chunks " + string.Join(", ", list.ToArray()) + "; layout checksum " + Geo.Checksum(Plans).ToString("X8") + ", built in " + Mathf.RoundToInt((Time.realtimeSinceStartup - realtimeSinceStartup) * 1000f) + " ms); the piece appears after the Capstone (or the Stone Fortress) once a world is loaded. The host and every player need this add-on."));
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Setup failed - the Stone Ramp rune will not be available. Nothing else is affected. " + ex));
			Teardown();
			Log.LogWarning((object)"If this instance is the host or server, raised ramps are permanently deleted when their area loads.");
		}
	}

	private void OnDestroy()
	{
		Teardown();
	}

	private static void Teardown()
	{
		if (EnergyCost != null)
		{
			EnergyCost.SettingChanged -= RefreshDescription;
		}
		if (Height != null)
		{
			Height.SettingChanged -= RefreshDescription;
		}
		if (BlockHealth != null)
		{
			BlockHealth.SettingChanged -= RefreshRockSettings;
		}
		if (DropStone != null)
		{
			DropStone.SettingChanged -= RefreshRockSettings;
		}
		if (Style != null)
		{
			Style.SettingChanged -= RefreshStyle;
		}
		try
		{
			if ((Object)(object)_table != (Object)null && (Object)(object)_runePrefab != (Object)null)
			{
				_table.m_pieces.Remove(_runePrefab);
			}
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				foreach (GameObject item in AllPrefabs())
				{
					ZNetScene.instance.m_prefabs.Remove(item);
				}
			}
			if ((Object)(object)_container != (Object)null)
			{
				Object.Destroy((Object)(object)_container);
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Unregister failed: " + ex.Message));
		}
		_runePrefab = null;
		for (int i = 0; i < _rampPrefabs.Length; i++)
		{
			_rampPrefabs[i] = null;
		}
		_capstone = null;
		_container = null;
		_table = null;
		_pieceConfigured = false;
		_styleMaterials.Clear();
		_scenePrefabs = null;
		_capstoneMaterials = null;
		DustTemplate = null;
		CapstoneRock = null;
		if (_harmony != null)
		{
			List<MethodBase> list;
			try
			{
				list = new List<MethodBase>(_harmony.GetPatchedMethods());
			}
			catch (Exception)
			{
				list = new List<MethodBase>();
			}
			foreach (MethodBase item2 in list)
			{
				try
				{
					_harmony.Unpatch(item2, (HarmonyPatchType)0, "danpe.RuneMagicStoneRamp");
				}
				catch (Exception ex3)
				{
					Log.LogWarning((object)("Unpatch failed for " + item2.Name + ": " + ex3.Message));
				}
			}
		}
		Patches.Reset();
	}

	private static List<GameObject> AllPrefabs()
	{
		List<GameObject> list = new List<GameObject>();
		if ((Object)(object)_runePrefab != (Object)null)
		{
			list.Add(_runePrefab);
		}
		for (int i = 0; i < _rampPrefabs.Length; i++)
		{
			if ((Object)(object)_rampPrefabs[i] != (Object)null)
			{
				list.Add(_rampPrefabs[i]);
			}
		}
		return list;
	}

	private static void CheckRuneMagicVersion()
	{
		if (!Chainloader.PluginInfos.TryGetValue("hyleanlegend.RuneMagic", out var value) || value == null)
		{
			throw new InvalidOperationException("Rune Magic is not loaded");
		}
		Version version = value.Metadata.Version;
		if (version.Major != 1 || version.Minor != 5)
		{
			if (!AllowUntestedVersion.Value)
			{
				throw new InvalidOperationException(string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x). Set 'Allow untested Rune Magic version' to true to try anyway."));
			}
			Log.LogWarning((object)string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x); continuing because the config allows it."));
		}
	}

	private static Type RequireType(string name)
	{
		Type type = AccessTools.TypeByName(name);
		if (type == null)
		{
			throw new InvalidOperationException("Rune Magic type not found: " + name);
		}
		return type;
	}

	private static MethodInfo RequireMethod(Type t, string name, Type[] args)
	{
		MethodInfo methodInfo = ((args == null) ? AccessTools.Method(t, name, (Type[])null, (Type[])null) : AccessTools.Method(t, name, args, (Type[])null));
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Method not found: " + t.FullName + "." + name);
		}
		return methodInfo;
	}

	private static FieldInfo RequireField(Type t, string name)
	{
		FieldInfo fieldInfo = AccessTools.Field(t, name);
		if (fieldInfo == null)
		{
			throw new InvalidOperationException("Field not found: " + t.FullName + "." + name);
		}
		return fieldInfo;
	}

	private static HarmonyMethod H(string name)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(typeof(Patches), name, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Patch method missing: " + name);
		}
		return new HarmonyMethod(methodInfo);
	}

	private static void Setup()
	{
		//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b3: Expected O, but got Unknown
		//IL_04a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b3: Expected O, but got Unknown
		CheckRuneMagicVersion();
		Type t = RequireType("ValheimMod.ValheimMod");
		MethodInfo methodInfo = RequireMethod(t, "get_isModAwake", Type.EmptyTypes);
		if (!(bool)methodInfo.Invoke(null, null))
		{
			throw new InvalidOperationException("Rune Magic did not finish initialising (isModAwake is false)");
		}
		Type t2 = RequireType("ValheimMod.UnlockManager");
		Type type = RequireType("ValheimMod.RunemagicPieceConfig");
		Type t3 = RequireType("ValheimMod.CustomContentSetupHandler");
		Type t4 = RequireType("ValheimMod.BoulderSetupHandler");
		Type t5 = RequireType("ValheimMod.PlayerPatch");
		MethodInfo methodInfo2 = RequireMethod(t2, "isUnlockable", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo3 = RequireMethod(t2, "isUnlocked", new Type[2]
		{
			typeof(Player),
			typeof(Piece)
		});
		MethodInfo methodInfo4 = RequireMethod(type, "getEnergyCost", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo5 = RequireMethod(t4, "SetUpCustomBoulderFeatures", Type.EmptyTypes);
		FieldInfo fieldInfo = RequireField(t5, "PlayerPlacing");
		if (fieldInfo.FieldType != typeof(bool) || !fieldInfo.IsStatic)
		{
			throw new InvalidOperationException("PlayerPatch.PlayerPlacing has an unexpected shape");
		}
		MethodInfo methodInfo6 = RequireMethod(typeof(ZNetScene), "Awake", Type.EmptyTypes);
		MethodInfo methodInfo7 = RequireMethod(typeof(Player), "UpdatePlacementGhost", new Type[1] { typeof(bool) });
		MethodInfo methodInfo8 = RequireMethod(typeof(Player), "SetupPlacementGhost", Type.EmptyTypes);
		MethodInfo methodInfo9 = RequireMethod(typeof(MineRock5), "RPC_Damage", new Type[3]
		{
			typeof(long),
			typeof(HitData),
			typeof(int)
		});
		ConstructorInfo constructor = type.GetConstructor(new Type[3]
		{
			typeof(Biome),
			typeof(string),
			typeof(string)
		});
		if (constructor == null)
		{
			throw new InvalidOperationException("RunemagicPieceConfig(Biome, string, string) constructor not found");
		}
		if (!(RequireField(t3, "RegisteredItemPrefabs").GetValue(null) is List<GameObject> list))
		{
			throw new InvalidOperationException("Rune Magic's item prefab list has an unexpected type");
		}
		Type type2 = AccessTools.TypeByName("ValheimMod.AssetLoader");
		_getBundlePrefab = ((type2 != null) ? AccessTools.Method(type2, "GetPrefabFromAssetBundle", new Type[1] { typeof(string) }, (Type[])null) : null);
		PieceTable val = null;
		foreach (GameObject item in list)
		{
			ItemDrop val2 = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null && val2.m_itemData.m_shared.m_name == "$item_runemagic_runefocus")
			{
				val = val2.m_itemData.m_shared.m_buildPieces;
				break;
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			throw new InvalidOperationException("Rune Focus piece table not found");
		}
		for (int i = 0; i < Plans.Length; i++)
		{
			Plans[i] = Geo.Build(Geo.Heights[i]);
		}
		Patches.IsUnlockedOriginal = (Func<Player, Piece, bool>)Delegate.CreateDelegate(typeof(Func<Player, Piece, bool>), methodInfo3);
		Patches.PlayerPlacingField = fieldInfo;
		_harmony = new Harmony("danpe.RuneMagicStoneRamp");
		_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, H("IsUnlockablePostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, H("IsUnlockedPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, H("EnergyCostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, H("BoulderSetupPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, H("PlacementGhostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo8, H("SetupPlacementGhostPrefix"), H("SetupPlacementGhostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo9, H("MineRockDamagePrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		HarmonyMethod val3 = H("ZNetSceneAwakePrefix");
		val3.priority = 800;
		_harmony.Patch((MethodBase)methodInfo6, val3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_container = new GameObject("RuneMagicStoneRamp_Prefabs");
		_container.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)_container);
		_table = val;
		constructor.Invoke(new object[3]
		{
			(object)(Biome)8,
			"runemagic_stone_ramp",
			"runemagic_stone_capstone"
		});
	}

	internal static GameObject FindPrefab(string name)
	{
		List<GameObject> scenePrefabs = _scenePrefabs;
		if (scenePrefabs == null)
		{
			return null;
		}
		for (int i = 0; i < scenePrefabs.Count; i++)
		{
			if ((Object)(object)scenePrefabs[i] != (Object)null && ((Object)scenePrefabs[i]).name == name)
			{
				return scenePrefabs[i];
			}
		}
		return null;
	}

	internal static void OnZNetSceneAwake(ZNetScene scene)
	{
		if ((Object)(object)scene == (Object)null || scene.m_prefabs == null || (Object)(object)_container == (Object)null)
		{
			return;
		}
		_scenePrefabs = scene.m_prefabs;
		if ((Object)(object)_runePrefab == (Object)null)
		{
			GameObject val = FindPrefab("widestone");
			GameObject val2 = FindPrefab("widestone_frac");
			if ((Object)(object)val2 == (Object)null && (Object)(object)val != (Object)null)
			{
				Destructible component = val.GetComponent<Destructible>();
				val2 = (((Object)(object)component != (Object)null) ? component.m_spawnWhenDestroyed : null);
			}
			MineRock5 val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<MineRock5>() : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val3 == (Object)null || Prefabs.RendererMaterials(val2) == null)
			{
				Log.LogWarning((object)"The vanilla Capstone (widestone / widestone_frac) was not found in this scene; the Stone Ramp rune is unavailable.");
				return;
			}
			_capstone = val;
			CapstoneRock = val3;
			_capstoneMaterials = Prefabs.RendererMaterials(val2);
			Material[] array = StyleMaterials(Style.Value);
			if (array == null)
			{
				Log.LogWarning((object)"The Capstone's materials were not found; the Stone Ramp rune is unavailable.");
				_capstone = null;
				CapstoneRock = null;
				return;
			}
			GameObject[] array2 = (GameObject[])(object)new GameObject[Plans.Length];
			GameObject val4 = null;
			try
			{
				for (int i = 0; i < Plans.Length; i++)
				{
					array2[i] = Prefabs.BuildRamp(RampName(i), Plans[i], i, array, val3, val2.layer, _container.transform);
				}
				val4 = Prefabs.BuildRune(array, _container.transform);
			}
			catch (Exception)
			{
				GameObject[] array3 = array2;
				foreach (GameObject val5 in array3)
				{
					if ((Object)(object)val5 != (Object)null)
					{
						Object.Destroy((Object)(object)val5);
					}
				}
				if ((Object)(object)val4 != (Object)null)
				{
					Object.Destroy((Object)(object)val4);
				}
				_capstone = null;
				CapstoneRock = null;
				throw;
			}
			for (int k = 0; k < Plans.Length; k++)
			{
				_rampPrefabs[k] = array2[k];
			}
			_runePrefab = val4;
			DustTemplate = Prefabs.BuildDust(_getBundlePrefab, _container.transform);
			Log.LogInfo((object)string.Concat("Stone Ramp prefabs built (", Style.Value, " rock)", ((Object)(object)DustTemplate == (Object)null) ? "; no dust effect: Rune Magic's vfx_DustCloud not found." : "."));
		}
		foreach (GameObject item in AllPrefabs())
		{
			if (!scene.m_prefabs.Contains(item))
			{
				scene.m_prefabs.Add(item);
			}
		}
		TryFinishPieceSetup();
	}

	internal static void TryFinishPieceSetup()
	{
		if ((Object)(object)_runePrefab == (Object)null || (Object)(object)_capstone == (Object)null || (Object)(object)_table == (Object)null)
		{
			return;
		}
		Piece component = _capstone.GetComponent<Piece>();
		if ((Object)(object)component == (Object)null)
		{
			return;
		}
		Piece component2 = _runePrefab.GetComponent<Piece>();
		if ((Object)(object)component2 == (Object)null)
		{
			return;
		}
		if (!_pieceConfigured)
		{
			Prefabs.ConfigurePiece(component2, component, StyleIcon(Style.Value, component.m_icon));
			_pieceConfigured = true;
		}
		List<GameObject> pieces = _table.m_pieces;
		if (pieces.IndexOf(_capstone) < 0)
		{
			return;
		}
		for (int num = pieces.Count - 1; num >= 0; num--)
		{
			GameObject val = pieces[num];
			if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)_runePrefab && ((Object)val).name == "runemagic_stone_ramp")
			{
				pieces.RemoveAt(num);
			}
		}
		if (pieces.Contains(_runePrefab))
		{
			return;
		}
		int num2 = -1;
		for (int i = 0; i < pieces.Count; i++)
		{
			if ((Object)(object)pieces[i] != (Object)null && ((Object)pieces[i]).name == "runemagic_stone_fortress")
			{
				num2 = i;
			}
		}
		if (num2 < 0)
		{
			num2 = pieces.IndexOf(_capstone);
		}
		pieces.Insert(num2 + 1, _runePrefab);
		Log.LogInfo((object)"Stone Ramp added to the Rune Focus menu.");
	}

	internal static GameObject RampPrefab(int variant)
	{
		if (variant < 0 || variant >= _rampPrefabs.Length)
		{
			return null;
		}
		return _rampPrefabs[variant];
	}

	internal static Material[] StyleMaterials(RockStyle style)
	{
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Expected O, but got Unknown
		//IL_0115: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		if (_styleMaterials.TryGetValue(style, out var value))
		{
			return value;
		}
		Material[] capstoneMaterials = _capstoneMaterials;
		if (capstoneMaterials == null)
		{
			return null;
		}
		Material val = null;
		float num = 11f;
		Material val2 = ((capstoneMaterials.Length > 1) ? capstoneMaterials[1] : capstoneMaterials[0]);
		switch (style)
		{
		case RockStyle.Megalith:
		{
			Material[] array2 = Prefabs.RendererMaterials(FindPrefab("HeathRockPillar_frac"));
			if (array2 == null)
			{
				array2 = Prefabs.RendererMaterials(FindPrefab("HeathRockPillar"));
			}
			if (array2 != null)
			{
				val = array2[0];
				num = 59f;
			}
			break;
		}
		case RockStyle.Arch:
		{
			Material[] array = Prefabs.RendererMaterials(FindPrefab("cliff_ashlands3_Arch_1"));
			if (array != null)
			{
				val = array[0];
				num = 59f;
			}
			break;
		}
		}
		if ((Object)(object)val == (Object)null)
		{
			if (style != RockStyle.Capstone)
			{
				Log.LogWarning((object)string.Concat("The ", style, " rock was not found; using the Capstone's look."));
			}
			val = capstoneMaterials[0];
			num = 11f;
		}
		Material val3 = new Material(val);
		((Object)val3).name = ((Object)val).name + " (Stone Ramp)";
		float num2 = 10f / num;
		string[] texturePropertyNames = val.GetTexturePropertyNames();
		foreach (string text in texturePropertyNames)
		{
			if (val.HasProperty(text))
			{
				val3.SetTextureScale(text, val.GetTextureScale(text) * num2);
			}
		}
		Material[] array3 = (Material[])(object)new Material[2]
		{
			val3,
			(style == RockStyle.Arch) ? val3 : val2
		};
		_styleMaterials[style] = array3;
		return array3;
	}

	private static Sprite StyleIcon(RockStyle style, Sprite fallback)
	{
		GameObject val = FindPrefab(style switch
		{
			RockStyle.Arch => "cliff_ashlands3_Arch_1", 
			RockStyle.Megalith => "HeathRockPillar", 
			_ => "widestone", 
		});
		Piece val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Piece>() : null);
		Sprite source = (((Object)(object)val2 != (Object)null && (Object)(object)val2.m_icon != (Object)null) ? val2.m_icon : fallback);
		return Icon.Compose(source);
	}

	private static void RefreshStyle(object sender, EventArgs e)
	{
		try
		{
			if ((Object)(object)_runePrefab == (Object)null)
			{
				return;
			}
			Material[] array = StyleMaterials(Style.Value);
			if (array == null)
			{
				return;
			}
			foreach (GameObject item in AllPrefabs())
			{
				MeshRenderer[] componentsInChildren = item.GetComponentsInChildren<MeshRenderer>(true);
				foreach (MeshRenderer val in componentsInChildren)
				{
					((Renderer)val).sharedMaterials = array;
				}
			}
			Piece component = _runePrefab.GetComponent<Piece>();
			if ((Object)(object)component != (Object)null && _pieceConfigured && (Object)(object)_capstone != (Object)null)
			{
				Piece component2 = _capstone.GetComponent<Piece>();
				component.m_icon = StyleIcon(Style.Value, ((Object)(object)component2 != (Object)null) ? component2.m_icon : component.m_icon);
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Could not switch the rock style: " + ex.Message));
		}
	}

	private static void RefreshDescription(object sender, EventArgs e)
	{
		if (!((Object)(object)_runePrefab == (Object)null))
		{
			Piece component = _runePrefab.GetComponent<Piece>();
			if ((Object)(object)component != (Object)null && _pieceConfigured)
			{
				component.m_description = Description();
			}
		}
	}

	private static void RefreshRockSettings(object sender, EventArgs e)
	{
		GameObject[] rampPrefabs = _rampPrefabs;
		foreach (GameObject val in rampPrefabs)
		{
			MineRock5 val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<MineRock5>() : null);
			if ((Object)(object)val2 != (Object)null && (Object)(object)CapstoneRock != (Object)null)
			{
				ApplyRockSettings(val2, CapstoneRock);
			}
		}
	}

	internal static void ApplyRockSettings(MineRock5 target, MineRock5 capstone)
	{
		float num = ((BlockHealth != null) ? BlockHealth.Value : 0f);
		target.m_health = ((num > 0f) ? num : capstone.m_health);
		target.m_dropItems = ((DropStone == null || DropStone.Value) ? capstone.m_dropItems : NoDrops);
	}

	static RampPlugin()
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Expected O, but got Unknown
		DropTable val = new DropTable();
		val.m_dropMin = 0;
		val.m_dropMax = 0;
		NoDrops = val;
		_styleMaterials = new Dictionary<RockStyle, Material[]>();
	}
}
internal sealed class MeshData
{
	internal sealed class OuterFan
	{
		internal int Start;

		internal int Count;

		internal Vector3 FaceNormal;

		internal Vector3[] Weights;
	}

	internal readonly List<Vector3> Verts = new List<Vector3>();

	internal readonly List<Vector3> Normals = new List<Vector3>();

	internal readonly List<Vector2> Uvs = new List<Vector2>();

	internal readonly List<int> Outer = new List<int>();

	internal readonly List<int> Inner = new List<int>();

	internal readonly List<OuterFan> Fans = new List<OuterFan>();

	internal void AddPolygon(List<Vector3> pts, Vector3 n, bool outer, Blueprint bp)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: 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)
		//IL_0049: 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)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: 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_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_011b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_0159: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0191: Unknown result type (might be due to invalid IL or missing references)
		//IL_019e: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_029c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0297: Unknown result type (might be due to invalid IL or missing references)
		//IL_0201: Unknown result type (might be due to invalid IL or missing references)
		//IL_0203: Unknown result type (might be due to invalid IL or missing references)
		//IL_0205: Unknown result type (might be due to invalid IL or missing references)
		//IL_020a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0215: Unknown result type (might be due to invalid IL or missing references)
		//IL_021a: Unknown result type (might be due to invalid IL or missing references)
		//IL_021c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0221: Unknown result type (might be due to invalid IL or missing references)
		//IL_0230: Unknown result type (might be due to invalid IL or missing references)
		//IL_0235: Unknown result type (might be due to invalid IL or missing references)
		//IL_0237: Unknown result type (might be due to invalid IL or missing references)
		//IL_023c: Unknown result type (might be due to invalid IL or missing references)
		//IL_024b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0250: Unknown result type (might be due to invalid IL or missing references)
		//IL_0252: Unknown result type (might be due to invalid IL or missing references)
		//IL_0257: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
		int count = pts.Count;
		if (count < 3)
		{
			return;
		}
		Vector3 val = Vector3.zero;
		for (int i = 0; i < count; i++)
		{
			val += pts[i];
		}
		val /= (float)count;
		Vector3 val2 = Vector3.zero;
		for (int j = 0; j < count; j++)
		{
			val2 += Vector3.Cross(pts[j] - val, pts[(j + 1) % count] - val);
		}
		bool flag = Vector3.Dot(val2, n) < 0f;
		int count2 = Verts.Count;
		Vector3[] array = (Vector3[])(object)new Vector3[count + 1];
		ref Vector3 reference = ref array[0];
		reference = Geo.Deform(bp, val);
		for (int k = 0; k < count; k++)
		{
			ref Vector3 reference2 = ref array[k + 1];
			reference2 = Geo.Deform(bp, pts[k]);
		}
		for (int l = 0; l <= count; l++)
		{
			Verts.Add(array[l]);
			Normals.Add(n);
			Uvs.Add(Uv(array[l], n));
		}
		List<int> list = (outer ? Outer : Inner);
		Vector3[] array2 = (Vector3[])(object)(outer ? new Vector3[count + 1] : null);
		Vector3 val3 = Vector3.zero;
		for (int m = 0; m < count; m++)
		{
			int num = 1 + m;
			int num2 = 1 + (m + 1) % count;
			if (flag)
			{
				int num3 = num;
				num = num2;
				num2 = num3;
			}
			Vector3 val4 = Vector3.Cross(array[num] - array[0], array[num2] - array[0]);
			if (!(((Vector3)(ref val4)).sqrMagnitude < 1E-12f))
			{
				list.Add(count2);
				list.Add(count2 + num);
				list.Add(count2 + num2);
				if (outer)
				{
					val3 += val4;
					ref Vector3 reference3 = ref array2[0];
					reference3 += val4;
					ref Vector3 reference4 = ref array2[num];
					reference4 += val4;
					ref Vector3 reference5 = ref array2[num2];
					reference5 += val4;
				}
			}
		}
		if (outer)
		{
			OuterFan outerFan = new OuterFan();
			outerFan.Start = count2;
			outerFan.Count = count + 1;
			outerFan.FaceNormal = ((((Vector3)(ref val3)).sqrMagnitude > 1E-12f) ? ((Vector3)(ref val3)).normalized : n);
			outerFan.Weights = array2;
			Fans.Add(outerFan);
		}
	}

	private static Vector2 Uv(Vector3 p, Vector3 n)
	{
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		float num = Mathf.Abs(n.x);
		float num2 = Mathf.Abs(n.y);
		float num3 = Mathf.Abs(n.z);
		float num4 = 0.1f;
		if (num2 >= num && num2 >= num3)
		{
			return new Vector2(p.x * num4, p.z * num4);
		}
		if (num >= num3)
		{
			return new Vector2(p.z * num4, p.y * num4);
		}
		return new Vector2(p.x * num4, p.y * num4);
	}

	internal void Append(MeshData other)
	{
		int count = Verts.Count;
		Verts.AddRange(other.Verts);
		Normals.AddRange(other.Normals);
		Uvs.AddRange(other.Uvs);
		for (int i = 0; i < other.Outer.Count; i++)
		{
			Outer.Add(other.Outer[i] + count);
		}
		for (int j = 0; j < other.Inner.Count; j++)
		{
			Inner.Add(other.Inner[j] + count);
		}
	}

	internal Bounds GetBounds()
	{
		//IL_001e: 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_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		Bounds result = default(Bounds);
		((Bounds)(ref result))..ctor((Verts.Count > 0) ? Verts[0] : Vector3.zero, Vector3.zero);
		for (int i = 1; i < Verts.Count; i++)
		{
			((Bounds)(ref result)).Encapsulate(Verts[i]);
		}
		return result;
	}

	internal Mesh ToMesh(string name)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		Mesh val = new Mesh();
		((Object)val).name = name;
		if (Verts.Count > 65000)
		{
			val.indexFormat = (IndexFormat)1;
		}
		val.SetVertices(Verts);
		val.SetNormals(Normals);
		val.SetUVs(0, Uvs);
		val.subMeshCount = 2;
		val.SetTriangles(Outer, 0);
		val.SetTriangles(Inner, 1);
		val.RecalculateBounds();
		val.RecalculateTangents();
		return val;
	}
}
internal sealed class PolyFace
{
	internal const int Surface = -1;

	internal const int Seam = -2;

	internal List<Vector3> Pts;

	internal Vector3 N;

	internal int Tag;

	internal PolyFace(List<Vector3> pts, Vector3 n, int tag)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		Pts = pts;
		N = n;
		Tag = tag;
	}
}
internal sealed class Poly
{
	private const float Eps = 1E-05f;

	internal List<PolyFace> Faces = new List<PolyFace>();

	internal Bounds Box;

	internal Poly Clone()
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		Poly poly = new Poly();
		poly.Box = Box;
		for (int i = 0; i < Faces.Count; i++)
		{
			poly.Faces.Add(new PolyFace(new List<Vector3>(Faces[i].Pts), Faces[i].N, Faces[i].Tag));
		}
		return poly;
	}

	internal static Poly FromBox(Vector3 min, Vector3 max)
	{
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: 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)
		//IL_00b4: 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)
		//IL_00cc: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: 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_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0144: 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_0156: Unknown result type (might be due to invalid IL or missing references)
		//IL_0172: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: Unknown result type (might be due to invalid IL or missing references)
		//IL_018b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0204: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_021d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0222: Unknown result type (might be due to invalid IL or missing references)
		//IL_0236: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_0264: Unknown result type (might be due to invalid IL or missing references)
		//IL_0269: Unknown result type (might be due to invalid IL or missing references)
		//IL_027d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0282: Unknown result type (might be due to invalid IL or missing references)
		//IL_0296: Unknown result type (might be due to invalid IL or missing references)
		//IL_029b: Unknown result type (might be due to invalid IL or missing references)
		//IL_02af: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0314: Unknown result type (might be due to invalid IL or missing references)
		//IL_0328: Unknown result type (might be due to invalid IL or missing references)
		//IL_032d: Unknown result type (might be due to invalid IL or missing references)
		//IL_033a: Unknown result type (might be due to invalid IL or missing references)
		//IL_033b: Unknown result type (might be due to invalid IL or missing references)
		//IL_033c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0346: Unknown result type (might be due to invalid IL or missing references)
		//IL_034b: Unknown result type (might be due to invalid IL or missing references)
		//IL_034c: Unknown result type (might be due to invalid IL or missing references)
		//IL_034d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0352: Unknown result type (might be due to invalid IL or missing references)
		//IL_0357: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		Poly poly = new Poly();
		Vector3[] array = (Vector3[])(object)new Vector3[8];
		for (int i = 0; i < 8; i++)
		{
			ref Vector3 reference = ref array[i];
			reference = new Vector3(((i & 1) == 0) ? min.x : max.x, ((i & 2) == 0) ? min.y : max.y, ((i & 4) == 0) ? min.z : max.z);
		}
		poly.Add(Vector3.left, array[0], array[2], array[6], array[4]);
		poly.Add(Vector3.right, array[1], array[5], array[7], array[3]);
		poly.Add(Vector3.down, array[0], array[4], array[5], array[1]);
		poly.Add(Vector3.up, array[2], array[3], array[7], array[6]);
		poly.Add(Vector3.back, array[0], array[1], array[3], array[2]);
		poly.Add(Vector3.forward, array[4], array[6], array[7], array[5]);
		poly.Box = new Bounds((min + max) * 0.5f, max - min);
		return poly;
	}

	internal static Poly FromPrism(Vector2 a, Vector2 b, Vector2 c, float z0, float z1)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//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_0113: 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_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_013a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0154: Unknown result type (might be due to invalid IL or missing references)
		//IL_0159: Unknown result type (might be due to invalid IL or missing references)
		//IL_0166: Unknown result type (might be due to invalid IL or missing references)
		//IL_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_016d: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Unknown result type (might be due to invalid IL or missing references)
		//IL_0195: 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_0199: Unknown result type (might be due to invalid IL or missing references)
		//IL_019b: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_0291: Unknown result type (might be due to invalid IL or missing references)
		//IL_0296: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cd: 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_02f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01db: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0204: Unknown result type (might be due to invalid IL or missing references)
		//IL_0220: Unknown result type (might be due to invalid IL or missing references)
		//IL_0225: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0247: Unknown result type (might be due to invalid IL or missing references)
		//IL_0264: Unknown result type (might be due to invalid IL or missing references)
		//IL_0269: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
		Poly poly = new Poly();
		Vector2[] array = (Vector2[])(object)new Vector2[3] { a, b, c };
		Vector2 val = (a + b + c) / 3f;
		poly.Add(Vector3.back, new Vector3(a.x, a.y, z0), new Vector3(b.x, b.y, z0), new Vector3(c.x, c.y, z0));
		poly.Add(Vector3.forward, new Vector3(a.x, a.y, z1), new Vector3(c.x, c.y, z1), new Vector3(b.x, b.y, z1));
		for (int i = 0; i < 3; i++)
		{
			Vector2 val2 = array[i];
			Vector2 val3 = array[(i + 1) % 3];
			Vector2 val4 = val3 - val2;
			Vector2 val5 = new Vector2(val4.y, 0f - val4.x);
			Vector2 val6 = ((Vector2)(ref val5)).normalized;
			if (Vector2.Dot(val6, (val2 + val3) * 0.5f - val) < 0f)
			{
				val6 = -val6;
			}
			poly.Add(new Vector3(val6.x, val6.y, 0f), new Vector3(val2.x, val2.y, z0), new Vector3(val3.x, val3.y, z0), new Vector3(val3.x, val3.y, z1), new Vector3(val2.x, val2.y, z1));
		}
		Bounds box = default(Bounds);
		((Bounds)(ref box))..ctor(new Vector3(a.x, a.y, z0), Vector3.zero);
		((Bounds)(ref box)).Encapsulate(new Vector3(b.x, b.y, z0));
		((Bounds)(ref box)).Encapsulate(new Vector3(c.x, c.y, z1));
		((Bounds)(ref box)).Encapsulate(new Vector3(a.x, a.y, z1));
		poly.Box = box;
		return poly;
	}

	private void Add(Vector3 n, params Vector3[] pts)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		Faces.Add(new PolyFace(new List<Vector3>(pts), n, -1));
	}

	internal bool Clip(Vector3 n, float d, int tag)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: 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)
		//IL_00cb: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a1: 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_013d: 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_0141: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: 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_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		bool flag = false;
		bool flag2 = false;
		for (int i = 0; i < Faces.Count; i++)
		{
			List<Vector3> pts = Faces[i].Pts;
			for (int j = 0; j < pts.Count; j++)
			{
				float num = Vector3.Dot(n, pts[j]) - d;
				if (num > 1E-05f)
				{
					flag = true;
				}
				else if (num < -1E-05f)
				{
					flag2 = true;
				}
			}
		}
		if (!flag)
		{
			return true;
		}
		if (!flag2)
		{
			Faces.Clear();
			return false;
		}
		List<PolyFace> list = new List<PolyFace>();
		List<Vector3> list2 = new List<Vector3>();
		for (int k = 0; k < Faces.Count; k++)
		{
			List<Vector3> pts2 = Faces[k].Pts;
			List<Vector3> list3 = new List<Vector3>();
			int count = pts2.Count;
			for (int l = 0; l < count; l++)
			{
				Vector3 val = pts2[l];
				Vector3 val2 = pts2[(l + 1) % count];
				float num2 = Vector3.Dot(n, val) - d;
				float num3 = Vector3.Dot(n, val2) - d;
				if (num2 <= 1E-05f)
				{
					list3.Add(val);
					if (num2 >= -1E-05f)
					{
						list2.Add(val);
					}
				}
				if ((num2 < -1E-05f && num3 > 1E-05f) || (num2 > 1E-05f && num3 < -1E-05f))
				{
					Vector3 item = val + (val2 - val) * (num2 / (num2 - num3));
					list3.Add(item);
					list2.Add(item);
				}
			}
			list3 = Unique(list3);
			if (list3.Count >= 3)
			{
				list.Add(new PolyFace(list3, Faces[k].N, Faces[k].Tag));
			}
		}
		list2 = Unique(list2);
		if (list2.Count >= 3)
		{
			Order(list2, n);
			list.Add(new PolyFace(list2, n, tag));
		}
		Faces = list;
		return Faces.Count >= 4;
	}

	private static List<Vector3> Unique(List<Vector3> pts)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: 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)
		List<Vector3> list = new List<Vector3>();
		for (int i = 0; i < pts.Count; i++)
		{
			bool flag = false;
			for (int j = 0; j < list.Count; j++)
			{
				Vector3 val = list[j] - pts[i];
				if (((Vector3)(ref val)).sqrMagnitude < 1E-08f)
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				list.Add(pts[i]);
			}
		}
		return list;
	}

	private static void Order(List<Vector3> pts, Vector3 n)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: 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_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: 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_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: 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_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: 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_009e: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = Vector3.zero;
		for (int i = 0; i < pts.Count; i++)
		{
			val += pts[i];
		}
		val /= (float)pts.Count;
		Vector3 val2 = Vector3.Cross(n, (Mathf.Abs(n.y) < 0.9f) ? Vector3.up : Vector3.right);
		Vector3 normalized = ((Vector3)(ref val2)).normalized;
		Vector3 val3 = Vector3.Cross(n, normalized);
		float[] array = new float[pts.Count];
		Vector3[] array2 = pts.ToArray();
		for (int j = 0; j < array2.Length; j++)
		{
			Vector3 val4 = array2[j] - val;
			array[j] = Mathf.Atan2(Vector3.Dot(val4, val3), Vector3.Dot(val4, normalized));
		}
		Array.Sort(array, array2);
		pts.Clear();
		pts.AddRange(array2);
	}
}
internal sealed class Welder
{
	private readonly float _tol;

	private readonly float _cell;

	private readonly Dictionary<long, List<Vector3>> _grid = new Dictionary<long, List<Vector3>>();

	internal Welder(float tolerance)
	{
		_tol = tolerance;
		_cell = tolerance * 2f;
	}

	private long Key(int x, int y, int z)
	{
		return ((long)x * 73856093L) ^ ((long)y * 19349663L) ^ ((long)z * 83492791L);
	}

	internal Vector3 Weld(Vector3 p)
	{
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: 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)
		int num = Mathf.FloorToInt(p.x / _cell);
		int num2 = Mathf.FloorToInt(p.y / _cell);
		int num3 = Mathf.FloorToInt(p.z / _cell);
		float num4 = _tol * _tol;
		for (int i = -1; i <= 1; i++)
		{
			for (int j = -1; j <= 1; j++)
			{
				for (int k = -1; k <= 1; k++)
				{
					if (!_grid.TryGetValue(Key(num + i, num2 + j, num3 + k), out var value))
					{
						continue;
					}
					for (int l = 0; l < value.Count; l++)
					{
						Vector3 val = value[l] - p;
						if (((Vector3)(ref val)).sqrMagnitude <= num4)
						{
							return value[l];
						}
					}
				}
			}
		}
		long key = Key(num, num2, num3);
		if (!_grid.TryGetValue(key, out var value2))
		{
			value2 = new List<Vector3>();
			_grid[key] = value2;
		}
		value2.Add(p);
		return p;
	}

	internal List<Vector3> WeldPolygon(List<Vector3> pts)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		List<Vector3> list = new List<Vector3>();
		for (int i = 0; i < pts.Count; i++)
		{
			Vector3 val = Weld(pts[i]);
			if (list.Count == 0 || list[list.Count - 1] != val)
			{
				list.Add(val);
			}
		}
		while (list.Count > 1 && list[0] == list[list.Count - 1])
		{
			list.RemoveAt(list.Count - 1);
		}
		return list;
	}
}
internal sealed class BlockDef
{
	internal MeshData Data;

	internal Mesh Mesh;
}
internal sealed class Blueprint
{
	internal int Height;

	internal float Run;

	internal float End;

	internal readonly List<BlockDef> Blocks = new List<BlockDef>();

	internal readonly List<Vector3> WardSamples = new List<Vector3>();

	internal readonly List<Vector3> DustPoints = new List<Vector3>();

	internal Mesh GhostMesh;

	internal float MinY;

	internal float MaxY;

	internal float RiseDepth => MaxY - MinY;
}
internal static class Geo
{
	private struct PosKey : IEquatable<PosKey>
	{
		private readonly int _x;

		private readonly int _y;

		private readonly int _z;

		internal PosKey(Vector3 p)
		{
			_x = Mathf.RoundToInt(p.x * 1000f);
			_y = Mathf.RoundToInt(p.y * 1000f);
			_z = Mathf.RoundToInt(p.z * 1000f);
		}

		public bool Equals(PosKey o)
		{
			if (_x == o._x && _y == o._y)
			{
				return _z == o._z;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj is PosKey)
			{
				return Equals((PosKey)obj);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (_x * 73856093) ^ (_y * 19349663) ^ (_z * 83492791);
		}
	}

	private struct Contribution
	{
		internal Vector3 Face;

		internal Vector3 Weight;
	}

	internal const float HalfWidth = 2f;

	internal const float TanSlope = 0.57735026f;

	internal const float Landing = 4f;

	internal const float Footing = 4f;

	internal const float RoundRadius = 0.6f;

	internal const float UvMetres = 10f;

	private const float NoiseAmp1 = 0.45f;

	private const float NoiseScale1 = 3.2f;

	private const float NoiseAmp2 = 0.13f;

	private const float NoiseScale2 = 1.3f;

	private const float PathNoise = 0.1f;

	private const float PathBand = 1.5f;

	private const float SeedStep = 2.4f;

	private const float MaxReach = 3.3f;

	internal static readonly int[] Heights = new int[3] { 10, 15, 20 };

	internal static bool DebugNoDeform;

	internal static uint Checksum(Blueprint[] plans)
	{
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: 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)
		uint num = 2166136261u;
		for (int i = 0; i < plans.Length; i++)
		{
			List<BlockDef> blocks = plans[i].Blocks;
			num = (num ^ (uint)blocks.Count) * 16777619;
			for (int j = 0; j < blocks.Count; j++)
			{
				List<Vector3> verts = blocks[j].Data.Verts;
				num = (num ^ (uint)verts.Count) * 16777619;
				for (int k = 0; k < verts.Count; k += 7)
				{
					num = (num ^ (uint)Mathf.RoundToInt(verts[k].x * 1000f)) * 16777619;
					num = (num ^ (uint)Mathf.RoundToInt(verts[k].y * 1000f)) * 16777619;
					num = (num ^ (uint)Mathf.RoundToInt(verts[k].z * 1000f)) * 16777619;
				}
			}
		}
		return num;
	}

	internal static Blueprint Build(int height)
	{
		Blueprint blueprint = Layout(height);
		MeshData meshData = new MeshData();
		for (int i = 0; i < blueprint.Blocks.Count; i++)
		{
			BlockDef blockDef = blueprint.Blocks[i];
			blockDef.Mesh = blockDef.Data.ToMesh("RampRock_" + height + "_" + i.ToString("D3"));
			meshData.Append(blockDef.Data);
		}
		blueprint.GhostMesh = meshData.ToMesh("RampGhost_" + height);
		return blueprint;
	}

	internal static float Top(Blueprint bp, float z)
	{
		return Mathf.Min(Mathf.Max(z, 0f) * 0.57735026f, (float)bp.Height);
	}

	private static List<Poly> Pieces(Blueprint bp)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		float num = 1.4f;
		float[] array = new float[4]
		{
			-2f,
			0f - num,
			num,
			2f
		};
		Vector3 val = new Vector3(0f, 1f, -0.57735026f);
		Vector3 normalized = ((Vector3)(ref val)).normalized;
		List<Poly> list = new List<Poly>();
		for (int i = 0; i + 1 < array.Length; i++)
		{
			Poly poly = Poly.FromBox(new Vector3(array[i], -4f, 0f), new Vector3(array[i + 1], (float)bp.Height, bp.End));
			if (!poly.Clip(normalized, 0f, -1))
			{
				throw new InvalidOperationException("A ramp strip came out empty");
			}
			list.Add(poly);
		}
		MarkSeams(list);
		return list;
	}

	private static void MarkSeams(List<Poly> pieces)
	{
		Dictionary<string, int> dictionary = new Dictionary<string, int>();
		List<string> list = new List<string>();
		for (int i = 0; i < pieces.Count; i++)
		{
			for (int j = 0; j < pieces[i].Faces.Count; j++)
			{
				string text = FaceKey(pieces[i].Faces[j].Pts);
				list.Add(text);
				dictionary.TryGetValue(text, out var value);
				dictionary[text] = value + 1;
			}
		}
		int num = 0;
		for (int k = 0; k < pieces.Count; k++)
		{
			for (int l = 0; l < pieces[k].Faces.Count; l++)
			{
				if (dictionary[list[num++]] > 1)
				{
					pieces[k].Faces[l].Tag = -2;
				}
			}
		}
	}

	private static string FaceKey(List<Vector3> pts)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		List<string> list = new List<string>();
		for (int i = 0; i < pts.Count; i++)
		{
			list.Add(Mathf.RoundToInt(pts[i].x * 1000f) + "," + Mathf.RoundToInt(pts[i].y * 1000f) + "," + Mathf.RoundToInt(pts[i].z * 1000f));
		}
		list.Sort(StringComparer.Ordinal);
		return string.Join(";", list.ToArray());
	}

	internal static Blueprint Layout(int height)
	{
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_024e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0311: Unknown result type (might be due to invalid IL or missing references)
		//IL_0330: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0416: Unknown result type (might be due to invalid IL or missing references)
		//IL_042b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0445: Unknown result type (might be due to invalid IL or missing references)
		//IL_0459: 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_0135: 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_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: 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_0147: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: 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_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0151: 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_015d: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
		Blueprint blueprint = new Blueprint();
		blueprint.Height = height;
		blueprint.Run = (float)height / 0.57735026f;
		blueprint.End = blueprint.Run + 4f;
		List<Poly> list = Pieces(blueprint);
		List<Vector3> list2 = Seeds(blueprint, 4001 + height * 7);
		float num = Reach(blueprint, list2);
		List<List<PolyFace>> list3 = new List<List<PolyFace>>();
		for (int i = 0; i < list2.Count; i++)
		{
			Vector3 val = list2[i];
			List<int> list4 = new List<int>();
			List<float> list5 = new List<float>();
			for (int j = 0; j < list2.Count; j++)
			{
				Vector3 val2 = list2[j] - val;
				float magnitude = ((Vector3)(ref val2)).magnitude;
				if (j != i && magnitude <= 2f * num + 0.2f)
				{
					list4.Add(j);
					list5.Add(magnitude);
				}
			}
			int[] array = list4.ToArray();
			Array.Sort(list5.ToArray(), array);
			List<PolyFace> list6 = new List<PolyFace>();
			for (int k = 0; k < list.Count; k++)
			{
				if (DistanceToBox(list[k].Box, val) > num + 0.1f)
				{
					continue;
				}
				Poly poly = list[k].Clone();
				bool flag = true;
				for (int l = 0; l < array.Length; l++)
				{
					if (!flag)
					{
						break;
					}
					Vector3 val3 = list2[array[l]];
					Vector3 val4 = val3 - val;
					Vector3 normalized = ((Vector3)(ref val4)).normalized;
					flag = poly.Clip(normalized, Vector3.Dot(normalized, (val3 + val) * 0.5f), array[l]);
				}
				if (flag)
				{
					list6.AddRange(poly.Faces);
				}
			}
			list6.RemoveAll((PolyFace face) => face.Tag == -2);
			if (list6.Count > 0)
			{
				list3.Add(list6);
			}
		}
		Welder welder = new Welder(0.002f);
		for (int num2 = 0; num2 < list3.Count; num2++)
		{
			MeshData meshData = new MeshData();
			List<PolyFace> list7 = list3[num2];
			for (int num3 = 0; num3 < list7.Count; num3++)
			{
				List<Vector3> list8 = welder.WeldPolygon(list7[num3].Pts);
				if (list8.Count >= 3)
				{
					meshData.AddPolygon(list8, list7[num3].N, list7[num3].Tag == -1, blueprint);
				}
			}
			if (meshData.Outer.Count + meshData.Inner.Count != 0)
			{
				BlockDef blockDef = new BlockDef();
				blockDef.Data = meshData;
				blueprint.Blocks.Add(blockDef);
			}
		}
		SmoothSurface(blueprint);
		blueprint.MinY = float.MaxValue;
		blueprint.MaxY = float.MinValue;
		for (int num4 = 0; num4 < blueprint.Blocks.Count; num4++)
		{
			List<Vector3> verts = blueprint.Blocks[num4].Data.Verts;
			for (int num5 = 0; num5 < verts.Count; num5++)
			{
				blueprint.MinY = Mathf.Min(blueprint.MinY, verts[num5].y);
				blueprint.MaxY = Mathf.Max(blueprint.MaxY, verts[num5].y);
			}
		}
		int num6 = Mathf.CeilToInt(blueprint.End / 2f);
		for (int num7 = 0; num7 <= num6; num7++)
		{
			float num8 = Mathf.Min((float)num7 * 2f, blueprint.End);
			for (int num9 = -1; num9 <= 1; num9++)
			{
				blueprint.WardSamples.Add(new Vector3((float)num9 * 2f, 0f, num8));
			}
		}
		AddDustLine(blueprint, new Vector3(-2f, 0f, 0f), new Vector3(-2f, 0f, blueprint.End));
		AddDustLine(blueprint, new Vector3(2f, 0f, 0f), new Vector3(2f, 0f, blueprint.End));
		AddDustLine(blueprint, new Vector3(-2f, 0f, 0f), new Vector3(2f, 0f, 0f));
		return blueprint;
	}

	private static void AddDustLine(Blueprint bp, Vector3 a, Vector3 b)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		int num = Mathf.Max(2, Mathf.RoundToInt(Vector3.Distance(a, b) / 3.5f));
		for (int i = 0; i < num; i++)
		{
			bp.DustPoints.Add(Vector3.Lerp(a, b, ((float)i + 0.5f) / (float)num));
		}
	}

	internal static bool InSolid(Blueprint bp, Vector3 p)
	{
		if (Mathf.Abs(p.x) <= 2f && p.y >= -4f && p.z >= 0f && p.z <= bp.End)
		{
			return p.y <= Top(bp, p.z);
		}
		return false;
	}

	private static List<Vector3> Seeds(Blueprint bp, int randomSeed)
	{
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
		Random rng = new Random(randomSeed);
		List<Vector3> list = new List<Vector3>();
		for (float num = 1.2f; num < bp.End; num += 2.4f)
		{
			for (float num2 = -2.8f; num2 < (float)bp.Height; num2 += 2.4f)
			{
				for (int i = 0; i < 2; i++)
				{
					float num3 = ((i == 0) ? (-1f) : 1f);
					float num4 = Jitter(rng, 0.35f);
					float num5 = Jitter(rng, 0.5f);
					float num6 = Jitter(rng, 0.5f);
					TryAddSeed(bp, list, new Vector3(num3 + num4, num2 + num5, num + num6));
				}
			}
		}
		for (float num7 = 0.6f; num7 < 4.8f; num7 += 1.2f)
		{
			for (int j = 0; j < 2; j++)
			{
				float num8 = ((j == 0) ? (-1f) : 1f);
				TryAddSeed(bp, list, new Vector3(num8 + Jitter(rng, 0.2f), Top(bp, num7) - 0.35f, num7));
			}
		}
		return list;
	}

	private static void TryAddSeed(Blueprint bp, List<Vector3> seeds, Vector3 p)
	{
		//IL_0001: 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_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		if (!InSolid(bp, p))
		{
			return;
		}
		for (int i = 0; i < seeds.Count; i++)
		{
			Vector3 val = seeds[i] - p;
			if (((Vector3)(ref val)).sqrMagnitude < 0.64000005f)
			{
				return;
			}
		}
		seeds.Add(p);
	}

	private static float Reach(Blueprint bp, List<Vector3> seeds)
	{
		//IL_002c: 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)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		float num = 0f;
		Vector3 val = default(Vector3);
		for (float num2 = -1.75f; num2 < 2f; num2 += 0.5f)
		{
			for (float num3 = 0.25f; num3 < bp.End; num3 += 0.5f)
			{
				for (float num4 = -3.75f; num4 < (float)bp.Height; num4 += 0.5f)
				{
					((Vector3)(ref val))..ctor(num2, num4, num3);
					if (!InSolid(bp, val))
					{
						continue;
					}
					float num5 = float.MaxValue;
					for (int i = 0; i < seeds.Count; i++)
					{
						Vector3 val2 = seeds[i] - val;
						float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
						if (sqrMagnitude < num5)
						{
							num5 = sqrMagnitude;
						}
					}
					num = Mathf.Max(num, num5);
				}
			}
		}
		float num6 = Mathf.Sqrt(num) + 0.4f;
		if (num6 > 3.3f)
		{
			throw new InvalidOperationException("Ramp seeds leave a gap (" + num6.ToString("F2") + " m)");
		}
		return num6;
	}

	internal static Vector3 Deform(Blueprint bp, Vector3 p)
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: 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_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//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_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		if (DebugNoDeform)
		{
			return p;
		}
		Vector3 val = Round(bp, p);
		Vector3 val2 = new Vector3(Noise(p / 3.2f, 11), Noise(p / 3.2f, 23), Noise(p / 3.2f, 37)) * 0.45f + new Vector3(Noise(p / 1.3f, 41), Noise(p / 1.3f, 53), Noise(p / 1.3f, 67)) * 0.13f;
		float num = Top(bp, p.z) - p.y;
		float num2 = Mathf.Lerp(0.1f, 1f, Mathf.SmoothStep(0f, 1f, Mathf.Clamp01(num / 1.5f)));
		return val + val2 * num2;
	}

	private static Vector3 Round(Blueprint bp, Vector3 p)
	{
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//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)
		float num = 0.6f;
		float num2 = 2f - num;
		Vector3 val = default(Vector3);
		((Vector3)(ref val))..ctor(Mathf.Clamp(p.x, 0f - num2, num2), Mathf.Min(p.y, Top(bp, p.z) - num), Mathf.Min(p.z, bp.End - num));
		Vector3 val2 = p - val;
		float magnitude = ((Vector3)(ref val2)).magnitude;
		if (magnitude <= num || magnitude < 1E-06f)
		{
			return p;
		}
		return val + val2 * (num / magnitude);
	}

	private static float Jitter(Random rng, float amount)
	{
		return (float)(rng.NextDouble() * 2.0 - 1.0) * amount;
	}

	private static float DistanceToBox(Bounds b, Vector3 p)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		Vector3 min = ((Bounds)(ref b)).min;
		Vector3 max = ((Bounds)(ref b)).max;
		Vector3 val = default(Vector3);
		((Vector3)(ref val))..ctor(Mathf.Clamp(p.x, min.x, max.x), Mathf.Clamp(p.y, min.y, max.y), Mathf.Clamp(p.z, min.z, max.z));
		Vector3 val2 = val - p;
		return ((Vector3)(ref val2)).magnitude;
	}

	private static float Noise(Vector3 p, int seed)
	{
		int num = Mathf.FloorToInt(p.x);
		int num2 = Mathf.FloorToInt(p.y);
		int num3 = Mathf.FloorToInt(p.z);
		float num4 = p.x - (float)num;
		float num5 = p.y - (float)num2;
		float num6 = p.z - (float)num3;
		float num7 = num4 * num4 * (3f - 2f * num4);
		float num8 = num5 * num5 * (3f - 2f * num5);
		float num9 = num6 * num6 * (3f - 2f * num6);
		float num10 = Hash(num, num2, num3, seed);
		float num11 = Hash(num + 1, num2, num3, seed);
		float num12 = Hash(num, num2 + 1, num3, seed);
		float num13 = Hash(num + 1, num2 + 1, num3, seed);
		float num14 = Hash(num, num2, num3 + 1, seed);
		float num15 = Hash(num + 1, num2, num3 + 1, seed);
		float num16 = Hash(num, num2 + 1, num3 + 1, seed);
		float num17 = Hash(num + 1, num2 + 1, num3 + 1, seed);
		float num18 = Mathf.Lerp(Mathf.Lerp(num10, num11, num7), Mathf.Lerp(num12, num13, num7), num8);
		float num19 = Mathf.Lerp(Mathf.Lerp(num14, num15, num7), Mathf.Lerp(num16, num17, num7), num8);
		return Mathf.Lerp(num18, num19, num9);
	}

	private static float Hash(int x, int y, int z, int seed)
	{
		uint num = (uint)(x * 374761393 + y * 668265263 + z * -2048144777 + seed * -1028477379);
		num = (num ^ (num >> 13)) * 1274126177;
		num ^= num >> 16;
		return (float)(num & 0xFFFFFF) / (26353588f / (float)Math.PI) - 1f;
	}

	private static void SmoothSurface(Blueprint bp)
	{
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: 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_0137: 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_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		//IL_0185: Unknown result type (might be due to invalid IL or missing references)
		//IL_018a: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		Dictionary<PosKey, List<Contribution>> dictionary = new Dictionary<PosKey, List<Contribution>>();
		for (int i = 0; i < bp.Blocks.Count; i++)
		{
			MeshData data = bp.Blocks[i].Data;
			for (int j = 0; j < data.Fans.Count; j++)
			{
				MeshData.OuterFan outerFan = data.Fans[j];
				for (int k = 0; k < outerFan.Count; k++)
				{
					PosKey key = new PosKey(data.Verts[outerFan.Start + k]);
					if (!dictionary.TryGetValue(key, out var value))
					{
						value = (dictionary[key] = new List<Contribution>());
					}
					Contribution item = new Contribution
					{
						Face = outerFan.FaceNormal,
						Weight = outerFan.Weights[k]
					};
					value.Add(item);
				}
			}
		}
		for (int l = 0; l < bp.Blocks.Count; l++)
		{
			MeshData data2 = bp.Blocks[l].Data;
			for (int m = 0; m < data2.Fans.Count; m++)
			{
				MeshData.OuterFan outerFan2 = data2.Fans[m];
				for (int n = 0; n < outerFan2.Count; n++)
				{
					List<Contribution> list2 = dictionary[new PosKey(data2.Verts[outerFan2.Start + n])];
					Vector3 val = Vector3.zero;
					for (int num = 0; num < list2.Count; num++)
					{
						if (Vector3.Dot(list2[num].Face, outerFan2.FaceNormal) > 0.5f)
						{
							val += list2[num].Weight;
						}
					}
					data2.Normals[outerFan2.Start + n] = ((((Vector3)(ref val)).sqrMagnitude > 1E-12f) ? ((Vector3)(ref val)).normalized : outerFan2.FaceNormal);
				}
			}
		}
	}
}
internal static class Prefabs
{
	internal static Material[] RendererMaterials(GameObject rock)
	{
		if ((Object)(object)rock == (Object)null)
		{
			return null;
		}
		Material[] array = null;
		MeshRenderer[] componentsInChildren = rock.GetComponentsInChildren<MeshRenderer>(true);
		foreach (MeshRenderer val in componentsInChildren)
		{
			Material[] array2 = (((Object)(object)val != (Object)null) ? ((Renderer)val).sharedMaterials : null);
			if (array2 != null && array2.Length != 0 && !((Object)(object)array2[0] == (Object)null) && (array == null || array2.Length > array.Length))
			{
				array = array2;
			}
		}
		return array;
	}

	internal static GameObject BuildRamp(string name, Blueprint plan, int variant, Material[] materials, MineRock5 capstone, int layer, Transform container)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_013a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_018b: Expected O, but got Unknown
		GameObject val = new GameObject(name);
		val.transform.SetParent(container, false);
		val.layer = layer;
		ZNetView val2 = val.AddComponent<ZNetView>();
		val2.m_persistent = true;
		val2.m_distant = true;
		val2.m_type = (ObjectType)2;
		val2.m_syncInitialScale = false;
		RampDamageGuard rampDamageGuard = val.AddComponent<RampDamageGuard>();
		rampDamageGuard.ChunkCount = plan.Blocks.Count;
		MineRock5 val3 = val.AddComponent<MineRock5>();
		val3.m_name = "Ramp rock";
		val3.m_damageModifiers = capstone.m_damageModifiers;
		val3.m_minToolTier = capstone.m_minToolTier;
		val3.m_supportCheck = false;
		val3.m_triggerPrivateArea = capstone.m_triggerPrivateArea;
		val3.m_destroyedEffect = capstone.m_destroyedEffect;
		val3.m_hitEffect = capstone.m_hitEffect;
		val3.m_hitEffectAreaCenter = false;
		val3.m_hoverOffset = capstone.m_hoverOffset;
		RampPlugin.ApplyRockSettings(val3, capstone);
		RampRiser rampRiser = val.AddComponent<RampRiser>();
		rampRiser.Variant = variant;
		LODGroup val4 = val.AddComponent<LODGroup>();
		val4.SetLODs((LOD[])(object)new LOD[1]
		{
			new LOD(0.01f, (Renderer[])(object)new Renderer[0])
		});
		val4.localReferencePoint = new Vector3(0f, (plan.MinY + plan.MaxY) * 0.5f, plan.End * 0.5f);
		val4.size = plan.End + 2f;
		for (int i = 0; i < plan.Blocks.Count; i++)
		{
			BlockDef blockDef = plan.Blocks[i];
			GameObject val5 = new GameObject("Rock_" + i.ToString("D3"));
			val5.transform.SetParent(val.transform, false);
			val5.layer = layer;
			MeshFilter val6 = val5.AddComponent<MeshFilter>();
			val6.sharedMesh = blockDef.Mesh;
			MeshRenderer val7 = val5.AddComponent<MeshRenderer>();
			((Renderer)val7).sharedMaterials = materials;
			MeshCollider val8 = val5.AddComponent<MeshCollider>();
			val8.sharedMesh = blockDef.Mesh;
			val8.convex = false;
			try
			{
				Physics.BakeMesh(((Object)blockDef.Mesh).GetInstanceID(), false);
			}
			catch (Exception)
			{
			}
		}
		return val;
	}

	internal static GameObject BuildRune(Material[] materials, Transform container)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Expected O, but got Unknown
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Expected O, but got Unknown
		GameObject val = new GameObject("runemagic_stone_ramp");
		val.transform.SetParent(container, false);
		ZNetView val2 = val.AddComponent<ZNetView>();
		val2.m_persistent = false;
		val2.m_distant = false;
		val2.m_type = (ObjectType)0;
		val2.m_syncInitialScale = false;
		Piece val3 = val.AddComponent<Piece>();
		val3.m_name = "Rune of the Stonecaller: Ramp";
		val3.m_enabled = false;
		val.AddComponent<RampRune>();
		for (int i = 0; i < RampPlugin.Plans.Length; i++)
		{
			GameObject val4 = new GameObject("Ghost_" + i);
			val4.transform.SetParent(val.transform, false);
			val4.AddComponent<MeshFilter>().sharedMesh = RampPlugin.Plans[i].GhostMesh;
			((Renderer)val4.AddComponent<MeshRenderer>()).sharedMaterials = materials;
		}
		return val;
	}

	internal static GameObject BuildDust(MethodInfo getPrefab, Transform container)
	{
		if (getPrefab == null)
		{
			return null;
		}
		try
		{
			object? obj = getPrefab.Invoke(null, new object[1] { "vfx_DustCloud" });
			GameObject val = (GameObject)((obj is GameObject) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, container, false);
			((Object)val2).name = "StoneRamp_Dust";
			TimedDestruction[] componentsInChildren = val2.GetComponentsInChildren<TimedDestruction>(true);
			foreach (TimedDestruction val3 in componentsInChildren)
			{
				Object.DestroyImmediate((Object)(object)val3);
			}
			ZNetView[] componentsInChildren2 = val2.GetComponentsInChildren<ZNetView>(true);
			foreach (ZNetView val4 in componentsInChildren2)
			{
				Object.DestroyImmediate((Object)(object)val4);
			}
			return val2;
		}
		catch (Exception ex)
		{
			Exception ex2 = ((ex.InnerException != null) ? ex.InnerException : ex);
			RampPlugin.Log.LogWarning((object)("Dust effect unavailable: " + ex2.Message));
			return null;
		}
	}

	internal static void ConfigurePiece(Piece piece, Piece capstone, Sprite icon)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Expected O, but got Unknown
		piece.m_category = capstone.m_category;
		piece.m_usage = capstone.m_usage;
		piece.m_groundPiece = capstone.m_groundPiece;
		piece.m_groundOnly = capstone.m_groundOnly;
		piece.m_allowedInDeepSnow = capstone.m_allowedInDeepSnow;
		piece.m_clipEverything = capstone.m_clipEverything;
		piece.m_noInWater = capstone.m_noInWater;
		piece.m_notOnFloor = capstone.m_notOnFloor;
		piece.m_cultivatedGroundOnly = capstone.m_cultivatedGroundOnly;
		piece.m_allowedInDungeons = capstone.m_allowedInDungeons;
		piece.m_waterPiece = capstone.m_waterPiece;
		piece.m_onlyInBiome = capstone.m_onlyInBiome;
		piece.m_comfortGroup = capstone.m_comfortGroup;
		piece.m_canBeRemoved = capstone.m_canBeRemoved;
		piece.m_randomInitBuildRotation = false;
		piece.m_placeEffect = new EffectList();
		piece.m_resources = (Requirement[])(object)new Requirement[0];
		piece.m_description = RampPlugin.Description();
		piece.m_icon = (((Object)(object)icon != (Object)null) ? icon : capstone.m_icon);
		piece.m_enabled = true;
	}
}
internal static class Layout
{
	internal const float Sink = 0.3f;

	internal static Quaternion BaseRotation(Vector3 rootPos, Quaternion rootRot)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: 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)
		if (RampPlugin.AlignToView != null && !RampPlugin.AlignToView.Value)
		{
			return rootRot;
		}
		Player localPlayer = Player.m_localPlayer;
		Vector3 val = Vector3.zero;
		if ((Object)(object)GameCamera.instance != (Object)null)
		{
			val = ((Component)GameCamera.instance).transform.forward;
			val.y = 0f;
		}
		if (((Vector3)(ref val)).sqrMagnitude < 0.0001f && (Object)(object)localPlayer != (Object)null)
		{
			val = rootPos - ((Component)localPlayer).transform.position;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude < 0.25f)
			{
				val = ((Component)localPlayer).transform.forward;
				val.y = 0f;
			}
		}
		if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
		{
			return rootRot;
		}
		float num = Mathf.Atan2(val.x, val.z) * 57.29578f;
		return Quaternion.Euler(0f, num + ((Quaternion)(ref rootRot)).eulerAngles.y, 0f);
	}

	internal static void Pose(Vector3 aimed, Quaternion pieceRot, out Vector3 position, out Quaternion rotation)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//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)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		rotation = BaseRotation(aimed, pieceRot);
		position = aimed - Vector3.up * 0.3f;
	}
}
public class RampRune : MonoBehaviour
{
	private bool _ghost;

	private bool _done;

	private float _created;

	private ZNetView _nview;

	private Transform[] _previews;

	private MeshRenderer[] _renderers;

	private void Awake()
	{
		_ghost = ZNetView.m_forceDisableInit;
		int num = RampPlugin.Plans.Length;
		_previews = (Transform[])(object)new Transform[num];
		_renderers = (MeshRenderer[])(object)new MeshRenderer[num];
		for (int i = 0; i < num; i++)
		{
			_previews[i] = ((Component)this).transform.Find("Ghost_" + i);
			_renderers[i] = (((Object)(object)_previews[i] != (Object)null) ? ((Component)_previews[i]).GetComponent<MeshRenderer>() : null);
		}
		if (_ghost)
		{
			ShowVariant();
			return;
		}
		for (int j = 0; j < num; j++)
		{
			if ((Object)(object)_previews[j] != (Object)null)
			{
				((Component)_previews[j]).gameObject.SetActive(false);
			}
		}
		_created = Time.time;
		_nview = ((Component)this).GetComponent<ZNetView>();
		try
		{
			if (Patches.GetPlayerPlacing() && (Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.IsOwner())
			{
				_done = true;
				Raise();
			}
		}
		catch (Exception ex)
		{
			_done = true;
			RampPlugin.Log.LogError((object)("Raising the ramp failed: " + ex));
		}
	}

	private Transform ShowVariant()
	{
		int num = RampPlugin.CurrentVariant();
		for (int i = 0; i < _renderers.Length; i++)
		{
			if ((Object)(object)_renderers[i] != (Object)null && ((Renderer)_renderers[i]).enabled != (i == num))
			{
				((Renderer)_renderers[i]).enabled = i == num;
			}
		}
		return _previews[num];
	}

	private void Update()
	{
		if (!_ghost && !((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner() && (_done || Time.time - _created > 2f))
		{
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				ZNetScene.instance.Destroy(((Component)this).gameObject);
			}
			else
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}

	private void LateUpdate()
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		if (_ghost)
		{
			Transform val = ShowVariant();
			if (!((Object)(object)val == (Object)null))
			{
				Layout.Pose(((Component)this).transform.position, ((Component)this).transform.rotation, out var position, out var rotation);
				val.SetPositionAndRotation(position, rotation);
			}
		}
	}

	private void Raise()
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_011b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0132: 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_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_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_0161: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result typ

plugins/WaystoneTrio.dll

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

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

[BepInPlugin("danpe.RuneMagicWaystoneTrio", "Rune Magic - Three Waystones", "1.1.2")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class WaystoneTrioPlugin : BaseUnityPlugin
{
	public enum Formation
	{
		Arc,
		Row,
		Triangle
	}

	public const string PluginGuid = "danpe.RuneMagicWaystoneTrio";

	public const string PluginName = "Rune Magic - Three Waystones";

	public const string PluginVersion = "1.1.2";

	internal const string RuneMagicGuid = "hyleanlegend.RuneMagic";

	internal const string WaystonePrefab = "MountainGraveStone01";

	internal const string WaystoneConfigName = "runemagic_stone_waystone";

	internal const string RuneName = "runemagic_stone_waystone3";

	internal const string RuneCloneName = "runemagic_stone_waystone3(Clone)";

	private const string RuneFocusItemName = "$item_runemagic_runefocus";

	private const int TestedMajor = 1;

	private const int TestedMinor = 5;

	internal const string DescriptionBody = "Engrave the ground and three waystones rise at once, side by side in a gentle arc (or a row, or a triangle) around the point you choose. ";

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<Formation> Shape;

	internal static ConfigEntry<float> ArcBend;

	internal static ConfigEntry<bool> AlignToView;

	internal static ConfigEntry<float> StoneTurn;

	internal static ConfigEntry<float> Spacing;

	internal static ConfigEntry<float> YawVariation;

	internal static ConfigEntry<bool> MatchGround;

	internal static ConfigEntry<float> EnergyCost;

	internal static ConfigEntry<bool> AllowUntestedVersion;

	private static Harmony _harmony;

	private static GameObject _container;

	private static GameObject _prefab;

	private static GameObject _waystone;

	private static PieceTable _table;

	private static bool _pieceConfigured;

	internal static float AutoSpacing = 2f;

	internal static string CostSentence()
	{
		float num = ((EnergyCost != null) ? EnergyCost.Value : 0f);
		if (!(num > 0f))
		{
			return "Costs three times a single waystone.";
		}
		return "Costs " + Mathf.CeilToInt(num) + " runic energy.";
	}

	private static void RefreshDescription(object sender, EventArgs e)
	{
		if (!((Object)(object)_prefab == (Object)null))
		{
			Piece component = _prefab.GetComponent<Piece>();
			if ((Object)(object)component != (Object)null)
			{
				component.m_description = "Engrave the ground and three waystones rise at once, side by side in a gentle arc (or a row, or a triangle) around the point you choose. " + CostSentence();
			}
		}
	}

	private void Awake()
	{
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Expected O, but got Unknown
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Expected O, but got Unknown
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Expected O, but got Unknown
		//IL_0154: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: Expected O, but got Unknown
		//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bc: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When false the plugin does nothing at all (restart required). Only the player who places the rune needs this add-on: what it leaves in the world are three ordinary Waystones.");
		Shape = ((BaseUnityPlugin)this).Config.Bind<Formation>("General", "Formation", Formation.Arc, "Arc: three stones side by side on a gentle curve, the middle one at the point you aim at. Row: side by side in a straight line. Triangle: three stones around the point you aim at. Applies to the next placement; the menu icon is drawn for the formation set at startup.");
		ArcBend = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Arc bend", 30f, new ConfigDescription("Arc only: degrees between neighbouring stones along the curve, and how far each outer stone turns to follow it. Positive bends the ends towards you, negative away from you, 0 is a straight row.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-90f, 90f), new object[0]));
		AlignToView = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Align to your view", true, "The formation opens side by side across the direction you look each time you select it; the scroll wheel turns it in steps from there. Off: the piece keeps Valheim's fixed world orientation and only the scroll wheel turns it.");
		StoneTurn = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Stone turn", 0f, new ConfigDescription("Extra turn in degrees applied to every stone. By default each stone's long side is laid along the formation, end to end like a wall; 90 stands them face-on to the curve instead.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-180f, 180f), new object[0]));
		Spacing = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Spacing", 0f, new ConfigDescription("Distance in metres between neighbouring stones (centre to centre). 0 = automatic: the stone's own footprint plus 35 %.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), new object[0]));
		YawVariation = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Yaw variation", 0f, new ConfigDescription("Each stone is turned by a random angle up to this many degrees either way, for a less uniform look. 0 = all three face the same way.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 180f), new object[0]));
		MatchGround = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Follow the ground", true, "Each stone rises from the ground height at its own spot. Off: all three use the height of the point you aim at.");
		EnergyCost = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Energy cost", 0f, new ConfigDescription("Runic energy to raise all three. 0 = three times the Waystone's cost (energyCost_runemagic_stone_waystone, 60 by default, so 180).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 400f), new object[0]));
		AllowUntestedVersion = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Allow untested Rune Magic version", false, "This add-on was verified against Rune Magic 1.5.x. With any other version it stays off unless this is true.");
		if (!Enabled.Value)
		{
			Log.LogInfo((object)"Three Waystones is OFF.");
			return;
		}
		EnergyCost.SettingChanged += RefreshDescription;
		try
		{
			Setup();
			Log.LogInfo((object)"Three Waystones registered; the piece appears after the Waystone once a world is loaded.");
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Setup failed - the Three Waystones rune will not be available. Nothing else is affected. " + ex));
			Teardown();
		}
	}

	private void OnDestroy()
	{
		Teardown();
	}

	private static void Teardown()
	{
		if (EnergyCost != null)
		{
			EnergyCost.SettingChanged -= RefreshDescription;
		}
		try
		{
			if ((Object)(object)_table != (Object)null && (Object)(object)_prefab != (Object)null)
			{
				_table.m_pieces.Remove(_prefab);
			}
			if ((Object)(object)ZNetScene.instance != (Object)null && (Object)(object)_prefab != (Object)null)
			{
				ZNetScene.instance.m_prefabs.Remove(_prefab);
			}
			if ((Object)(object)_container != (Object)null)
			{
				Object.Destroy((Object)(object)_container);
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Unregister failed: " + ex.Message));
		}
		_prefab = null;
		_waystone = null;
		_container = null;
		_table = null;
		_pieceConfigured = false;
		if (_harmony != null)
		{
			List<MethodBase> list;
			try
			{
				list = new List<MethodBase>(_harmony.GetPatchedMethods());
			}
			catch (Exception)
			{
				list = new List<MethodBase>();
			}
			foreach (MethodBase item in list)
			{
				try
				{
					_harmony.Unpatch(item, (HarmonyPatchType)0, "danpe.RuneMagicWaystoneTrio");
				}
				catch (Exception ex3)
				{
					Log.LogWarning((object)("Unpatch failed for " + item.Name + ": " + ex3.Message));
				}
			}
		}
		Patches.Reset();
	}

	private static void CheckRuneMagicVersion()
	{
		if (!Chainloader.PluginInfos.TryGetValue("hyleanlegend.RuneMagic", out var value) || value == null)
		{
			throw new InvalidOperationException("Rune Magic is not loaded");
		}
		Version version = value.Metadata.Version;
		if (version.Major != 1 || version.Minor != 5)
		{
			if (!AllowUntestedVersion.Value)
			{
				throw new InvalidOperationException(string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x). Set 'Allow untested Rune Magic version' to true to try anyway."));
			}
			Log.LogWarning((object)string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x); continuing because the config allows it."));
		}
	}

	private static Type RequireType(string name)
	{
		Type type = AccessTools.TypeByName(name);
		if (type == null)
		{
			throw new InvalidOperationException("Rune Magic type not found: " + name);
		}
		return type;
	}

	private static MethodInfo RequireMethod(Type t, string name, Type[] args)
	{
		MethodInfo methodInfo = ((args == null) ? AccessTools.Method(t, name, (Type[])null, (Type[])null) : AccessTools.Method(t, name, args, (Type[])null));
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Method not found: " + t.FullName + "." + name);
		}
		return methodInfo;
	}

	private static FieldInfo RequireField(Type t, string name)
	{
		FieldInfo fieldInfo = AccessTools.Field(t, name);
		if (fieldInfo == null)
		{
			throw new InvalidOperationException("Field not found: " + t.FullName + "." + name);
		}
		return fieldInfo;
	}

	private static HarmonyMethod H(string name)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(typeof(Patches), name, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Patch method missing: " + name);
		}
		return new HarmonyMethod(methodInfo);
	}

	private static void Setup()
	{
		//IL_031e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0328: Expected O, but got Unknown
		//IL_03fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0404: Expected O, but got Unknown
		CheckRuneMagicVersion();
		Type t = RequireType("ValheimMod.ValheimMod");
		MethodInfo methodInfo = RequireMethod(t, "get_isModAwake", Type.EmptyTypes);
		if (!(bool)methodInfo.Invoke(null, null))
		{
			throw new InvalidOperationException("Rune Magic did not finish initialising (isModAwake is false)");
		}
		Type t2 = RequireType("ValheimMod.UnlockManager");
		Type type = RequireType("ValheimMod.RunemagicPieceConfig");
		Type t3 = RequireType("ValheimMod.CustomContentSetupHandler");
		Type t4 = RequireType("ValheimMod.BoulderSetupHandler");
		Type t5 = RequireType("ValheimMod.PlayerPatch");
		MethodInfo methodInfo2 = RequireMethod(t2, "isUnlockable", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo3 = RequireMethod(t2, "isUnlocked", new Type[2]
		{
			typeof(Player),
			typeof(Piece)
		});
		MethodInfo methodInfo4 = RequireMethod(type, "getEnergyCost", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo5 = RequireMethod(t4, "SetUpCustomBoulderFeatures", Type.EmptyTypes);
		MethodInfo addRuneCircle = RequireMethod(t4, "addRuneCircle", new Type[1] { typeof(GameObject) });
		FieldInfo fieldInfo = RequireField(t5, "PlayerPlacing");
		if (fieldInfo.FieldType != typeof(bool) || !fieldInfo.IsStatic)
		{
			throw new InvalidOperationException("PlayerPatch.PlayerPlacing has an unexpected shape");
		}
		MethodInfo methodInfo6 = RequireMethod(typeof(ZNetScene), "Awake", Type.EmptyTypes);
		MethodInfo methodInfo7 = RequireMethod(typeof(Player), "UpdatePlacementGhost", new Type[1] { typeof(bool) });
		MethodInfo methodInfo8 = RequireMethod(typeof(Player), "SetupPlacementGhost", Type.EmptyTypes);
		ConstructorInfo constructor = type.GetConstructor(new Type[3]
		{
			typeof(Biome),
			typeof(string),
			typeof(string)
		});
		if (constructor == null)
		{
			throw new InvalidOperationException("RunemagicPieceConfig(Biome, string, string) constructor not found");
		}
		if (!(RequireField(t3, "RegisteredItemPrefabs").GetValue(null) is List<GameObject> list))
		{
			throw new InvalidOperationException("Rune Magic's item prefab list has an unexpected type");
		}
		PieceTable val = null;
		foreach (GameObject item in list)
		{
			ItemDrop val2 = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null && val2.m_itemData.m_shared.m_name == "$item_runemagic_runefocus")
			{
				val = val2.m_itemData.m_shared.m_buildPieces;
				break;
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			throw new InvalidOperationException("Rune Focus piece table not found");
		}
		Patches.IsUnlockedOriginal = (Func<Player, Piece, bool>)Delegate.CreateDelegate(typeof(Func<Player, Piece, bool>), methodInfo3);
		Patches.PlayerPlacingField = fieldInfo;
		Patches.AddRuneCircle = addRuneCircle;
		_harmony = new Harmony("danpe.RuneMagicWaystoneTrio");
		_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, H("IsUnlockablePostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, H("IsUnlockedPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, H("EnergyCostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, H("BoulderSetupPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, H("PlacementGhostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo8, (HarmonyMethod)null, H("SetupPlacementGhostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		HarmonyMethod val3 = H("ZNetSceneAwakePrefix");
		val3.priority = 800;
		_harmony.Patch((MethodBase)methodInfo6, val3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_container = new GameObject("RuneMagicWaystoneTrio_Prefabs");
		_container.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)_container);
		_table = val;
		constructor.Invoke(new object[3]
		{
			(object)(Biome)1,
			"runemagic_stone_waystone3",
			"runemagic_stone_waystone"
		});
	}

	internal static void OnZNetSceneAwake(ZNetScene scene)
	{
		if ((Object)(object)scene == (Object)null || scene.m_prefabs == null || (Object)(object)_container == (Object)null)
		{
			return;
		}
		if ((Object)(object)_prefab == (Object)null)
		{
			GameObject val = null;
			List<GameObject> prefabs = scene.m_prefabs;
			for (int i = 0; i < prefabs.Count; i++)
			{
				if ((Object)(object)prefabs[i] != (Object)null && ((Object)prefabs[i]).name == "MountainGraveStone01")
				{
					val = prefabs[i];
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Log.LogWarning((object)"Vanilla prefab MountainGraveStone01 not found in this scene; the Three Waystones rune is unavailable.");
				return;
			}
			_waystone = val;
			_prefab = Prefabs.Build(val, _container.transform);
			Log.LogInfo((object)("Three Waystones prefab built (stone footprint " + Prefabs.Footprint.ToString("F2") + " m, automatic spacing " + AutoSpacing.ToString("F2") + " m)."));
		}
		if (!scene.m_prefabs.Contains(_prefab))
		{
			scene.m_prefabs.Add(_prefab);
		}
		TryFinishPieceSetup();
	}

	internal static void TryFinishPieceSetup()
	{
		if ((Object)(object)_prefab == (Object)null || (Object)(object)_waystone == (Object)null || (Object)(object)_table == (Object)null)
		{
			return;
		}
		Piece component = _waystone.GetComponent<Piece>();
		if ((Object)(object)component == (Object)null)
		{
			return;
		}
		Piece component2 = _prefab.GetComponent<Piece>();
		if ((Object)(object)component2 == (Object)null)
		{
			return;
		}
		if (!_pieceConfigured)
		{
			Prefabs.ConfigurePiece(component2, component);
			_pieceConfigured = true;
		}
		List<GameObject> pieces = _table.m_pieces;
		int num = pieces.IndexOf(_waystone);
		if (num < 0)
		{
			return;
		}
		for (int num2 = pieces.Count - 1; num2 >= 0; num2--)
		{
			GameObject val = pieces[num2];
			if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)_prefab && ((Object)val).name == "runemagic_stone_waystone3")
			{
				pieces.RemoveAt(num2);
			}
		}
		if (!pieces.Contains(_prefab))
		{
			num = pieces.IndexOf(_waystone);
			pieces.Insert(num + 1, _prefab);
			Log.LogInfo((object)"Three Waystones added to the Rune Focus menu after the Waystone.");
		}
	}
}
internal static class Prefabs
{
	internal static float Footprint = 2f;

	internal static GameObject Build(GameObject waystone, Transform container)
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Expected O, but got Unknown
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
		Footprint = MeasureFootprint(waystone);
		WaystoneTrioPlugin.AutoSpacing = Mathf.Max(1f, Footprint * 1.35f);
		GameObject val = new GameObject("runemagic_stone_waystone3");
		val.transform.SetParent(container, false);
		ZNetView val2 = val.AddComponent<ZNetView>();
		val2.m_persistent = false;
		val2.m_distant = false;
		val2.m_type = (ObjectType)0;
		val2.m_syncInitialScale = false;
		Piece val3 = val.AddComponent<Piece>();
		val3.m_name = "Rune of the Stonecaller: Three Waystones";
		val3.m_enabled = false;
		val.AddComponent<WaystoneTrio>();
		float spacing = Layout.SpacingValue();
		for (int i = 0; i < 3; i++)
		{
			GameObject val4 = Object.Instantiate<GameObject>(waystone, val.transform, false);
			((Object)val4).name = "Waystone_" + i;
			Strip(val4);
			float turn;
			Vector2 val5 = Layout.Offset(i, spacing, out turn);
			val4.transform.localPosition = new Vector3(val5.x, 0f, val5.y);
			val4.transform.localRotation = Quaternion.identity;
		}
		return val;
	}

	internal static void ConfigurePiece(Piece piece, Piece waystone)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Expected O, but got Unknown
		piece.m_category = waystone.m_category;
		piece.m_usage = waystone.m_usage;
		piece.m_groundPiece = waystone.m_groundPiece;
		piece.m_groundOnly = waystone.m_groundOnly;
		piece.m_allowedInDeepSnow = waystone.m_allowedInDeepSnow;
		piece.m_clipEverything = waystone.m_clipEverything;
		piece.m_noInWater = waystone.m_noInWater;
		piece.m_notOnFloor = waystone.m_notOnFloor;
		piece.m_cultivatedGroundOnly = waystone.m_cultivatedGroundOnly;
		piece.m_allowedInDungeons = waystone.m_allowedInDungeons;
		piece.m_waterPiece = waystone.m_waterPiece;
		piece.m_onlyInBiome = waystone.m_onlyInBiome;
		piece.m_comfortGroup = waystone.m_comfortGroup;
		piece.m_canBeRemoved = waystone.m_canBeRemoved;
		piece.m_randomInitBuildRotation = waystone.m_randomInitBuildRotation;
		piece.m_placeEffect = new EffectList();
		piece.m_resources = (Requirement[])(object)new Requirement[0];
		piece.m_description = "Engrave the ground and three waystones rise at once, side by side in a gentle arc (or a row, or a triangle) around the point you choose. " + WaystoneTrioPlugin.CostSentence();
		piece.m_icon = Icon.Compose(waystone.m_icon, WaystoneTrioPlugin.Shape.Value);
		piece.m_enabled = true;
	}

	private static float MeasureFootprint(GameObject prefab)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: 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_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: 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_00ad: 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_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			MeshFilter[] componentsInChildren = prefab.GetComponentsInChildren<MeshFilter>(true);
			Matrix4x4 worldToLocalMatrix = prefab.transform.worldToLocalMatrix;
			float num = float.MaxValue;
			float num2 = float.MinValue;
			float num3 = float.MaxValue;
			float num4 = float.MinValue;
			bool flag = false;
			MeshFilter[] array = componentsInChildren;
			Vector3 val3 = default(Vector3);
			foreach (MeshFilter val in array)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.sharedMesh == (Object)null) && ActiveInPrefab(((Component)val).transform, prefab.transform))
				{
					Bounds bounds = val.sharedMesh.bounds;
					Matrix4x4 val2 = worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix;
					for (int j = 0; j < 8; j++)
					{
						((Vector3)(ref val3))..ctor(((j & 1) == 0) ? ((Bounds)(ref bounds)).min.x : ((Bounds)(ref bounds)).max.x, ((j & 2) == 0) ? ((Bounds)(ref bounds)).min.y : ((Bounds)(ref bounds)).max.y, ((j & 4) == 0) ? ((Bounds)(ref bounds)).min.z : ((Bounds)(ref bounds)).max.z);
						Vector3 val4 = ((Matrix4x4)(ref val2)).MultiplyPoint3x4(val3);
						num = Mathf.Min(num, val4.x);
						num2 = Mathf.Max(num2, val4.x);
						num3 = Mathf.Min(num3, val4.z);
						num4 = Mathf.Max(num4, val4.z);
						flag = true;
					}
				}
			}
			if (flag)
			{
				float num5 = num2 - num;
				float num6 = num4 - num3;
				float num7 = Mathf.Max(num5, num6);
				if (num7 > 0.1f && num7 < 50f)
				{
					float upperX;
					float upperZ;
					bool flag2 = UpperExtents(prefab, componentsInChildren, out upperX, out upperZ);
					string text;
					if (((Object)prefab).name == "MountainGraveStone01")
					{
						Layout.AcrossTurn = 90f;
						text = "the Waystone's long side runs along its local Z";
					}
					else if (flag2)
					{
						Layout.AcrossTurn = ((upperZ > upperX) ? 90f : 0f);
						text = "upper half of the mesh is " + upperX.ToString("F2") + " x " + upperZ.ToString("F2") + " m";
					}
					else
					{
						Layout.AcrossTurn = ((num6 > num5) ? 90f : 0f);
						text = "footprint only";
					}
					WaystoneTrioPlugin.Log.LogInfo((object)("Waystone footprint " + num5.ToString("F2") + " m across by " + num6.ToString("F2") + " m deep" + (flag2 ? (", upper half " + upperX.ToString("F2") + " x " + upperZ.ToString("F2") + " m") : "") + "; stones turned " + Layout.AcrossTurn + " degrees (" + text + ")."));
					return num7;
				}
			}
		}
		catch (Exception ex)
		{
			WaystoneTrioPlugin.Log.LogWarning((object)("Could not measure the Waystone: " + ex.Message));
		}
		WaystoneTrioPlugin.Log.LogWarning((object)"Could not measure the Waystone's meshes; using a 2 m footprint and no automatic stone turn (set 'Stone turn' by hand if the stones stand end-on).");
		return 2f;
	}

	private static bool UpperExtents(GameObject prefab, MeshFilter[] filters, out float upperX, out float upperZ)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: 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_0105: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: 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_0170: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
		upperX = 0f;
		upperZ = 0f;
		try
		{
			Matrix4x4 worldToLocalMatrix = prefab.transform.worldToLocalMatrix;
			List<Vector3> list = new List<Vector3>();
			foreach (MeshFilter val in filters)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.sharedMesh == (Object)null) && val.sharedMesh.isReadable && ActiveInPrefab(((Component)val).transform, prefab.transform))
				{
					Matrix4x4 val2 = worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix;
					Vector3[] vertices = val.sharedMesh.vertices;
					for (int j = 0; j < vertices.Length; j++)
					{
						list.Add(((Matrix4x4)(ref val2)).MultiplyPoint3x4(vertices[j]));
					}
				}
			}
			if (list.Count < 8)
			{
				return false;
			}
			float num = float.MaxValue;
			float num2 = float.MinValue;
			for (int k = 0; k < list.Count; k++)
			{
				num = Mathf.Min(num, list[k].y);
				num2 = Mathf.Max(num2, list[k].y);
			}
			float num3 = num + (num2 - num) * 0.5f;
			float num4 = float.MaxValue;
			float num5 = float.MinValue;
			float num6 = float.MaxValue;
			float num7 = float.MinValue;
			int num8 = 0;
			for (int l = 0; l < list.Count; l++)
			{
				if (!(list[l].y < num3))
				{
					num4 = Mathf.Min(num4, list[l].x);
					num5 = Mathf.Max(num5, list[l].x);
					num6 = Mathf.Min(num6, list[l].z);
					num7 = Mathf.Max(num7, list[l].z);
					num8++;
				}
			}
			if (num8 < 4)
			{
				return false;
			}
			upperX = num5 - num4;
			upperZ = num7 - num6;
			return upperX > 0.05f && upperZ > 0.05f;
		}
		catch (Exception)
		{
			return false;
		}
	}

	private static bool ActiveInPrefab(Transform t, Transform root)
	{
		Transform val = t;
		while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
		{
			if (!((Component)val).gameObject.activeSelf)
			{
				return false;
			}
			val = val.parent;
		}
		return true;
	}

	private static void Strip(GameObject go)
	{
		Transform[] componentsInChildren = go.GetComponentsInChildren<Transform>(true);
		Transform[] array = componentsInChildren;
		foreach (Transform val in array)
		{
			if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)go.transform && !((Component)val).gameObject.activeSelf)
			{
				Object.DestroyImmediate((Object)(object)((Component)val).gameObject);
			}
		}
		for (int j = 0; j < 8; j++)
		{
			bool flag = false;
			bool flag2 = false;
			Component[] componentsInChildren2 = go.GetComponentsInChildren<Component>(true);
			Component[] array2 = componentsInChildren2;
			foreach (Component val2 in array2)
			{
				if ((Object)(object)val2 == (Object)null || Keep(val2))
				{
					continue;
				}
				if (j < 2 && !(val2 is MonoBehaviour))
				{
					flag2 = true;
					continue;
				}
				try
				{
					Object.DestroyImmediate((Object)(object)val2);
				}
				catch (Exception)
				{
				}
				if ((Object)(object)val2 == (Object)null)
				{
					flag = true;
				}
				else
				{
					flag2 = true;
				}
			}
			if (!flag2)
			{
				return;
			}
			if (!flag && j >= 2)
			{
				break;
			}
		}
		Component[] componentsInChildren3 = go.GetComponentsInChildren<Component>(true);
		Component[] array3 = componentsInChildren3;
		foreach (Component val3 in array3)
		{
			if ((Object)(object)val3 != (Object)null && !Keep(val3))
			{
				throw new InvalidOperationException("Could not strip " + ((object)val3).GetType().Name + " from the Waystone visual copy");
			}
		}
	}

	private static bool Keep(Component c)
	{
		if (!(c is Transform) && !(c is MeshFilter) && !(c is MeshRenderer))
		{
			return c is LODGroup;
		}
		return true;
	}
}
internal static class Layout
{
	internal static readonly float[] Jitter = new float[3];

	internal static float AcrossTurn;

	private static int _mask = -1;

	internal static void Formation(Vector3 rootPos, Quaternion rootRot, Vector3[] points, float[] yaws, bool[] isCentre)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: 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_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		float spacing = SpacingValue();
		Quaternion val = BaseRotation(rootPos, rootRot);
		float y = ((Quaternion)(ref val)).eulerAngles.y;
		float num = ((WaystoneTrioPlugin.StoneTurn != null) ? WaystoneTrioPlugin.StoneTurn.Value : 0f);
		for (int i = 0; i < 3; i++)
		{
			float turn;
			Vector2 val2 = Offset(i, spacing, out turn);
			ref Vector3 reference = ref points[i];
			reference = rootPos + val * new Vector3(val2.x, 0f, val2.y);
			yaws[i] = y + AcrossTurn + num + turn + Jitter[i];
			isCentre[i] = val2.x == 0f && val2.y == 0f;
		}
	}

	internal static Quaternion BaseRotation(Vector3 rootPos, Quaternion rootRot)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: 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)
		if (WaystoneTrioPlugin.AlignToView != null && !WaystoneTrioPlugin.AlignToView.Value)
		{
			return rootRot;
		}
		Player localPlayer = Player.m_localPlayer;
		Vector3 val = Vector3.zero;
		if ((Object)(object)GameCamera.instance != (Object)null)
		{
			val = ((Component)GameCamera.instance).transform.forward;
			val.y = 0f;
		}
		if (((Vector3)(ref val)).sqrMagnitude < 0.0001f && (Object)(object)localPlayer != (Object)null)
		{
			val = rootPos - ((Component)localPlayer).transform.position;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude < 0.25f)
			{
				val = ((Component)localPlayer).transform.forward;
				val.y = 0f;
			}
		}
		if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
		{
			return rootRot;
		}
		float num = Mathf.Atan2(val.x, val.z) * 57.29578f;
		return Quaternion.Euler(0f, num + ((Quaternion)(ref rootRot)).eulerAngles.y, 0f);
	}

	internal static float ArcBendValue()
	{
		float num = ((WaystoneTrioPlugin.ArcBend != null) ? WaystoneTrioPlugin.ArcBend.Value : 30f);
		return Mathf.Clamp(num, -90f, 90f);
	}

	internal static float SpacingValue()
	{
		float num = ((WaystoneTrioPlugin.Spacing != null) ? WaystoneTrioPlugin.Spacing.Value : 0f);
		if (num <= 0f)
		{
			num = WaystoneTrioPlugin.AutoSpacing;
		}
		return Mathf.Clamp(num, 0.5f, 10f);
	}

	internal static Vector2 Offset(int i, float spacing, out float turn)
	{
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		turn = 0f;
		float num;
		switch ((WaystoneTrioPlugin.Shape != null) ? WaystoneTrioPlugin.Shape.Value : WaystoneTrioPlugin.Formation.Arc)
		{
		case WaystoneTrioPlugin.Formation.Triangle:
		{
			float num2 = spacing / Mathf.Sqrt(3f);
			float num3 = (90f + 120f * (float)i) * ((float)Math.PI / 180f);
			return new Vector2(Mathf.Cos(num3) * num2, Mathf.Sin(num3) * num2);
		}
		default:
			num = 0f;
			break;
		case WaystoneTrioPlugin.Formation.Arc:
			num = ArcBendValue();
			break;
		}
		float num4 = num;
		if (Mathf.Abs(num4) < 1f)
		{
			return new Vector2((float)(i - 1) * spacing, 0f);
		}
		float num5 = ((num4 > 0f) ? 1f : (-1f));
		float num6 = Mathf.Abs(num4);
		float num7 = spacing / (2f * Mathf.Sin(num6 * 0.5f * ((float)Math.PI / 180f)));
		float num8 = (float)(i - 1) * num6 * ((float)Math.PI / 180f);
		turn = (float)(i - 1) * num6 * num5;
		return new Vector2(num7 * Mathf.Sin(num8), (0f - num5) * num7 * (1f - Mathf.Cos(num8)));
	}

	internal static void NewJitter()
	{
		float num = ((WaystoneTrioPlugin.YawVariation != null) ? WaystoneTrioPlugin.YawVariation.Value : 0f);
		for (int i = 0; i < 3; i++)
		{
			Jitter[i] = ((num > 0f) ? Random.Range(0f - num, num) : 0f);
		}
	}

	internal static float GroundHeight(Vector3 world, float rootY)
	{
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		if (_mask < 0)
		{
			_mask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "terrain", "vehicle" });
		}
		RaycastHit[] array = Physics.RaycastAll(new Vector3(world.x, rootY + 2f, world.z), Vector3.down, 30f, _mask);
		bool flag = false;
		float num = 0f;
		for (int i = 0; i < array.Length; i++)
		{
			Collider collider = ((RaycastHit)(ref array[i])).collider;
			if (!((Object)(object)collider == (Object)null) && !((Object)(object)collider.attachedRigidbody != (Object)null) && (!flag || ((RaycastHit)(ref array[i])).point.y > num))
			{
				num = ((RaycastHit)(ref array[i])).point.y;
				flag = true;
			}
		}
		if (flag)
		{
			return num;
		}
		float result = default(float);
		if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGroundHeight(world, ref result))
		{
			return result;
		}
		return rootY;
	}
}
public class WaystoneTrio : MonoBehaviour
{
	private bool _ghost;

	private bool _done;

	private float _created;

	private ZNetView _nview;

	private Transform[] _visuals;

	private readonly Vector3[] _points = (Vector3[])(object)new Vector3[3];

	private readonly float[] _yaws = new float[3];

	private readonly bool[] _centre = new bool[3];

	private static bool _circleWarned;

	private void Awake()
	{
		_ghost = ZNetView.m_forceDisableInit;
		_visuals = (Transform[])(object)new Transform[3];
		for (int i = 0; i < 3; i++)
		{
			_visuals[i] = ((Component)this).transform.Find("Waystone_" + i);
		}
		if (_ghost)
		{
			Layout.NewJitter();
			AddCircles();
			return;
		}
		for (int j = 0; j < 3; j++)
		{
			if ((Object)(object)_visuals[j] != (Object)null)
			{
				((Component)_visuals[j]).gameObject.SetActive(false);
			}
		}
		_created = Time.time;
		_nview = ((Component)this).GetComponent<ZNetView>();
		try
		{
			if (Patches.GetPlayerPlacing() && (Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.IsOwner())
			{
				Raise();
				_done = true;
			}
		}
		catch (Exception ex)
		{
			_done = true;
			WaystoneTrioPlugin.Log.LogError((object)("Raising the three Waystones failed: " + ex));
		}
	}

	private void Update()
	{
		if (!_ghost && !((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner() && (_done || Time.time - _created > 2f))
		{
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				ZNetScene.instance.Destroy(((Component)this).gameObject);
			}
			else
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}

	private void LateUpdate()
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//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_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		if (!_ghost || _visuals == null)
		{
			return;
		}
		Vector3 position = ((Component)this).transform.position;
		bool flag = WaystoneTrioPlugin.MatchGround == null || WaystoneTrioPlugin.MatchGround.Value;
		Layout.Formation(position, ((Component)this).transform.rotation, _points, _yaws, _centre);
		for (int i = 0; i < 3; i++)
		{
			Transform val = _visuals[i];
			if (!((Object)(object)val == (Object)null))
			{
				Vector3 world = _points[i];
				float num = position.y;
				if (flag && !_centre[i])
				{
					num = Layout.GroundHeight(world, position.y);
				}
				val.position = new Vector3(world.x, num, world.z);
				val.rotation = Quaternion.Euler(0f, _yaws[i], 0f);
			}
		}
	}

	private void AddCircles()
	{
		if (Patches.AddRuneCircle == null)
		{
			return;
		}
		Transform val = null;
		for (int i = 0; i < 3; i++)
		{
			if (!((Object)(object)val == (Object)null))
			{
				break;
			}
			val = _visuals[i];
		}
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		int childCount = val.childCount;
		try
		{
			Patches.AddRuneCircle.Invoke(null, new object[1] { ((Component)val).gameObject });
		}
		catch (Exception ex)
		{
			if (!_circleWarned)
			{
				_circleWarned = true;
				Exception ex2 = ((ex.InnerException != null) ? ex.InnerException : ex);
				WaystoneTrioPlugin.Log.LogWarning((object)("Summon circle preview unavailable: " + ex2.Message));
			}
			return;
		}
		List<Transform> list = new List<Transform>();
		for (int j = childCount; j < val.childCount; j++)
		{
			list.Add(val.GetChild(j));
		}
		for (int k = 0; k < 3; k++)
		{
			Transform val2 = _visuals[k];
			if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)val))
			{
				for (int l = 0; l < list.Count; l++)
				{
					Object.Instantiate<GameObject>(((Component)list[l]).gameObject, val2, false);
				}
			}
		}
	}

	private void Raise()
	{
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_011b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: 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_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)
		GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab("MountainGraveStone01") : null);
		if ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<Piece>() == (Object)null)
		{
			WaystoneTrioPlugin.Log.LogError((object)"The Waystone prefab is not set up by Rune Magic; nothing was raised.");
			return;
		}
		bool flag = WaystoneTrioPlugin.MatchGround == null || WaystoneTrioPlugin.MatchGround.Value;
		Vector3 position = ((Component)this).transform.position;
		Vector3[] array = (Vector3[])(object)new Vector3[3];
		Quaternion[] array2 = (Quaternion[])(object)new Quaternion[3];
		Layout.Formation(position, ((Component)this).transform.rotation, _points, _yaws, _centre);
		for (int i = 0; i < 3; i++)
		{
			Vector3 world = _points[i];
			float num = position.y;
			if (flag && !_centre[i])
			{
				num = Layout.GroundHeight(world, position.y);
			}
			ref Vector3 reference = ref array[i];
			reference = new Vector3(world.x, num, world.z);
			ref Quaternion reference2 = ref array2[i];
			reference2 = Quaternion.Euler(0f, _yaws[i], 0f);
		}
		Player localPlayer = Player.m_localPlayer;
		long num2 = (((Object)(object)localPlayer != (Object)null) ? localPlayer.GetPlayerID() : 0);
		PlatformUserID val2 = default(PlatformUserID);
		try
		{
			val2 = ((IUser)PlatformManager.DistributionPlatform.LocalUser).PlatformUserID;
		}
		catch (Exception)
		{
		}
		int num3 = 0;
		bool playerPlacing = Patches.GetPlayerPlacing();
		Patches.SetPlayerPlacing(value: true);
		try
		{
			for (int j = 0; j < 3; j++)
			{
				if (PrivateArea.CheckAccess(array[j], 0f, false, false) && !Location.IsInsideNoBuildLocation(array[j]))
				{
					GameObject val3 = Object.Instantiate<GameObject>(val, array[j], array2[j]);
					Piece component = val3.GetComponent<Piece>();
					if ((Object)(object)component != (Object)null)
					{
						component.SetCreator(num2, val2);
					}
					num3++;
				}
			}
		}
		finally
		{
			Patches.SetPlayerPlacing(playerPlacing);
		}
		Layout.NewJitter();
		if (num3 < 3 && (Object)(object)localPlayer != (Object)null)
		{
			((Character)localPlayer).Message((MessageType)2, 3 - num3 + ((num3 == 2) ? " waystone" : " waystones") + " could not rise there (ward or no-build area)", 0, (Sprite)null, false);
		}
	}
}
public static class Patches
{
	internal static Func<Player, Piece, bool> IsUnlockedOriginal;

	internal static FieldInfo PlayerPlacingField;

	internal static MethodInfo AddRuneCircle;

	private static Piece _waystonePiece;

	private static bool _ghostWarned;

	private static readonly Vector3[] _checkPoints = (Vector3[])(object)new Vector3[3];

	private static readonly float[] _checkYaws = new float[3];

	private static readonly bool[] _checkCentre = new bool[3];

	internal static void Reset()
	{
		IsUnlockedOriginal = null;
		PlayerPlacingField = null;
		AddRuneCircle = null;
		_waystonePiece = null;
		_ghostWarned = false;
	}

	internal static bool GetPlayerPlacing()
	{
		if (PlayerPlacingField != null)
		{
			return (bool)PlayerPlacingField.GetValue(null);
		}
		return false;
	}

	internal static void SetPlayerPlacing(bool value)
	{
		if (PlayerPlacingField != null)
		{
			PlayerPlacingField.SetValue(null, value);
		}
	}

	private static bool IsTrio(Piece piece)
	{
		if ((Object)(object)piece == (Object)null)
		{
			return false;
		}
		string name = ((Object)((Component)piece).gameObject).name;
		if (!(name == "runemagic_stone_waystone3"))
		{
			return name == "runemagic_stone_waystone3(Clone)";
		}
		return true;
	}

	private static Piece WaystonePiece()
	{
		if ((Object)(object)_waystonePiece == (Object)null && (Object)(object)ZNetScene.instance != (Object)null)
		{
			GameObject prefab = ZNetScene.instance.GetPrefab("MountainGraveStone01");
			_waystonePiece = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Piece>() : null);
		}
		return _waystonePiece;
	}

	public static void IsUnlockablePostfix(Piece piece, ref bool __result)
	{
		if (!__result && IsTrio(piece))
		{
			__result = true;
		}
	}

	public static void IsUnlockedPostfix(Player player, Piece piece, ref bool __result)
	{
		if (IsTrio(piece) && IsUnlockedOriginal != null)
		{
			Piece val = WaystonePiece();
			__result = (Object)(object)val != (Object)null && IsUnlockedOriginal(player, val);
		}
	}

	public static void EnergyCostPostfix(Piece piece, ref float __result)
	{
		if (IsTrio(piece))
		{
			float num = ((WaystoneTrioPlugin.EnergyCost != null) ? WaystoneTrioPlugin.EnergyCost.Value : 0f);
			__result = ((num > 0f) ? num : (__result * 3f));
		}
	}

	public static void SetupPlacementGhostPostfix(GameObject ___m_placementGhost, ref int ___m_placeRotation)
	{
		if (!((Object)(object)___m_placementGhost == (Object)null) && !((Object)(object)___m_placementGhost.GetComponent<WaystoneTrio>() == (Object)null) && (WaystoneTrioPlugin.AlignToView == null || WaystoneTrioPlugin.AlignToView.Value))
		{
			___m_placeRotation = 0;
		}
	}

	public static void PlacementGhostPostfix(bool flashGuardStone, GameObject ___m_placementGhost, ref PlacementStatus ___m_placementStatus)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Expected I4, but got Unknown
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (___m_placementStatus || (Object)(object)___m_placementGhost == (Object)null || !___m_placementGhost.activeSelf || (Object)(object)___m_placementGhost.GetComponent<WaystoneTrio>() == (Object)null)
			{
				return;
			}
			Layout.Formation(___m_placementGhost.transform.position, ___m_placementGhost.transform.rotation, _checkPoints, _checkYaws, _checkCentre);
			PlacementStatus val = (PlacementStatus)0;
			for (int i = 0; i < 3; i++)
			{
				if ((int)val != 0)
				{
					break;
				}
				if (!_checkCentre[i])
				{
					Vector3 val2 = _checkPoints[i];
					if (Location.IsInsideNoBuildLocation(val2))
					{
						val = (PlacementStatus)3;
					}
					else if (!PrivateArea.CheckAccess(val2, 0f, flashGuardStone, false))
					{
						val = (PlacementStatus)4;
					}
				}
			}
			if ((int)val != 0)
			{
				___m_placementStatus = (PlacementStatus)(int)val;
				Piece component = ___m_placementGhost.GetComponent<Piece>();
				if ((Object)(object)component != (Object)null)
				{
					component.SetInvalidPlacementHeightlight(true);
				}
			}
		}
		catch (Exception ex)
		{
			if (!_ghostWarned)
			{
				_ghostWarned = true;
				WaystoneTrioPlugin.Log.LogWarning((object)("Three Waystones placement check failed: " + ex.Message));
			}
		}
	}

	public static void ZNetSceneAwakePrefix(ZNetScene __instance)
	{
		try
		{
			WaystoneTrioPlugin.OnZNetSceneAwake(__instance);
		}
		catch (Exception ex)
		{
			WaystoneTrioPlugin.Log.LogError((object)("Three Waystones could not be prepared for this world: " + ex));
		}
	}

	public static void BoulderSetupPostfix()
	{
		try
		{
			WaystoneTrioPlugin.TryFinishPieceSetup();
		}
		catch (Exception ex)
		{
			WaystoneTrioPlugin.Log.LogError((object)("Three Waystones could not be added to the menu: " + ex));
		}
	}
}
internal static class Icon
{
	private const int Size = 128;

	internal static Sprite Compose(Sprite source, WaystoneTrioPlugin.Formation formation)
	{
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0178: Expected O, but got Unknown
		//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)source == (Object)null || (Object)(object)source.texture == (Object)null || Application.isBatchMode)
		{
			return source;
		}
		try
		{
			int width;
			int height;
			Color[] src = ReadSprite(source, out width, out height);
			Color[] array = (Color[])(object)new Color[16384];
			float num;
			float[][] array2;
			if (formation == WaystoneTrioPlugin.Formation.Triangle)
			{
				num = 0.58f;
				array2 = new float[3][]
				{
					new float[2] { 0.5f, 0.66f },
					new float[2] { 0.29f, 0.36f },
					new float[2] { 0.71f, 0.36f }
				};
			}
			else
			{
				num = 0.56f;
				array2 = new float[3][]
				{
					new float[2] { 0.25f, 0.5f },
					new float[2] { 0.75f, 0.5f },
					new float[2] { 0.5f, 0.5f }
				};
			}
			float[][] array3 = array2;
			foreach (float[] array4 in array3)
			{
				Stamp(array, src, width, height, array4[0] * 128f, array4[1] * 128f, num * 128f);
			}
			Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false);
			((Object)val).name = "WaystoneTrioIcon";
			((Texture)val).wrapMode = (TextureWrapMode)1;
			val.SetPixels(array);
			val.Apply(false, false);
			return Sprite.Create(val, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f), 100f);
		}
		catch (Exception ex)
		{
			WaystoneTrioPlugin.Log.LogWarning((object)("Could not draw the Three Waystones icon, using the Waystone's: " + ex.Message));
			return source;
		}
	}

	private static Color[] ReadSprite(Sprite sprite, out int width, out int height)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Expected O, but got Unknown
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		Texture texture = (Texture)(object)sprite.texture;
		Rect textureRect = sprite.textureRect;
		width = Mathf.Max(1, Mathf.RoundToInt(((Rect)(ref textureRect)).width));
		height = Mathf.Max(1, Mathf.RoundToInt(((Rect)(ref textureRect)).height));
		RenderTexture temporary = RenderTexture.GetTemporary(texture.width, texture.height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
		RenderTexture active = RenderTexture.active;
		Texture2D val = null;
		try
		{
			Graphics.Blit(texture, temporary);
			RenderTexture.active = temporary;
			val = new Texture2D(width, height, (TextureFormat)4, false);
			val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)width, (float)height), 0, 0);
			val.Apply();
			return val.GetPixels();
		}
		finally
		{
			RenderTexture.active = active;
			RenderTexture.ReleaseTemporary(temporary);
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)val);
			}
		}
	}

	private static void Stamp(Color[] dst, Color[] src, int sw, int sh, float cx, float cy, float target)
	{
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
		float num = (float)sw / (float)sh;
		float num2 = ((num >= 1f) ? target : (target * num));
		float num3 = ((num >= 1f) ? (target / num) : target);
		float num4 = cx - num2 / 2f;
		float num5 = cy - num3 / 2f;
		int num6 = Mathf.Max(0, Mathf.FloorToInt(num4));
		int num7 = Mathf.Min(128, Mathf.CeilToInt(num4 + num2));
		int num8 = Mathf.Max(0, Mathf.FloorToInt(num5));
		int num9 = Mathf.Min(128, Mathf.CeilToInt(num5 + num3));
		for (int i = num8; i < num9; i++)
		{
			float num10 = ((float)i + 0.5f - num5) / num3;
			if (num10 < 0f || num10 >= 1f)
			{
				continue;
			}
			for (int j = num6; j < num7; j++)
			{
				float num11 = ((float)j + 0.5f - num4) / num2;
				if (num11 < 0f || num11 >= 1f)
				{
					continue;
				}
				Color val = Sample(src, sw, sh, num11, num10);
				if (!(val.a <= 0f))
				{
					int num12 = i * 128 + j;
					Color val2 = dst[num12];
					float num13 = val.a + val2.a * (1f - val.a);
					if (!(num13 <= 0f))
					{
						ref Color reference = ref dst[num12];
						reference = new Color((val.r * val.a + val2.r * val2.a * (1f - val.a)) / num13, (val.g * val.a + val2.g * val2.a * (1f - val.a)) / num13, (val.b * val.a + val2.b * val2.a * (1f - val.a)) / num13, num13);
					}
				}
			}
		}
	}

	private static Color Sample(Color[] src, int sw, int sh, float u, float v)
	{
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: 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_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		float num = u * (float)sw - 0.5f;
		float num2 = v * (float)sh - 0.5f;
		int num3 = Mathf.Clamp(Mathf.FloorToInt(num), 0, sw - 1);
		int num4 = Mathf.Clamp(Mathf.FloorToInt(num2), 0, sh - 1);
		int num5 = Mathf.Min(num3 + 1, sw - 1);
		int num6 = Mathf.Min(num4 + 1, sh - 1);
		float num7 = Mathf.Clamp01(num - (float)num3);
		float num8 = Mathf.Clamp01(num2 - (float)num4);
		Color val = Color.Lerp(src[num4 * sw + num3], src[num4 * sw + num5], num7);
		Color val2 = Color.Lerp(src[num6 * sw + num3], src[num6 * sw + num5], num7);
		return Color.Lerp(val, val2, num8);
	}
}

plugins/SquareFoundationRune.dll

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

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

[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("danpe.RuneMagicSquareFoundation", "Rune Magic - Square Foundation Rune", "1.0.1")]
public class SquareFoundationPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "danpe.RuneMagicSquareFoundation";

	public const string PluginName = "Rune Magic - Square Foundation Rune";

	public const string PluginVersion = "1.0.1";

	internal const string OrigName = "runemagic_LevelTerrain";

	internal const string SquareName = "runemagic_LevelTerrainSquare";

	internal const string SquareCloneName = "runemagic_LevelTerrainSquare(Clone)";

	private const string RuneFocusItemName = "$item_runemagic_runefocus";

	private const string RuneMagicGuid = "hyleanlegend.RuneMagic";

	private const int TestedMajor = 1;

	private const int TestedMinor = 5;

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<float> CostMultiplier;

	internal static ConfigEntry<bool> SquarePaint;

	internal static ConfigEntry<bool> AllowUntestedVersion;

	private static Harmony _harmony;

	private static GameObject _container;

	private static GameObject _clone;

	private static PieceTable _table;

	private static List<GameObject> _registeredPrefabs;

	private static HashSet<string> _resizableNames;

	private static Texture2D _glyph;

	private void Awake()
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When false the plugin does nothing at all (restart required).");
		CostMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Cost multiplier", 1f, new ConfigDescription("Runic energy cost of the square rune relative to the round Foundation Rune of the same size. 1 = same price; 1.27 = same price per area (a square covers 4/pi times the circle).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), new object[0]));
		SquarePaint = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Square dirt patch", true, "If true the dirt painted under the square rune is square too. This needs one small patch on the vanilla terrain paint routine (inactive except while a square rune paints). If false the dirt patch stays round (restart required).");
		AllowUntestedVersion = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Allow untested Rune Magic version", false, "This add-on was verified against Rune Magic 1.5.x. With any other version it stays off unless this is true (the code-shape checks still apply, but they cannot notice a change in what Rune Magic's code means).");
		if (!Enabled.Value)
		{
			Log.LogInfo((object)"Disabled in config.");
			return;
		}
		try
		{
			Setup();
			Log.LogInfo((object)"Square Foundation Rune registered.");
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Setup failed - the square rune will not be available. Nothing else is affected. " + ex));
			Teardown();
		}
	}

	private void OnDestroy()
	{
		Teardown();
	}

	private static void Teardown()
	{
		Patches.SetupDone = false;
		try
		{
			if ((Object)(object)_table != (Object)null && (Object)(object)_clone != (Object)null)
			{
				_table.m_pieces.Remove(_clone);
			}
			if (_registeredPrefabs != null && (Object)(object)_clone != (Object)null)
			{
				_registeredPrefabs.Remove(_clone);
			}
			if (_resizableNames != null)
			{
				_resizableNames.Remove("runemagic_LevelTerrainSquare");
				_resizableNames.Remove("runemagic_LevelTerrainSquare(Clone)");
			}
			if ((Object)(object)_container != (Object)null)
			{
				Object.Destroy((Object)(object)_container);
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Unregister failed: " + ex.Message));
		}
		_clone = null;
		_container = null;
		_table = null;
		if (_harmony != null)
		{
			List<MethodBase> list;
			try
			{
				list = new List<MethodBase>(_harmony.GetPatchedMethods());
			}
			catch (Exception)
			{
				list = new List<MethodBase>();
			}
			foreach (MethodBase item in list)
			{
				try
				{
					_harmony.Unpatch(item, (HarmonyPatchType)0, "danpe.RuneMagicSquareFoundation");
				}
				catch (Exception ex3)
				{
					Log.LogWarning((object)("Unpatch failed for " + item.Name + ": " + ex3.Message));
				}
			}
		}
		Patches.Reset();
	}

	private static void CheckRuneMagicVersion()
	{
		if (!Chainloader.PluginInfos.TryGetValue("hyleanlegend.RuneMagic", out var value) || value == null)
		{
			throw new InvalidOperationException("Rune Magic is not loaded");
		}
		Version version = value.Metadata.Version;
		if (version.Major != 1 || version.Minor != 5)
		{
			if (!AllowUntestedVersion.Value)
			{
				throw new InvalidOperationException(string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x). Set 'Allow untested Rune Magic version' to true to try anyway."));
			}
			Log.LogWarning((object)string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x); continuing because the config allows it."));
		}
	}

	private static Type RequireType(string name)
	{
		Type type = AccessTools.TypeByName(name);
		if (type == null)
		{
			throw new InvalidOperationException("Rune Magic type not found: " + name);
		}
		return type;
	}

	private static MethodInfo RequireMethod(Type t, string name, Type[] args)
	{
		MethodInfo methodInfo = ((args == null) ? AccessTools.Method(t, name, (Type[])null, (Type[])null) : AccessTools.Method(t, name, args, (Type[])null));
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Method not found: " + t.FullName + "." + name);
		}
		return methodInfo;
	}

	private static FieldInfo RequireField(Type t, string name)
	{
		FieldInfo fieldInfo = AccessTools.Field(t, name);
		if (fieldInfo == null)
		{
			throw new InvalidOperationException("Field not found: " + t.FullName + "." + name);
		}
		return fieldInfo;
	}

	private static HarmonyMethod H(string name)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(typeof(Patches), name, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Patch method missing: " + name);
		}
		return new HarmonyMethod(methodInfo);
	}

	private static void Setup()
	{
		//IL_066f: Unknown result type (might be due to invalid IL or missing references)
		//IL_067e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0696: Unknown result type (might be due to invalid IL or missing references)
		//IL_06a0: Expected O, but got Unknown
		//IL_08af: Unknown result type (might be due to invalid IL or missing references)
		//IL_08b9: Expected O, but got Unknown
		CheckRuneMagicVersion();
		Type type = RequireType("ValheimMod.Monobehaviours.FoundationRune");
		Type t = RequireType("ValheimMod.ProgressiveAlteration");
		Type type2 = RequireType("ValheimMod.RadialProgressiveAlteration");
		Type t2 = RequireType("ValheimMod.TerrainHolder");
		Type t3 = RequireType("ValheimMod.UnlockManager");
		Type type3 = RequireType("ValheimMod.RunemagicPieceConfig");
		Type t4 = RequireType("ValheimMod.ValheimMod");
		Type t5 = RequireType("ValheimMod.CustomContentSetupHandler");
		Type type4 = RequireType("ValheimMod.Monobehaviours.RuneProjector");
		Patches.RadialType = type2;
		Patches.AlterationField = RequireField(type, "alteration");
		Patches.HolderField = RequireField(type, "terrainHolder");
		Patches.StartField = RequireField(t, "start");
		Patches.WidthField = RequireField(t, "effectWidth");
		Patches.DistanceField = RequireField(t, "<currentDistance>k__BackingField");
		Patches.StartGetter = Patches.MakeGetter<Vector2>(Patches.StartField);
		Patches.WidthGetter = Patches.MakeGetter<float>(Patches.WidthField);
		Patches.DistanceGetter = Patches.MakeGetter<float>(Patches.DistanceField);
		Patches.Vector2Distance = RequireMethod(typeof(Vector2), "Distance", new Type[2]
		{
			typeof(Vector2),
			typeof(Vector2)
		});
		Patches.UtilsDistanceXZ = RequireMethod(typeof(Utils), "DistanceXZ", new Type[2]
		{
			typeof(Vector3),
			typeof(Vector3)
		});
		MethodInfo methodInfo = RequireMethod(type, "adjustTerrain", new Type[1] { typeof(TerrainComp) });
		MethodInfo methodInfo2 = RequireMethod(type, "GetColumnArcAligned", new Type[1] { typeof(GameObject) });
		MethodInfo methodInfo3 = RequireMethod(type, "setupVFX", Type.EmptyTypes);
		MethodInfo methodInfo4 = RequireMethod(type, "PostZNetViewAwake", new Type[1] { typeof(ZNetView) });
		MethodInfo methodInfo5 = RequireMethod(type, "OnDestroy", Type.EmptyTypes);
		MethodInfo methodInfo6 = RequireMethod(type2, "isPointInsideCenterEdge", new Type[1] { typeof(Vector3) });
		MethodInfo methodInfo7 = RequireMethod(type2, "getFractionOfWaveCrossed", new Type[1] { typeof(Vector3) });
		MethodInfo methodInfo8 = RequireMethod(t2, "repaint", null);
		MethodInfo methodInfo9 = RequireMethod(t3, "isUnlockable", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo10 = RequireMethod(t3, "isUnlocked", new Type[2]
		{
			typeof(Player),
			typeof(Piece)
		});
		MethodInfo methodInfo11 = RequireMethod(type3, "getEnergyCost", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo12 = (SquarePaint.Value ? RequireMethod(typeof(TerrainComp), "PaintCleared", null) : null);
		MethodInfo[] array = new MethodInfo[3] { methodInfo, methodInfo2, methodInfo3 };
		MethodInfo[] array2 = array;
		foreach (MethodInfo methodInfo13 in array2)
		{
			if (methodInfo13.IsStatic || methodInfo13.DeclaringType != type)
			{
				throw new InvalidOperationException(methodInfo13.Name + " is no longer an instance method of FoundationRune");
			}
		}
		ConstructorInfo constructor = type3.GetConstructor(new Type[3]
		{
			typeof(Biome),
			typeof(string),
			typeof(string)
		});
		FieldInfo fieldInfo = RequireField(t4, "resizableTerrainModifierNames");
		FieldInfo fieldInfo2 = RequireField(t5, "RegisteredItemPrefabs");
		MethodInfo methodInfo14 = RequireMethod(t5, "RegisterPrefab", new Type[1] { typeof(GameObject) });
		FieldInfo fieldInfo3 = RequireField(type4, "runeTexture");
		if (constructor == null)
		{
			throw new InvalidOperationException("RunemagicPieceConfig(Biome, string, string) constructor not found");
		}
		HashSet<string> hashSet = fieldInfo.GetValue(null) as HashSet<string>;
		List<GameObject> list = RequireField(t5, "RegisteredNonItemPrefabs").GetValue(null) as List<GameObject>;
		if (hashSet == null || list == null)
		{
			throw new InvalidOperationException("Rune Magic's name set / prefab list have an unexpected type");
		}
		Patches.IsUnlockedOriginal = (Func<Player, Piece, bool>)Delegate.CreateDelegate(typeof(Func<Player, Piece, bool>), methodInfo10);
		PieceTable val = null;
		if (fieldInfo2.GetValue(null) is List<GameObject> list2)
		{
			foreach (GameObject item in list2)
			{
				ItemDrop val2 = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null && val2.m_itemData.m_shared.m_name == "$item_runemagic_runefocus")
				{
					val = val2.m_itemData.m_shared.m_buildPieces;
					break;
				}
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			throw new InvalidOperationException("Rune Focus piece table not found");
		}
		GameObject val3 = null;
		List<GameObject> list3 = new List<GameObject>();
		foreach (GameObject piece in val.m_pieces)
		{
			if ((Object)(object)piece != (Object)null && ((Object)piece).name == "runemagic_LevelTerrainSquare")
			{
				list3.Add(piece);
			}
			else if ((Object)(object)piece != (Object)null && ((Object)piece).name == "runemagic_LevelTerrain")
			{
				val3 = piece;
			}
		}
		foreach (GameObject item2 in list3)
		{
			Log.LogInfo((object)"Replacing a stale square rune entry.");
			val.m_pieces.Remove(item2);
			list.Remove(item2);
		}
		if ((Object)(object)val3 == (Object)null || (Object)(object)val3.GetComponent<Piece>() == (Object)null || (Object)(object)val3.GetComponent(type) == (Object)null)
		{
			throw new InvalidOperationException("Foundation Rune prefab not found in the Rune Focus piece table");
		}
		Patches.OrigPiece = val3.GetComponent<Piece>();
		_glyph = Glyph.Build();
		Sprite icon = Sprite.Create(_glyph, new Rect(0f, 0f, (float)((Texture)_glyph).width, (float)((Texture)_glyph).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
		_harmony = new Harmony("danpe.RuneMagicSquareFoundation");
		_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, H("AdjustTerrainTranspiler"), (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, H("ColumnArcTranspiler"), (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, (HarmonyMethod)null, H("SetupVfxTranspiler"), (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo4, H("PostAwakePrefix"), H("PostAwakePostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, H("OnDestroyPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo6, H("InsideCenterEdgePrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo7, H("FractionPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo9, (HarmonyMethod)null, H("IsUnlockablePostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo10, (HarmonyMethod)null, H("IsUnlockedPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo11, (HarmonyMethod)null, H("EnergyCostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		if (methodInfo12 != null)
		{
			_harmony.Patch((MethodBase)methodInfo8, H("RepaintPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, H("RepaintFinalizer"), (HarmonyMethod)null);
			_harmony.Patch((MethodBase)methodInfo12, (HarmonyMethod)null, (HarmonyMethod)null, H("PaintClearedTranspiler"), (HarmonyMethod)null, (HarmonyMethod)null);
		}
		string[] array3 = ((methodInfo12 != null) ? new string[4] { "adjustTerrain", "GetColumnArcAligned", "setupVFX", "PaintCleared" } : new string[3] { "adjustTerrain", "GetColumnArcAligned", "setupVFX" });
		string[] array4 = array3;
		foreach (string text in array4)
		{
			if (!Patches.TranspilerOk.TryGetValue(text, out var value) || !value)
			{
				throw new InvalidOperationException("IL pattern mismatch in " + text + " (Rune Magic or Valheim changed)");
			}
		}
		_container = new GameObject("RuneMagicSquareFoundation_Prefabs");
		_container.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)_container);
		GameObject val4 = Object.Instantiate<GameObject>(val3, _container.transform);
		((Object)val4).name = "runemagic_LevelTerrainSquare";
		Piece component = val4.GetComponent<Piece>();
		component.m_name = "Square Foundation Rune";
		component.m_description = "Even the plains aren't this flat. Or this square.";
		Component component2 = val4.GetComponent(type4);
		if ((Object)(object)component2 != (Object)null)
		{
			fieldInfo3.SetValue(component2, _glyph);
		}
		component.m_icon = icon;
		_clone = val4;
		_table = val;
		_registeredPrefabs = list;
		_resizableNames = hashSet;
		constructor.Invoke(new object[3]
		{
			(object)(Biome)8,
			"runemagic_LevelTerrainSquare",
			"runemagic_LevelTerrain"
		});
		hashSet.Add("runemagic_LevelTerrainSquare");
		hashSet.Add("runemagic_LevelTerrainSquare(Clone)");
		methodInfo14.Invoke(null, new object[1] { val4 });
		int num = val.m_pieces.IndexOf(val3);
		val.m_pieces.Insert(num + 1, val4);
		Patches.SetupDone = true;
	}
}
internal sealed class ReferenceComparer : IEqualityComparer<object>
{
	internal static readonly ReferenceComparer Instance = new ReferenceComparer();

	bool IEqualityComparer<object>.Equals(object a, object b)
	{
		return object.ReferenceEquals(a, b);
	}

	int IEqualityComparer<object>.GetHashCode(object o)
	{
		return RuntimeHelpers.GetHashCode(o);
	}
}
public static class Patches
{
	private static readonly HashSet<object> SquareRunes = new HashSet<object>(ReferenceComparer.Instance);

	private static readonly HashSet<object> SquareWaves = new HashSet<object>(ReferenceComparer.Instance);

	private static readonly HashSet<object> SquareHolders = new HashSet<object>(ReferenceComparer.Instance);

	private static readonly Dictionary<object, object[]> RuneParts = new Dictionary<object, object[]>(ReferenceComparer.Instance);

	internal static readonly Dictionary<string, bool> TranspilerOk = new Dictionary<string, bool>();

	internal static bool SetupDone;

	internal static Type RadialType;

	internal static FieldInfo AlterationField;

	internal static FieldInfo HolderField;

	internal static FieldInfo StartField;

	internal static FieldInfo WidthField;

	internal static FieldInfo DistanceField;

	internal static Func<object, Vector2> StartGetter;

	internal static Func<object, float> WidthGetter;

	internal static Func<object, float> DistanceGetter;

	internal static MethodInfo Vector2Distance;

	internal static MethodInfo UtilsDistanceXZ;

	internal static Piece OrigPiece;

	internal static Func<Player, Piece, bool> IsUnlockedOriginal;

	private static bool _paintSquare;

	internal static void Reset()
	{
		SquareRunes.Clear();
		SquareWaves.Clear();
		SquareHolders.Clear();
		RuneParts.Clear();
		_paintSquare = false;
	}

	internal static Func<object, T> MakeGetter<T>(FieldInfo field)
	{
		try
		{
			DynamicMethod dynamicMethod = new DynamicMethod("SquareRune_get_" + field.Name.Replace('<', '_').Replace('>', '_'), typeof(T), new Type[1] { typeof(object) }, field.DeclaringType, skipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			iLGenerator.Emit(OpCodes.Ldarg_0);
			iLGenerator.Emit(OpCodes.Castclass, field.DeclaringType);
			iLGenerator.Emit(OpCodes.Ldfld, field);
			iLGenerator.Emit(OpCodes.Ret);
			return (Func<object, T>)dynamicMethod.CreateDelegate(typeof(Func<object, T>));
		}
		catch (Exception ex)
		{
			SquareFoundationPlugin.Log.LogWarning((object)("Fast accessor unavailable for " + field.Name + " (" + ex.Message + "), using reflection."));
			return ReflectionGetter<T>(field);
		}
	}

	internal static Func<object, T> ReflectionGetter<T>(FieldInfo field)
	{
		return (object o) => (T)field.GetValue(o);
	}

	private static float Chebyshev(float dx, float dy)
	{
		return Mathf.Max(Mathf.Abs(dx), Mathf.Abs(dy));
	}

	private static bool IsSquarePiece(Piece piece)
	{
		if ((Object)(object)piece == (Object)null)
		{
			return false;
		}
		string name = ((Object)((Component)piece).gameObject).name;
		if (!(name == "runemagic_LevelTerrainSquare"))
		{
			return name == "runemagic_LevelTerrainSquare(Clone)";
		}
		return true;
	}

	public static float GridDist(Vector2 a, Vector2 b, object rune)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		if (SquareRunes.Count != 0 && SquareRunes.Contains(rune))
		{
			return Chebyshev(a.x - b.x, a.y - b.y);
		}
		return Vector2.Distance(a, b);
	}

	public static float WorldDistXZ(Vector3 a, Vector3 b, object rune)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		if (SquareRunes.Count != 0 && SquareRunes.Contains(rune))
		{
			return Chebyshev(a.x - b.x, a.z - b.z);
		}
		return Utils.DistanceXZ(a, b);
	}

	public static float PaintDist(Vector2 a, Vector2 b)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		if (_paintSquare)
		{
			return Chebyshev(a.x - b.x, a.y - b.y);
		}
		return Vector2.Distance(a, b);
	}

	private static IEnumerable<CodeInstruction> Rewrite(IEnumerable<CodeInstruction> source, string key, int expectVector2, int expectXZ, bool paintMode)
	{
		//IL_019f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a6: Expected O, but got Unknown
		List<CodeInstruction> list = new List<CodeInstruction>(source);
		List<int> list2 = new List<int>();
		int num = 0;
		int num2 = 0;
		bool flag = false;
		for (int i = 0; i < list.Count; i++)
		{
			CodeInstruction val = list[i];
			MethodInfo methodInfo = val.operand as MethodInfo;
			if (methodInfo == null || (val.opcode != OpCodes.Call && val.opcode != OpCodes.Callvirt))
			{
				continue;
			}
			if (methodInfo == Vector2Distance)
			{
				num++;
			}
			else
			{
				if (!(methodInfo == UtilsDistanceXZ))
				{
					continue;
				}
				num2++;
			}
			list2.Add(i);
			if (val.blocks != null && val.blocks.Count > 0)
			{
				flag = true;
			}
		}
		if (num != expectVector2 || num2 != expectXZ || flag)
		{
			TranspilerOk[key] = false;
			if (SetupDone)
			{
				SquareFoundationPlugin.Log.LogWarning((object)("Another mod re-patched " + key + " and the expected distance call is gone; this part of the square rune falls back to the round shape."));
			}
			return list;
		}
		MethodInfo methodInfo2 = AccessTools.Method(typeof(Patches), "GridDist", (Type[])null, (Type[])null);
		MethodInfo methodInfo3 = AccessTools.Method(typeof(Patches), "WorldDistXZ", (Type[])null, (Type[])null);
		MethodInfo operand = AccessTools.Method(typeof(Patches), "PaintDist", (Type[])null, (Type[])null);
		for (int num3 = list2.Count - 1; num3 >= 0; num3--)
		{
			int index = list2[num3];
			CodeInstruction val2 = list[index];
			bool flag2 = (MethodInfo)val2.operand == Vector2Distance;
			val2.opcode = OpCodes.Call;
			if (paintMode)
			{
				val2.operand = operand;
			}
			else
			{
				CodeInstruction val3 = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
				val3.labels.AddRange(val2.labels);
				val2.labels.Clear();
				val2.operand = (flag2 ? methodInfo2 : methodInfo3);
				list.Insert(index, val3);
			}
		}
		TranspilerOk[key] = true;
		return list;
	}

	public static IEnumerable<CodeInstruction> AdjustTerrainTranspiler(IEnumerable<CodeInstruction> instructions)
	{
		return Rewrite(instructions, "adjustTerrain", 1, 0, paintMode: false);
	}

	public static IEnumerable<CodeInstruction> ColumnArcTranspiler(IEnumerable<CodeInstruction> instructions)
	{
		return Rewrite(instructions, "GetColumnArcAligned", 1, 1, paintMode: false);
	}

	public static IEnumerable<CodeInstruction> SetupVfxTranspiler(IEnumerable<CodeInstruction> instructions)
	{
		return Rewrite(instructions, "setupVFX", 0, 1, paintMode: false);
	}

	public static IEnumerable<CodeInstruction> PaintClearedTranspiler(IEnumerable<CodeInstruction> instructions)
	{
		return Rewrite(instructions, "PaintCleared", 1, 0, paintMode: true);
	}

	public static void PostAwakePrefix(MonoBehaviour __instance)
	{
		try
		{
			if ((Object)(object)__instance != (Object)null && Utils.GetPrefabName(((Component)__instance).gameObject) == "runemagic_LevelTerrainSquare")
			{
				SquareRunes.Add(__instance);
			}
		}
		catch (Exception ex)
		{
			SquareFoundationPlugin.Log.LogWarning((object)("PostAwakePrefix: " + ex.Message));
		}
	}

	public static void PostAwakePostfix(MonoBehaviour __instance)
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if ((Object)(object)__instance == (Object)null || !SquareRunes.Contains(__instance))
			{
				return;
			}
			object value = AlterationField.GetValue(__instance);
			object value2 = HolderField.GetValue(__instance);
			if (value != null && RadialType.IsInstanceOfType(value))
			{
				try
				{
					StartGetter(value);
					WidthGetter(value);
					DistanceGetter(value);
				}
				catch (Exception ex)
				{
					SquareFoundationPlugin.Log.LogWarning((object)("Fast accessors failed (" + ex.Message + "), using reflection."));
					StartGetter = ReflectionGetter<Vector2>(StartField);
					WidthGetter = ReflectionGetter<float>(WidthField);
					DistanceGetter = ReflectionGetter<float>(DistanceField);
				}
				SquareWaves.Add(value);
			}
			if (value2 != null)
			{
				SquareHolders.Add(value2);
			}
			RuneParts[__instance] = new object[2] { value, value2 };
		}
		catch (Exception ex2)
		{
			SquareFoundationPlugin.Log.LogWarning((object)("PostAwakePostfix: " + ex2.Message));
		}
	}

	public static void OnDestroyPostfix(MonoBehaviour __instance)
	{
		SquareRunes.Remove(__instance);
		if (RuneParts.TryGetValue(__instance, out var value))
		{
			RuneParts.Remove(__instance);
			if (value[0] != null)
			{
				SquareWaves.Remove(value[0]);
			}
			if (value[1] != null)
			{
				SquareHolders.Remove(value[1]);
			}
		}
	}

	public static bool InsideCenterEdgePrefix(object __instance, Vector3 pos, ref bool __result)
	{
		//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)
		if (SquareWaves.Count == 0 || !SquareWaves.Contains(__instance))
		{
			return true;
		}
		try
		{
			Vector2 val = StartGetter(__instance);
			float num = Chebyshev(pos.x - val.x, pos.z - val.y);
			__result = !(num > DistanceGetter(__instance));
			return false;
		}
		catch (Exception e)
		{
			return WaveFailed(__instance, e);
		}
	}

	private static bool WaveFailed(object wave, Exception e)
	{
		SquareWaves.Remove(wave);
		SquareFoundationPlugin.Log.LogWarning((object)("Square wave disabled for this rune: " + e.Message));
		return true;
	}

	public static bool FractionPrefix(object __instance, Vector3 pos, ref float __result)
	{
		//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)
		if (SquareWaves.Count == 0 || !SquareWaves.Contains(__instance))
		{
			return true;
		}
		try
		{
			Vector2 val = StartGetter(__instance);
			float num = Chebyshev(pos.x - val.x, pos.z - val.y);
			float num2 = DistanceGetter(__instance);
			float num3 = WidthGetter(__instance);
			float num4 = num2 + num3 / 2f;
			float num5 = num2 - num3 / 2f;
			__result = ((num4 == num5) ? 0f : ((num - num4) / (num5 - num4)));
			return false;
		}
		catch (Exception e)
		{
			return WaveFailed(__instance, e);
		}
	}

	public static void RepaintPrefix(object __instance)
	{
		_paintSquare = SquareHolders.Count != 0 && SquareHolders.Contains(__instance);
	}

	public static void RepaintFinalizer()
	{
		_paintSquare = false;
	}

	public static void IsUnlockablePostfix(Piece piece, ref bool __result)
	{
		if (!__result && IsSquarePiece(piece))
		{
			__result = true;
		}
	}

	public static void IsUnlockedPostfix(Player player, Piece piece, ref bool __result)
	{
		if (IsSquarePiece(piece) && (Object)(object)OrigPiece != (Object)null && IsUnlockedOriginal != null)
		{
			__result = IsUnlockedOriginal(player, OrigPiece);
		}
	}

	public static void EnergyCostPostfix(Piece piece, ref float __result)
	{
		if (IsSquarePiece(piece))
		{
			__result *= SquareFoundationPlugin.CostMultiplier.Value;
		}
	}
}
internal static class Glyph
{
	private const int Size = 512;

	private const float Centre = 255.5f;

	private const float RadiusPx = 182.9f;

	private const float HalfLine = 2.2f;

	internal static Texture2D Build()
	{
		//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a8: Expected O, but got Unknown
		//IL_0267: Unknown result type (might be due to invalid IL or missing references)
		//IL_026c: Unknown result type (might be due to invalid IL or missing references)
		List<float[]> list = new List<float[]>();
		float num = 182.9f;
		float num2 = 120.714005f;
		float num3 = 47.553997f;
		float num4 = 20.119f;
		AddSquare(list, 0f, 0f, num);
		AddSquare(list, 0f, 0f, num2);
		AddSquare(list, num, 0f, num4);
		AddSquare(list, 0f - num, 0f, num4);
		AddSquare(list, 0f, num, num4);
		AddSquare(list, 0f, 0f - num, num4);
		AddLine(list, num3, 0f, 0f, num3);
		AddLine(list, 0f, num3, 0f - num3, 0f);
		AddLine(list, 0f - num3, 0f, 0f, 0f - num3);
		AddLine(list, 0f, 0f - num3, num3, 0f);
		AddLine(list, num3, 0f, num2, 0f);
		AddLine(list, 0f - num3, 0f, 0f - num2, 0f);
		AddLine(list, 0f, num3, 0f, num2);
		AddLine(list, 0f, 0f - num3, 0f, 0f - num2);
		AddLine(list, num2, num2, num, num);
		AddLine(list, 0f - num2, num2, 0f - num, num);
		AddLine(list, num2, 0f - num2, num, 0f - num);
		AddLine(list, 0f - num2, 0f - num2, 0f - num, 0f - num);
		AddLine(list, num2, 0f, 0f, num2);
		AddLine(list, 0f, num2, 0f - num2, 0f);
		AddLine(list, 0f - num2, 0f, 0f, 0f - num2);
		AddLine(list, 0f, 0f - num2, num2, 0f);
		Color32[] array = (Color32[])(object)new Color32[262144];
		float num5 = num + num4 + 2.2f + 2f;
		for (int i = 0; i < 512; i++)
		{
			float num6 = (float)i - 255.5f;
			for (int j = 0; j < 512; j++)
			{
				float num7 = (float)j - 255.5f;
				byte b = 0;
				if (Mathf.Abs(num7) <= num5 && Mathf.Abs(num6) <= num5)
				{
					float num8 = float.MaxValue;
					for (int k = 0; k < list.Count; k++)
					{
						float num9 = DistanceToSegment(num7, num6, list[k]);
						if (num9 < num8)
						{
							num8 = num9;
						}
					}
					float num10 = Mathf.Clamp01(2.7f - num8);
					b = (byte)Mathf.RoundToInt(num10 * 255f);
				}
				ref Color32 reference = ref array[i * 512 + j];
				reference = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b);
			}
		}
		Texture2D val = new Texture2D(512, 512, (TextureFormat)4, true);
		((Object)val).name = "SquareFoundationRuneGlyph";
		((Texture)val).wrapMode = (TextureWrapMode)1;
		((Texture)val).filterMode = (FilterMode)2;
		val.SetPixels32(array);
		val.Apply(true, false);
		return val;
	}

	private static void AddLine(List<float[]> segments, float x1, float y1, float x2, float y2)
	{
		segments.Add(new float[4] { x1, y1, x2, y2 });
	}

	private static void AddSquare(List<float[]> segments, float cx, float cy, float half)
	{
		AddLine(segments, cx - half, cy - half, cx + half, cy - half);
		AddLine(segments, cx + half, cy - half, cx + half, cy + half);
		AddLine(segments, cx + half, cy + half, cx - half, cy + half);
		AddLine(segments, cx - half, cy + half, cx - half, cy - half);
	}

	private static float DistanceToSegment(float px, float py, float[] s)
	{
		float num = s[2] - s[0];
		float num2 = s[3] - s[1];
		float num3 = px - s[0];
		float num4 = py - s[1];
		float num5 = num * num + num2 * num2;
		float num6 = ((num5 > 0f) ? Mathf.Clamp01((num3 * num + num4 * num2) / num5) : 0f);
		float num7 = num3 - num6 * num;
		float num8 = num4 - num6 * num2;
		return Mathf.Sqrt(num7 * num7 + num8 * num8);
	}
}

plugins/ClearSkyRune.dll

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

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

[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("danpe.RuneMagicClearSkyRune", "Rune Magic - Clear Sky Rune", "1.0.1")]
public class ClearSkyRunePlugin : BaseUnityPlugin
{
	public const string PluginGuid = "danpe.RuneMagicClearSkyRune";

	public const string PluginName = "Rune Magic - Clear Sky Rune";

	public const string PluginVersion = "1.0.1";

	internal const string RuneMagicGuid = "hyleanlegend.RuneMagic";

	internal const string OrigName = "runemagic_CanopyRune";

	internal const string RuneName = "runemagic_ClearSkyRune";

	internal const string RuneCloneName = "runemagic_ClearSkyRune(Clone)";

	private const string RuneFocusItemName = "$item_runemagic_runefocus";

	private const int TestedMajor = 1;

	private const int TestedMinor = 5;

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<float> Radius;

	internal static ConfigEntry<string> PreferredEnvironment;

	internal static ConfigEntry<float> EnergyCost;

	internal static ConfigEntry<float> Glow;

	internal static ConfigEntry<bool> AllowUntestedVersion;

	private static Harmony _harmony;

	private static GameObject _container;

	private static GameObject _clone;

	private static PieceTable _table;

	private static List<GameObject> _registeredPrefabs;

	private static Texture2D _glyph;

	private void Awake()
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Expected O, but got Unknown
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Expected O, but got Unknown
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When false the plugin does nothing at all (restart required). Multiplayer: install this add-on on the host (or dedicated server) AND on every client - a server without it permanently deletes engraved Clear Sky Runes when their area loads (unknown prefab); a client without it sees no rune and no effect. Fires going out, rain wear on buildings and weather-gated spawns are decided by whoever owns the object (on a hosted game usually the host) using that player's weather, so they follow the owner's rune state, not each client's.");
		Radius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Radius", 50f, new ConfigDescription("Radius in metres around the engraved rune inside which the weather is clear for you. Capped at 64: beyond that the rune's zone can be unloaded while you are still inside. Applied per client; changes apply within a second.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 64f), new object[0]));
		PreferredEnvironment = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Preferred environment", "", "Leave empty to let the rune pick the calmest environment of whatever biome you are in (no rain, ash, storm or darkness; a biome with no dry weather of its own, like the Swamp, gets plain Clear; the Mountain keeps its light snow and Freezing because both of its weathers are freezing). Or name one environment to force everywhere, e.g. Clear. The 'env' console command lists the names; boss and raid weather always wins over the rune.");
		EnergyCost = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Energy cost", 120f, new ConfigDescription("Runic energy needed to engrave the rune. 0 = same as the Canopy Rune (energyCost_runemagic_CanopyRune, 70 by default).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 400f), new object[0]));
		Glow = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Glow", 1.4f, new ConfigDescription("Brightness of the engraved glyph.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), new object[0]));
		AllowUntestedVersion = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Allow untested Rune Magic version", false, "This add-on was verified against Rune Magic 1.5.x. With any other version it stays off unless this is true.");
		if (!Enabled.Value)
		{
			Log.LogWarning((object)"Clear Sky Rune is OFF on this game instance. If this instance is the host or server, any placed Clear Sky Runes are permanently deleted when their area loads.");
			return;
		}
		try
		{
			Setup();
			Log.LogInfo((object)"Clear Sky Rune registered. Multiplayer: the host/server and every client need this add-on; the weather change is applied per client.");
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Setup failed - the Clear Sky Rune will not be available. Nothing else is affected. " + ex));
			Teardown();
			Log.LogWarning((object)"If this instance is the host or server, any placed Clear Sky Runes are permanently deleted when their area loads.");
		}
	}

	private void OnDestroy()
	{
		Teardown();
	}

	private static void Teardown()
	{
		Weather.Release();
		try
		{
			if ((Object)(object)_table != (Object)null && (Object)(object)_clone != (Object)null)
			{
				_table.m_pieces.Remove(_clone);
			}
			if (_registeredPrefabs != null && (Object)(object)_clone != (Object)null)
			{
				_registeredPrefabs.Remove(_clone);
			}
			if ((Object)(object)_container != (Object)null)
			{
				Object.Destroy((Object)(object)_container);
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Unregister failed: " + ex.Message));
		}
		_clone = null;
		_container = null;
		_table = null;
		if (_harmony != null)
		{
			List<MethodBase> list;
			try
			{
				list = new List<MethodBase>(_harmony.GetPatchedMethods());
			}
			catch (Exception)
			{
				list = new List<MethodBase>();
			}
			foreach (MethodBase item in list)
			{
				try
				{
					_harmony.Unpatch(item, (HarmonyPatchType)0, "danpe.RuneMagicClearSkyRune");
				}
				catch (Exception ex3)
				{
					Log.LogWarning((object)("Unpatch failed for " + item.Name + ": " + ex3.Message));
				}
			}
		}
		Patches.OrigPiece = null;
	}

	private static void CheckRuneMagicVersion()
	{
		if (!Chainloader.PluginInfos.TryGetValue("hyleanlegend.RuneMagic", out var value) || value == null)
		{
			throw new InvalidOperationException("Rune Magic is not loaded");
		}
		Version version = value.Metadata.Version;
		if (version.Major != 1 || version.Minor != 5)
		{
			if (!AllowUntestedVersion.Value)
			{
				throw new InvalidOperationException(string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x). Set 'Allow untested Rune Magic version' to true to try anyway."));
			}
			Log.LogWarning((object)string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x); continuing because the config allows it."));
		}
	}

	private static Type RequireType(string name)
	{
		Type type = AccessTools.TypeByName(name);
		if (type == null)
		{
			throw new InvalidOperationException("Rune Magic type not found: " + name);
		}
		return type;
	}

	private static MethodInfo RequireMethod(Type t, string name, Type[] args)
	{
		MethodInfo methodInfo = ((args == null) ? AccessTools.Method(t, name, (Type[])null, (Type[])null) : AccessTools.Method(t, name, args, (Type[])null));
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Method not found: " + t.FullName + "." + name);
		}
		return methodInfo;
	}

	private static FieldInfo RequireField(Type t, string name)
	{
		FieldInfo fieldInfo = AccessTools.Field(t, name);
		if (fieldInfo == null)
		{
			throw new InvalidOperationException("Field not found: " + t.FullName + "." + name);
		}
		return fieldInfo;
	}

	private static HarmonyMethod H(string name)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(typeof(Patches), name, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Patch method missing: " + name);
		}
		return new HarmonyMethod(methodInfo);
	}

	private static void Setup()
	{
		//IL_0494: Unknown result type (might be due to invalid IL or missing references)
		//IL_04a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_04bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c5: Expected O, but got Unknown
		//IL_0536: Unknown result type (might be due to invalid IL or missing references)
		//IL_0540: Expected O, but got Unknown
		CheckRuneMagicVersion();
		Type t = RequireType("ValheimMod.ValheimMod");
		MethodInfo methodInfo = RequireMethod(t, "get_isModAwake", Type.EmptyTypes);
		if (!(bool)methodInfo.Invoke(null, null))
		{
			throw new InvalidOperationException("Rune Magic did not finish initialising (isModAwake is false)");
		}
		Type type = RequireType("ValheimMod.Monobehaviours.CanopyRune");
		Type type2 = RequireType("ValheimMod.Monobehaviours.RuneProjector");
		Type t2 = RequireType("ValheimMod.UnlockManager");
		Type type3 = RequireType("ValheimMod.RunemagicPieceConfig");
		Type t3 = RequireType("ValheimMod.CustomContentSetupHandler");
		MethodInfo methodInfo2 = RequireMethod(t2, "isUnlockable", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo3 = RequireMethod(t2, "isUnlocked", new Type[2]
		{
			typeof(Player),
			typeof(Piece)
		});
		MethodInfo methodInfo4 = RequireMethod(type3, "getEnergyCost", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo5 = RequireMethod(t3, "RegisterPrefab", new Type[1] { typeof(GameObject) });
		MethodInfo methodInfo6 = RequireMethod(typeof(EnvMan), "FixedUpdate", Type.EmptyTypes);
		if (AccessTools.Field(typeof(EnvMan), "m_debugEnv") == null || AccessTools.Method(typeof(Player), "GetCurrentBiomeData", (Type[])null, (Type[])null) == null || AccessTools.Method(typeof(EnvMan), "GetAvailableEnvironments", new Type[1] { typeof(BiomeSector) }, (Type[])null) == null)
		{
			throw new InvalidOperationException("EnvMan / Player weather API changed");
		}
		FieldInfo fieldInfo = RequireField(type2, "runeTexture");
		ClearSkyRuneController.SetIntensityMethod = RequireMethod(type2, "setIntensity", new Type[1] { typeof(float) });
		ClearSkyRuneController.ProjectorType = type2;
		ConstructorInfo constructor = type3.GetConstructor(new Type[3]
		{
			typeof(Biome),
			typeof(string),
			typeof(string)
		});
		if (constructor == null)
		{
			throw new InvalidOperationException("RunemagicPieceConfig(Biome, string, string) constructor not found");
		}
		List<GameObject> list = RequireField(t3, "RegisteredItemPrefabs").GetValue(null) as List<GameObject>;
		List<GameObject> list2 = RequireField(t3, "RegisteredNonItemPrefabs").GetValue(null) as List<GameObject>;
		if (list == null || list2 == null)
		{
			throw new InvalidOperationException("Rune Magic's prefab lists have an unexpected type");
		}
		Patches.IsUnlockedOriginal = (Func<Player, Piece, bool>)Delegate.CreateDelegate(typeof(Func<Player, Piece, bool>), methodInfo3);
		PieceTable val = null;
		foreach (GameObject item in list)
		{
			ItemDrop val2 = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null && val2.m_itemData.m_shared.m_name == "$item_runemagic_runefocus")
			{
				val = val2.m_itemData.m_shared.m_buildPieces;
				break;
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			throw new InvalidOperationException("Rune Focus piece table not found");
		}
		GameObject val3 = null;
		List<GameObject> list3 = new List<GameObject>();
		foreach (GameObject piece in val.m_pieces)
		{
			if ((Object)(object)piece != (Object)null && ((Object)piece).name == "runemagic_ClearSkyRune")
			{
				list3.Add(piece);
			}
			else if ((Object)(object)piece != (Object)null && ((Object)piece).name == "runemagic_CanopyRune")
			{
				val3 = piece;
			}
		}
		foreach (GameObject item2 in list3)
		{
			Log.LogInfo((object)"Replacing a stale Clear Sky Rune entry.");
			val.m_pieces.Remove(item2);
			list2.Remove(item2);
		}
		if ((Object)(object)val3 == (Object)null || (Object)(object)val3.GetComponent<Piece>() == (Object)null || (Object)(object)val3.GetComponent(type) == (Object)null)
		{
			throw new InvalidOperationException("Canopy Rune prefab not found in the Rune Focus piece table");
		}
		Patches.OrigPiece = val3.GetComponent<Piece>();
		_glyph = Glyph.Build();
		Sprite icon = Sprite.Create(_glyph, new Rect(0f, 0f, (float)((Texture)_glyph).width, (float)((Texture)_glyph).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
		_harmony = new Harmony("danpe.RuneMagicClearSkyRune");
		_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, H("IsUnlockablePostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, H("IsUnlockedPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, H("EnergyCostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo6, H("EnvManFixedUpdatePrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_container = new GameObject("RuneMagicClearSkyRune_Prefabs");
		_container.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)_container);
		GameObject val4 = Object.Instantiate<GameObject>(val3, _container.transform);
		((Object)val4).name = "runemagic_ClearSkyRune";
		Component component = val4.GetComponent(type);
		if ((Object)(object)component != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component);
		}
		Demister component2 = val4.GetComponent<Demister>();
		if ((Object)(object)component2 != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component2);
		}
		ParticleSystemForceField component3 = val4.GetComponent<ParticleSystemForceField>();
		if ((Object)(object)component3 != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component3);
		}
		if ((Object)(object)val4.GetComponent(type) != (Object)null)
		{
			throw new InvalidOperationException("Could not remove the CanopyRune component from the clone");
		}
		val4.AddComponent<ClearSkyRuneController>();
		Piece component4 = val4.GetComponent<Piece>();
		component4.m_name = "Clear Sky Rune";
		component4.m_description = "Engrave on a standing stone. Within its reach the weather stays fair for you: no rain, ash or storm, whatever rages beyond. The wrath of a boss or a raid still darkens the sky.";
		component4.m_icon = icon;
		Component component5 = val4.GetComponent(type2);
		if ((Object)(object)component5 != (Object)null)
		{
			fieldInfo.SetValue(component5, _glyph);
		}
		_clone = val4;
		_table = val;
		_registeredPrefabs = list2;
		constructor.Invoke(new object[3]
		{
			(object)(Biome)8,
			"runemagic_ClearSkyRune",
			"runemagic_CanopyRune"
		});
		methodInfo5.Invoke(null, new object[1] { val4 });
		int num = val.m_pieces.IndexOf(val3);
		val.m_pieces.Insert(num + 1, val4);
	}
}
public class ClearSkyRuneController : MonoBehaviour
{
	internal static MethodInfo SetIntensityMethod;

	internal static Type ProjectorType;

	internal static readonly List<ClearSkyRuneController> Live = new List<ClearSkyRuneController>();

	private Component _projector;

	private float _appliedGlow = -1f;

	private float _nextCheck;

	private bool _ghost;

	private void Awake()
	{
		_ghost = ZNetView.m_forceDisableInit;
	}

	private void OnEnable()
	{
		if (!_ghost && !Live.Contains(this))
		{
			Live.Add(this);
		}
	}

	private void OnDisable()
	{
		Live.Remove(this);
	}

	private void Start()
	{
		if (!_ghost)
		{
			Apply();
		}
	}

	private void Update()
	{
		if (!_ghost && !(Time.time < _nextCheck))
		{
			_nextCheck = Time.time + 1f;
			Apply();
		}
	}

	private void Apply()
	{
		try
		{
			float num = ((ClearSkyRunePlugin.Glow != null) ? ClearSkyRunePlugin.Glow.Value : 1.4f);
			if (num != _appliedGlow && SetIntensityMethod != null && ProjectorType != null)
			{
				if ((Object)(object)_projector == (Object)null)
				{
					_projector = ((Component)this).GetComponent(ProjectorType);
				}
				if ((Object)(object)_projector != (Object)null)
				{
					SetIntensityMethod.Invoke(_projector, new object[1] { num });
					_appliedGlow = num;
				}
			}
		}
		catch (Exception ex)
		{
			Exception ex2 = ((ex.InnerException != null) ? ex.InnerException : ex);
			ClearSkyRunePlugin.Log.LogWarning((object)("Clear Sky Rune update failed: " + ex2.GetType().Name + ": " + ex2.Message));
			_nextCheck = Time.time + 30f;
		}
	}
}
internal static class Weather
{
	private static bool _owning;

	private static bool _yielded;

	private static string _lastWritten = "";

	private static EnvMan _env;

	private static float _nextPick;

	private static Biome _pickedBiome = (Biome)0;

	private static string _picked = "";

	private static string _badName;

	private static string Canonical(EnvMan env, string name)
	{
		List<EnvSetup> environments = env.m_environments;
		if (environments != null)
		{
			for (int i = 0; i < environments.Count; i++)
			{
				if (environments[i] != null && string.Equals(environments[i].m_name, name, StringComparison.OrdinalIgnoreCase))
				{
					return environments[i].m_name;
				}
			}
		}
		return null;
	}

	private static bool Inside(Vector3 pos)
	{
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		float value = ClearSkyRunePlugin.Radius.Value;
		List<ClearSkyRuneController> live = ClearSkyRuneController.Live;
		for (int num = live.Count - 1; num >= 0; num--)
		{
			ClearSkyRuneController clearSkyRuneController = live[num];
			if ((Object)(object)clearSkyRuneController == (Object)null)
			{
				live.RemoveAt(num);
			}
			else if (Utils.DistanceXZ(((Component)clearSkyRuneController).transform.position, pos) <= value)
			{
				return true;
			}
		}
		return false;
	}

	private static float Score(EnvSetup env)
	{
		float num = 0f;
		if (env.m_isWet)
		{
			num += 100f;
		}
		if (env.m_alwaysDark)
		{
			num += 50f;
		}
		if (env.m_isFreezing)
		{
			num += 20f;
		}
		if (env.m_isFreezingAtNight)
		{
			num += 3f;
		}
		if (env.m_isCold)
		{
			num += 2f;
		}
		num += Mathf.Clamp01(env.m_rainCloudAlpha) * 10f;
		num += (float)((env.m_psystems != null) ? env.m_psystems.Length : 0) * 4f;
		if (env.m_name != null && env.m_name.IndexOf("clear", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			num -= 5f;
		}
		return num;
	}

	private static string Pick(EnvMan env, Player player)
	{
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: 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_00cc: 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)
		string value = ClearSkyRunePlugin.PreferredEnvironment.Value;
		if (!string.IsNullOrEmpty(value))
		{
			string text = Canonical(env, value.Trim());
			if (text != null)
			{
				return text;
			}
			if (_badName != value)
			{
				_badName = value;
				ClearSkyRunePlugin.Log.LogWarning((object)("Preferred environment '" + value + "' does not exist - using the biome's calmest environment instead."));
			}
		}
		BiomeSector currentBiomeData = player.GetCurrentBiomeData();
		Biome val = (Biome)((currentBiomeData != null) ? ((int)currentBiomeData.Biome) : 0);
		if (val == _pickedBiome && Time.time < _nextPick && !string.IsNullOrEmpty(_picked))
		{
			return _picked;
		}
		_nextPick = Time.time + 1f;
		_pickedBiome = val;
		string text2 = "";
		float num = float.MaxValue;
		List<EnvEntry> list = ((currentBiomeData != null) ? env.GetAvailableEnvironments(currentBiomeData) : null);
		if (list != null)
		{
			Vector3 position = ((Component)player).transform.position;
			bool flag = WorldGenerator.IsAshlands(position.x, position.z);
			bool flag2 = WorldGenerator.IsDeepnorth(position.x, position.z);
			foreach (EnvEntry item in list)
			{
				if (item == null || (item.m_ashlandsOverride && !flag) || (item.m_deepnorthOverride && !flag2))
				{
					continue;
				}
				EnvSetup env2 = item.m_env;
				if (env2 != null && !string.IsNullOrEmpty(env2.m_name))
				{
					float num2 = Score(env2);
					if (num2 < num)
					{
						num = num2;
						text2 = env2.m_name;
					}
				}
			}
		}
		if (string.IsNullOrEmpty(text2) || num >= 50f)
		{
			string text3 = Canonical(env, "Clear");
			if (text3 != null || string.IsNullOrEmpty(text2))
			{
				text2 = ((text3 != null) ? text3 : "Clear");
			}
		}
		_picked = text2;
		return text2;
	}

	internal static void Tick(EnvMan env)
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		if (!object.ReferenceEquals(env, _env))
		{
			_env = env;
			_owning = false;
			_yielded = false;
			_lastWritten = "";
			_pickedBiome = (Biome)0;
			_picked = "";
		}
		Player localPlayer = Player.m_localPlayer;
		bool flag = (Object)(object)localPlayer != (Object)null && (Object)(object)ZNet.instance != (Object)null && !((Character)localPlayer).InInterior() && ClearSkyRuneController.Live.Count > 0 && Inside(((Component)localPlayer).transform.position);
		if (_owning && (env.m_debugEnv == null || env.m_debugEnv != _lastWritten))
		{
			_owning = false;
			_yielded = true;
			_lastWritten = "";
		}
		else if (!flag)
		{
			_yielded = false;
			Release(env);
		}
		else
		{
			if (!_owning && (_yielded || !string.IsNullOrEmpty(env.m_debugEnv)))
			{
				return;
			}
			string value = (((Object)(object)RandEventSystem.instance != (Object)null) ? RandEventSystem.instance.GetEnvOverride() : null);
			if (string.IsNullOrEmpty(value) && (Object)(object)PersistentEventSystem.instance != (Object)null)
			{
				value = PersistentEventSystem.instance.GetEnvironmentOverride();
			}
			if (!string.IsNullOrEmpty(value))
			{
				Release(env);
				return;
			}
			string text = Pick(env, localPlayer);
			if (env.m_debugEnv != text)
			{
				env.m_debugEnv = text;
			}
			_lastWritten = text;
			_owning = true;
		}
	}

	internal static void Release(EnvMan env)
	{
		if (_owning && (Object)(object)env != (Object)null && env.m_debugEnv == _lastWritten)
		{
			env.m_debugEnv = "";
		}
		_owning = false;
		_lastWritten = "";
	}

	internal static void Release()
	{
		Release(EnvMan.instance);
	}
}
public static class Patches
{
	internal static Piece OrigPiece;

	internal static Func<Player, Piece, bool> IsUnlockedOriginal;

	private static bool _failed;

	private static bool IsOurPiece(Piece piece)
	{
		if ((Object)(object)piece == (Object)null)
		{
			return false;
		}
		string name = ((Object)((Component)piece).gameObject).name;
		if (!(name == "runemagic_ClearSkyRune"))
		{
			return name == "runemagic_ClearSkyRune(Clone)";
		}
		return true;
	}

	public static void IsUnlockablePostfix(Piece piece, ref bool __result)
	{
		if (!__result && IsOurPiece(piece))
		{
			__result = true;
		}
	}

	public static void IsUnlockedPostfix(Player player, Piece piece, ref bool __result)
	{
		if (IsOurPiece(piece) && (Object)(object)OrigPiece != (Object)null && IsUnlockedOriginal != null)
		{
			__result = IsUnlockedOriginal(player, OrigPiece);
		}
	}

	public static void EnergyCostPostfix(Piece piece, ref float __result)
	{
		if (IsOurPiece(piece) && ClearSkyRunePlugin.EnergyCost != null && ClearSkyRunePlugin.EnergyCost.Value > 0f)
		{
			__result = ClearSkyRunePlugin.EnergyCost.Value;
		}
	}

	public static void EnvManFixedUpdatePrefix(EnvMan __instance)
	{
		if (_failed || (Object)(object)__instance == (Object)null)
		{
			return;
		}
		try
		{
			Weather.Tick(__instance);
		}
		catch (Exception ex)
		{
			_failed = true;
			Weather.Release(__instance);
			ClearSkyRunePlugin.Log.LogError((object)("Clear Sky Rune weather disabled for this session after an error: " + ex));
		}
	}
}
internal static class Glyph
{
	private const int Size = 512;

	private const float Centre = 255.5f;

	private const float HalfLine = 2.4f;

	internal static Texture2D Build()
	{
		//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bd: Expected O, but got Unknown
		//IL_027c: 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)
		List<float[]> list = new List<float[]>();
		List<float[]> list2 = new List<float[]>();
		list2.Add(new float[3] { 0f, -95f, 42f });
		for (int i = 0; i < 8; i++)
		{
			float num = (float)i * (float)Math.PI / 4f;
			float num2 = Mathf.Cos(num);
			float num3 = Mathf.Sin(num);
			list.Add(new float[4]
			{
				num2 * 56f,
				-95f + num3 * 56f,
				num2 * 84f,
				-95f + num3 * 84f
			});
		}
		list.Add(new float[4] { -150f, -10f, 150f, -10f });
		list2.Add(new float[3] { -160f, -10f, 10f });
		list2.Add(new float[3] { 160f, -10f, 10f });
		list.Add(new float[4] { -70f, 30f, -84f, 110f });
		list.Add(new float[4] { 0f, 30f, -14f, 110f });
		list.Add(new float[4] { 70f, 30f, 56f, 110f });
		list.Add(new float[4] { -150f, 150f, 150f, 20f });
		list2.Add(new float[3] { -160f, 154f, 10f });
		list2.Add(new float[3] { 160f, 16f, 10f });
		Color32[] array = (Color32[])(object)new Color32[262144];
		for (int j = 0; j < 512; j++)
		{
			float num4 = (float)j - 255.5f;
			for (int k = 0; k < 512; k++)
			{
				float num5 = (float)k - 255.5f;
				float num6 = float.MaxValue;
				for (int l = 0; l < list.Count; l++)
				{
					float num7 = DistanceToSegment(num5, num4, list[l]);
					if (num7 < num6)
					{
						num6 = num7;
					}
				}
				for (int m = 0; m < list2.Count; m++)
				{
					float num8 = num5 - list2[m][0];
					float num9 = num4 - list2[m][1];
					float num10 = Mathf.Abs(Mathf.Sqrt(num8 * num8 + num9 * num9) - list2[m][2]);
					if (num10 < num6)
					{
						num6 = num10;
					}
				}
				float num11 = Mathf.Clamp01(2.9f - num6);
				ref Color32 reference = ref array[j * 512 + k];
				reference = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)Mathf.RoundToInt(num11 * 255f));
			}
		}
		Texture2D val = new Texture2D(512, 512, (TextureFormat)4, true);
		((Object)val).name = "ClearSkyRuneGlyph";
		((Texture)val).wrapMode = (TextureWrapMode)1;
		((Texture)val).filterMode = (FilterMode)2;
		val.SetPixels32(array);
		val.Apply(true, false);
		return val;
	}

	private static float DistanceToSegment(float px, float py, float[] s)
	{
		float num = s[2] - s[0];
		float num2 = s[3] - s[1];
		float num3 = px - s[0];
		float num4 = py - s[1];
		float num5 = num * num + num2 * num2;
		float num6 = ((num5 > 0f) ? Mathf.Clamp01((num3 * num + num4 * num2) / num5) : 0f);
		float num7 = num3 - num6 * num;
		float num8 = num4 - num6 * num2;
		return Mathf.Sqrt(num7 * num7 + num8 * num8);
	}
}

plugins/SunRune.dll

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

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

[BepInPlugin("danpe.RuneMagicSunRune", "Rune Magic - Sun Rune", "1.0.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class SunRunePlugin : BaseUnityPlugin
{
	public const string PluginGuid = "danpe.RuneMagicSunRune";

	public const string PluginName = "Rune Magic - Sun Rune";

	public const string PluginVersion = "1.0.1";

	internal const string RuneMagicGuid = "hyleanlegend.RuneMagic";

	internal const string OrigName = "runemagic_CanopyRune";

	internal const string SunName = "runemagic_SunRune";

	internal const string SunCloneName = "runemagic_SunRune(Clone)";

	private const string RuneFocusItemName = "$item_runemagic_runefocus";

	private const int TestedMajor = 1;

	private const int TestedMinor = 5;

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<float> Radius;

	internal static ConfigEntry<float> TimeOfDay;

	internal static ConfigEntry<float> TransitionSeconds;

	internal static ConfigEntry<bool> GameplayFollowsRune;

	internal static ConfigEntry<float> EnergyCost;

	internal static ConfigEntry<float> Glow;

	internal static ConfigEntry<bool> AllowUntestedVersion;

	private static Harmony _harmony;

	private static GameObject _container;

	private static GameObject _clone;

	private static PieceTable _table;

	private static List<GameObject> _registeredPrefabs;

	private static Texture2D _glyph;

	private void Awake()
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Expected O, but got Unknown
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Expected O, but got Unknown
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Expected O, but got Unknown
		//IL_0134: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Expected O, but got Unknown
		//IL_0172: Unknown result type (might be due to invalid IL or missing references)
		//IL_017c: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When false the plugin does nothing at all (restart required). Multiplayer: install this add-on on the host (or dedicated server) AND on every client - a server without it permanently deletes engraved Sun Runes when their area loads (unknown prefab); a client without it sees no rune and no daylight.");
		Radius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Radius", 50f, new ConfigDescription("Radius in metres around the engraved rune inside which it is daytime for you. Capped at 64: beyond that the rune's zone can be unloaded while you are still inside. Applied per client; changes apply within a second.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 64f), new object[0]));
		TimeOfDay = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Time of day inside", 0.5f, new ConfigDescription("Which time the rune holds you at: 0.5 = noon, 0.35 = mid-morning, 0.65 = mid-afternoon (Valheim's day fraction; 0.25 is sunrise, 0.75 sunset). With 'Gameplay follows the rune' on, values below 0.5 are raised to 0.5 so beds keep working.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 0.7f), new object[0]));
		GameplayFollowsRune = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Gameplay follows the rune", false, "Off (default): only the sky and lighting change; the game's own day/night rules keep following the real clock, so night spawns, wisp fountains, sleeping, night cold and Ashlands day-heat behave exactly as before. On: the game also treats you as being in daytime while inside - night-only creatures leave and stop spawning, day-only ones spawn, wisp fountains go quiet and lured wisps vanish, no night cold - across every zone your game simulates (about 300 m around you, not just the rune), and in the Ashlands you build daytime heat while moving. If you host, that also decides spawning near you for everyone.");
		TransitionSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Transition seconds", 4f, new ConfigDescription("How long the sky takes to swing from the real time to the rune's daylight when you enter, and back when you leave.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f), new object[0]));
		EnergyCost = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Energy cost", 150f, new ConfigDescription("Runic energy needed to engrave the rune. 0 = same as the Canopy Rune (energyCost_runemagic_CanopyRune, 70 by default).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 400f), new object[0]));
		Glow = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Glow", 1.5f, new ConfigDescription("Brightness of the engraved glyph.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), new object[0]));
		AllowUntestedVersion = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Allow untested Rune Magic version", false, "This add-on was verified against Rune Magic 1.5.x. With any other version it stays off unless this is true.");
		if (!Enabled.Value)
		{
			Log.LogWarning((object)"Sun Rune is OFF on this game instance. If this instance is the host or server, any placed Sun Runes are permanently deleted when their area loads.");
			return;
		}
		try
		{
			Setup();
			Log.LogInfo((object)"Sun Rune registered. Multiplayer: the host/server and every client need this add-on; the daylight is applied per client.");
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Setup failed - the Sun Rune will not be available. Nothing else is affected. " + ex));
			Teardown();
			Log.LogWarning((object)"If this instance is the host or server, any placed Sun Runes are permanently deleted when their area loads.");
		}
	}

	private void OnDestroy()
	{
		Teardown();
	}

	private static void Teardown()
	{
		Daylight.Release();
		try
		{
			if ((Object)(object)_table != (Object)null && (Object)(object)_clone != (Object)null)
			{
				_table.m_pieces.Remove(_clone);
			}
			if (_registeredPrefabs != null && (Object)(object)_clone != (Object)null)
			{
				_registeredPrefabs.Remove(_clone);
			}
			if ((Object)(object)_container != (Object)null)
			{
				Object.Destroy((Object)(object)_container);
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Unregister failed: " + ex.Message));
		}
		_clone = null;
		_container = null;
		_table = null;
		if (_harmony != null)
		{
			List<MethodBase> list;
			try
			{
				list = new List<MethodBase>(_harmony.GetPatchedMethods());
			}
			catch (Exception)
			{
				list = new List<MethodBase>();
			}
			foreach (MethodBase item in list)
			{
				try
				{
					_harmony.Unpatch(item, (HarmonyPatchType)0, "danpe.RuneMagicSunRune");
				}
				catch (Exception ex3)
				{
					Log.LogWarning((object)("Unpatch failed for " + item.Name + ": " + ex3.Message));
				}
			}
		}
		Patches.OrigPiece = null;
	}

	private static void CheckRuneMagicVersion()
	{
		if (!Chainloader.PluginInfos.TryGetValue("hyleanlegend.RuneMagic", out var value) || value == null)
		{
			throw new InvalidOperationException("Rune Magic is not loaded");
		}
		Version version = value.Metadata.Version;
		if (version.Major != 1 || version.Minor != 5)
		{
			if (!AllowUntestedVersion.Value)
			{
				throw new InvalidOperationException(string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x). Set 'Allow untested Rune Magic version' to true to try anyway."));
			}
			Log.LogWarning((object)string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x); continuing because the config allows it."));
		}
	}

	private static Type RequireType(string name)
	{
		Type type = AccessTools.TypeByName(name);
		if (type == null)
		{
			throw new InvalidOperationException("Rune Magic type not found: " + name);
		}
		return type;
	}

	private static MethodInfo RequireMethod(Type t, string name, Type[] args)
	{
		MethodInfo methodInfo = ((args == null) ? AccessTools.Method(t, name, (Type[])null, (Type[])null) : AccessTools.Method(t, name, args, (Type[])null));
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Method not found: " + t.FullName + "." + name);
		}
		return methodInfo;
	}

	private static FieldInfo RequireField(Type t, string name)
	{
		FieldInfo fieldInfo = AccessTools.Field(t, name);
		if (fieldInfo == null)
		{
			throw new InvalidOperationException("Field not found: " + t.FullName + "." + name);
		}
		return fieldInfo;
	}

	private static HarmonyMethod H(string name)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(typeof(Patches), name, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Patch method missing: " + name);
		}
		return new HarmonyMethod(methodInfo);
	}

	private static void Setup()
	{
		//IL_048d: Unknown result type (might be due to invalid IL or missing references)
		//IL_049c: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_04be: Expected O, but got Unknown
		//IL_0565: Unknown result type (might be due to invalid IL or missing references)
		//IL_056f: Expected O, but got Unknown
		CheckRuneMagicVersion();
		Type t = RequireType("ValheimMod.ValheimMod");
		MethodInfo methodInfo = RequireMethod(t, "get_isModAwake", Type.EmptyTypes);
		if (!(bool)methodInfo.Invoke(null, null))
		{
			throw new InvalidOperationException("Rune Magic did not finish initialising (isModAwake is false)");
		}
		Type type = RequireType("ValheimMod.Monobehaviours.CanopyRune");
		Type type2 = RequireType("ValheimMod.Monobehaviours.RuneProjector");
		Type t2 = RequireType("ValheimMod.UnlockManager");
		Type type3 = RequireType("ValheimMod.RunemagicPieceConfig");
		Type t3 = RequireType("ValheimMod.CustomContentSetupHandler");
		MethodInfo methodInfo2 = RequireMethod(t2, "isUnlockable", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo3 = RequireMethod(t2, "isUnlocked", new Type[2]
		{
			typeof(Player),
			typeof(Piece)
		});
		MethodInfo methodInfo4 = RequireMethod(type3, "getEnergyCost", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo5 = RequireMethod(t3, "RegisterPrefab", new Type[1] { typeof(GameObject) });
		MethodInfo methodInfo6 = RequireMethod(typeof(EnvMan), "FixedUpdate", Type.EmptyTypes);
		MethodInfo methodInfo7 = RequireMethod(typeof(EnvMan), "UpdateTriggers", new Type[4]
		{
			typeof(float),
			typeof(float),
			typeof(Biome),
			typeof(float)
		});
		MethodInfo methodInfo8 = RequireMethod(typeof(EnvMan), "GetDayFraction", Type.EmptyTypes);
		FieldInfo fieldInfo = RequireField(type2, "runeTexture");
		SunRuneController.SetIntensityMethod = RequireMethod(type2, "setIntensity", new Type[1] { typeof(float) });
		SunRuneController.ProjectorType = type2;
		ConstructorInfo constructor = type3.GetConstructor(new Type[3]
		{
			typeof(Biome),
			typeof(string),
			typeof(string)
		});
		if (constructor == null)
		{
			throw new InvalidOperationException("RunemagicPieceConfig(Biome, string, string) constructor not found");
		}
		List<GameObject> list = RequireField(t3, "RegisteredItemPrefabs").GetValue(null) as List<GameObject>;
		List<GameObject> list2 = RequireField(t3, "RegisteredNonItemPrefabs").GetValue(null) as List<GameObject>;
		if (list == null || list2 == null)
		{
			throw new InvalidOperationException("Rune Magic's prefab lists have an unexpected type");
		}
		Patches.IsUnlockedOriginal = (Func<Player, Piece, bool>)Delegate.CreateDelegate(typeof(Func<Player, Piece, bool>), methodInfo3);
		PieceTable val = null;
		foreach (GameObject item in list)
		{
			ItemDrop val2 = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null && val2.m_itemData.m_shared.m_name == "$item_runemagic_runefocus")
			{
				val = val2.m_itemData.m_shared.m_buildPieces;
				break;
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			throw new InvalidOperationException("Rune Focus piece table not found");
		}
		GameObject val3 = null;
		List<GameObject> list3 = new List<GameObject>();
		foreach (GameObject piece in val.m_pieces)
		{
			if ((Object)(object)piece != (Object)null && ((Object)piece).name == "runemagic_SunRune")
			{
				list3.Add(piece);
			}
			else if ((Object)(object)piece != (Object)null && ((Object)piece).name == "runemagic_CanopyRune")
			{
				val3 = piece;
			}
		}
		foreach (GameObject item2 in list3)
		{
			Log.LogInfo((object)"Replacing a stale Sun Rune entry.");
			val.m_pieces.Remove(item2);
			list2.Remove(item2);
		}
		if ((Object)(object)val3 == (Object)null || (Object)(object)val3.GetComponent<Piece>() == (Object)null || (Object)(object)val3.GetComponent(type) == (Object)null)
		{
			throw new InvalidOperationException("Canopy Rune prefab not found in the Rune Focus piece table");
		}
		Patches.OrigPiece = val3.GetComponent<Piece>();
		_glyph = Glyph.Build();
		Sprite icon = Sprite.Create(_glyph, new Rect(0f, 0f, (float)((Texture)_glyph).width, (float)((Texture)_glyph).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
		_harmony = new Harmony("danpe.RuneMagicSunRune");
		_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, H("IsUnlockablePostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, H("IsUnlockedPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, H("EnergyCostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo6, H("EnvManFixedUpdatePrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo7, H("UpdateTriggersPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo8, (HarmonyMethod)null, H("GetDayFractionPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_container = new GameObject("RuneMagicSunRune_Prefabs");
		_container.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)_container);
		GameObject val4 = Object.Instantiate<GameObject>(val3, _container.transform);
		((Object)val4).name = "runemagic_SunRune";
		Component component = val4.GetComponent(type);
		if ((Object)(object)component != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component);
		}
		Demister component2 = val4.GetComponent<Demister>();
		if ((Object)(object)component2 != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component2);
		}
		ParticleSystemForceField component3 = val4.GetComponent<ParticleSystemForceField>();
		if ((Object)(object)component3 != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component3);
		}
		if ((Object)(object)val4.GetComponent(type) != (Object)null)
		{
			throw new InvalidOperationException("Could not remove the CanopyRune component from the clone");
		}
		val4.AddComponent<SunRuneController>();
		Piece component4 = val4.GetComponent<Piece>();
		component4.m_name = "Sun Rune";
		component4.m_description = "Engrave on a standing stone. Within its reach the night gives way and it is day for you, however dark the world beyond. The sky and the light change; the world's creatures keep to the true hour unless the rune is set to rule them too.";
		component4.m_icon = icon;
		Component component5 = val4.GetComponent(type2);
		if ((Object)(object)component5 != (Object)null)
		{
			fieldInfo.SetValue(component5, _glyph);
		}
		_clone = val4;
		_table = val;
		_registeredPrefabs = list2;
		constructor.Invoke(new object[3]
		{
			(object)(Biome)8,
			"runemagic_SunRune",
			"runemagic_CanopyRune"
		});
		methodInfo5.Invoke(null, new object[1] { val4 });
		int num = val.m_pieces.IndexOf(val3);
		val.m_pieces.Insert(num + 1, val4);
	}
}
public class SunRuneController : MonoBehaviour
{
	internal static MethodInfo SetIntensityMethod;

	internal static Type ProjectorType;

	internal static readonly List<SunRuneController> Live = new List<SunRuneController>();

	private Component _projector;

	private float _appliedGlow = -1f;

	private float _nextCheck;

	private bool _ghost;

	private void Awake()
	{
		_ghost = ZNetView.m_forceDisableInit;
	}

	private void OnEnable()
	{
		if (!_ghost && !Live.Contains(this))
		{
			Live.Add(this);
		}
	}

	private void OnDisable()
	{
		Live.Remove(this);
	}

	private void Start()
	{
		if (!_ghost)
		{
			Apply();
		}
	}

	private void Update()
	{
		if (!_ghost && !(Time.time < _nextCheck))
		{
			_nextCheck = Time.time + 1f;
			Apply();
		}
	}

	private void Apply()
	{
		try
		{
			float num = ((SunRunePlugin.Glow != null) ? SunRunePlugin.Glow.Value : 1.5f);
			if (num != _appliedGlow && SetIntensityMethod != null && ProjectorType != null)
			{
				if ((Object)(object)_projector == (Object)null)
				{
					_projector = ((Component)this).GetComponent(ProjectorType);
				}
				if ((Object)(object)_projector != (Object)null)
				{
					SetIntensityMethod.Invoke(_projector, new object[1] { num });
					_appliedGlow = num;
				}
			}
		}
		catch (Exception ex)
		{
			Exception ex2 = ((ex.InnerException != null) ? ex.InnerException : ex);
			SunRunePlugin.Log.LogWarning((object)("Sun Rune update failed: " + ex2.GetType().Name + ": " + ex2.Message));
			_nextCheck = Time.time + 30f;
		}
	}
}
internal static class Daylight
{
	private static float _blend;

	private static bool _owning;

	private static float _lastWritten = -1f;

	private static float _real;

	private static float _lastTriggerReal = -1f;

	private static EnvMan _env;

	internal static bool Owning => _owning;

	internal static float RealFraction(EnvMan env)
	{
		long num = ((env.m_dayLengthSec > 0) ? env.m_dayLengthSec : 1800);
		double timeSeconds = ZNet.instance.GetTimeSeconds();
		return Rescale(Mathf.Clamp01((float)(timeSeconds % (double)num / (double)num)));
	}

	internal static float GameplayFraction()
	{
		return _real;
	}

	internal static void TriggerFractions(EnvMan env, ref float oldFraction, ref float newFraction)
	{
		float num = RealFraction(env);
		oldFraction = ((_lastTriggerReal < 0f) ? num : _lastTriggerReal);
		newFraction = num;
		_lastTriggerReal = num;
	}

	private static float Rescale(float f)
	{
		if (f >= 0.15f && f <= 0.85f)
		{
			return 0.25f + (f - 0.15f) / 0.7f * 0.5f;
		}
		if (f < 0.5f)
		{
			return f / 0.15f * 0.25f;
		}
		return 0.75f + (f - 0.85f) / 0.15f * 0.25f;
	}

	private static bool Inside(Vector3 pos)
	{
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		float value = SunRunePlugin.Radius.Value;
		List<SunRuneController> live = SunRuneController.Live;
		for (int num = live.Count - 1; num >= 0; num--)
		{
			SunRuneController sunRuneController = live[num];
			if ((Object)(object)sunRuneController == (Object)null)
			{
				live.RemoveAt(num);
			}
			else if (Utils.DistanceXZ(((Component)sunRuneController).transform.position, pos) <= value)
			{
				return true;
			}
		}
		return false;
	}

	internal static void Tick(EnvMan env)
	{
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		if (!object.ReferenceEquals(env, _env))
		{
			_env = env;
			_owning = false;
			_blend = 0f;
			_lastWritten = -1f;
			_lastTriggerReal = -1f;
		}
		if ((Object)(object)ZNet.instance == (Object)null)
		{
			Release(env);
			return;
		}
		float fixedDeltaTime = Time.fixedDeltaTime;
		Player localPlayer = Player.m_localPlayer;
		bool flag = (Object)(object)localPlayer != (Object)null && SunRuneController.Live.Count > 0 && Inside(((Component)localPlayer).transform.position);
		if (!flag && _blend <= 0f)
		{
			Release(env);
		}
		else
		{
			if (!_owning && env.m_debugTimeOfDay)
			{
				return;
			}
			if (_owning && (!env.m_debugTimeOfDay || env.m_debugTime != _lastWritten))
			{
				_owning = false;
				_blend = 0f;
				return;
			}
			float num = fixedDeltaTime / Mathf.Max(0.5f, SunRunePlugin.TransitionSeconds.Value);
			_blend = Mathf.Clamp01(_blend + (flag ? num : (0f - num)));
			if (_blend <= 0f)
			{
				Release(env);
				return;
			}
			_real = RealFraction(env);
			float num2 = SunRunePlugin.TimeOfDay.Value;
			if (SunRunePlugin.GameplayFollowsRune.Value)
			{
				num2 = Mathf.Clamp(num2, 0.5f, 0.7f);
			}
			float num3 = ((_blend >= 1f) ? num2 : (Mathf.Repeat(Mathf.LerpAngle(_real * 360f, num2 * 360f, _blend), 360f) / 360f));
			_owning = true;
			env.m_debugTimeOfDay = true;
			env.m_debugTime = num3;
			_lastWritten = num3;
		}
	}

	internal static void Release(EnvMan env)
	{
		if (_owning && (Object)(object)env != (Object)null)
		{
			env.m_debugTimeOfDay = false;
		}
		_owning = false;
		_blend = 0f;
		_lastWritten = -1f;
		_lastTriggerReal = -1f;
	}

	internal static void Release()
	{
		Release(EnvMan.instance);
	}
}
public static class Patches
{
	internal static Piece OrigPiece;

	internal static Func<Player, Piece, bool> IsUnlockedOriginal;

	private static bool _failed;

	private static bool IsSunPiece(Piece piece)
	{
		if ((Object)(object)piece == (Object)null)
		{
			return false;
		}
		string name = ((Object)((Component)piece).gameObject).name;
		if (!(name == "runemagic_SunRune"))
		{
			return name == "runemagic_SunRune(Clone)";
		}
		return true;
	}

	public static void IsUnlockablePostfix(Piece piece, ref bool __result)
	{
		if (!__result && IsSunPiece(piece))
		{
			__result = true;
		}
	}

	public static void IsUnlockedPostfix(Player player, Piece piece, ref bool __result)
	{
		if (IsSunPiece(piece) && (Object)(object)OrigPiece != (Object)null && IsUnlockedOriginal != null)
		{
			__result = IsUnlockedOriginal(player, OrigPiece);
		}
	}

	public static void EnergyCostPostfix(Piece piece, ref float __result)
	{
		if (IsSunPiece(piece) && SunRunePlugin.EnergyCost != null && SunRunePlugin.EnergyCost.Value > 0f)
		{
			__result = SunRunePlugin.EnergyCost.Value;
		}
	}

	public static void EnvManFixedUpdatePrefix(EnvMan __instance)
	{
		if (_failed || (Object)(object)__instance == (Object)null)
		{
			return;
		}
		try
		{
			Daylight.Tick(__instance);
		}
		catch (Exception e)
		{
			Fail(__instance, e);
		}
	}

	public static void UpdateTriggersPrefix(EnvMan __instance, ref float oldDayFraction, ref float newDayFraction)
	{
		if (_failed || (Object)(object)__instance == (Object)null || !Daylight.Owning || (Object)(object)ZNet.instance == (Object)null)
		{
			return;
		}
		try
		{
			Daylight.TriggerFractions(__instance, ref oldDayFraction, ref newDayFraction);
		}
		catch (Exception e)
		{
			Fail(__instance, e);
		}
	}

	public static void GetDayFractionPostfix(ref float __result)
	{
		if (!_failed && Daylight.Owning && !SunRunePlugin.GameplayFollowsRune.Value)
		{
			__result = Daylight.GameplayFraction();
		}
	}

	private static void Fail(EnvMan env, Exception e)
	{
		_failed = true;
		Daylight.Release(env);
		SunRunePlugin.Log.LogError((object)("Sun Rune daylight disabled for this session after an error: " + e));
	}
}
internal static class Glyph
{
	private const int Size = 512;

	private const float Centre = 255.5f;

	private const float HalfLine = 2.4f;

	internal static Texture2D Build()
	{
		//IL_0309: Unknown result type (might be due to invalid IL or missing references)
		//IL_0310: Expected O, but got Unknown
		//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
		List<float[]> list = new List<float[]>();
		List<float[]> list2 = new List<float[]>();
		float num = 34f;
		float num2 = 78f;
		float num3 = 196f;
		float num4 = 150f;
		float num5 = 12f;
		list2.Add(new float[3] { 0f, 0f, num });
		list2.Add(new float[3] { 0f, 0f, num2 });
		for (int i = 0; i < 16; i++)
		{
			float num6 = (float)i * (float)Math.PI / 8f;
			float num7 = Mathf.Cos(num6);
			float num8 = Mathf.Sin(num6);
			bool flag = i % 2 == 0;
			float num9 = (flag ? num3 : num4);
			list.Add(new float[4]
			{
				num7 * (num2 + 10f),
				num8 * (num2 + 10f),
				num7 * (num9 - (flag ? num5 : 0f)),
				num8 * (num9 - (flag ? num5 : 0f))
			});
			if (flag)
			{
				list2.Add(new float[3]
				{
					num7 * num9,
					num8 * num9,
					num5
				});
			}
		}
		for (int j = 1; j < 8; j += 2)
		{
			float num10 = (float)j * (float)Math.PI / 4f;
			list.Add(new float[4]
			{
				Mathf.Cos(num10) * num,
				Mathf.Sin(num10) * num,
				Mathf.Cos(num10) * num2,
				Mathf.Sin(num10) * num2
			});
		}
		Color32[] array = (Color32[])(object)new Color32[262144];
		float num11 = num3 + num5 + 2.4f + 2f;
		for (int k = 0; k < 512; k++)
		{
			float num12 = (float)k - 255.5f;
			for (int l = 0; l < 512; l++)
			{
				float num13 = (float)l - 255.5f;
				byte b = 0;
				if (Mathf.Abs(num13) <= num11 && Mathf.Abs(num12) <= num11)
				{
					float num14 = float.MaxValue;
					for (int m = 0; m < list.Count; m++)
					{
						float num15 = DistanceToSegment(num13, num12, list[m]);
						if (num15 < num14)
						{
							num14 = num15;
						}
					}
					for (int n = 0; n < list2.Count; n++)
					{
						float num16 = num13 - list2[n][0];
						float num17 = num12 - list2[n][1];
						float num18 = Mathf.Abs(Mathf.Sqrt(num16 * num16 + num17 * num17) - list2[n][2]);
						if (num18 < num14)
						{
							num14 = num18;
						}
					}
					float num19 = Mathf.Clamp01(2.9f - num14);
					b = (byte)Mathf.RoundToInt(num19 * 255f);
				}
				ref Color32 reference = ref array[k * 512 + l];
				reference = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b);
			}
		}
		Texture2D val = new Texture2D(512, 512, (TextureFormat)4, true);
		((Object)val).name = "SunRuneGlyph";
		((Texture)val).wrapMode = (TextureWrapMode)1;
		((Texture)val).filterMode = (FilterMode)2;
		val.SetPixels32(array);
		val.Apply(true, false);
		return val;
	}

	private static float DistanceToSegment(float px, float py, float[] s)
	{
		float num = s[2] - s[0];
		float num2 = s[3] - s[1];
		float num3 = px - s[0];
		float num4 = py - s[1];
		float num5 = num * num + num2 * num2;
		float num6 = ((num5 > 0f) ? Mathf.Clamp01((num3 * num + num4 * num2) / num5) : 0f);
		float num7 = num3 - num6 * num;
		float num8 = num4 - num6 * num2;
		return Mathf.Sqrt(num7 * num7 + num8 * num8);
	}
}

plugins/WispRune.dll

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

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

[BepInPlugin("danpe.RuneMagicWispRune", "Rune Magic - Wisp Rune", "1.0.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class WispRunePlugin : BaseUnityPlugin
{
	public const string PluginGuid = "danpe.RuneMagicWispRune";

	public const string PluginName = "Rune Magic - Wisp Rune";

	public const string PluginVersion = "1.0.1";

	internal const string RuneMagicGuid = "hyleanlegend.RuneMagic";

	internal const string OrigName = "runemagic_CanopyRune";

	internal const string WispName = "runemagic_WispRune";

	internal const string WispCloneName = "runemagic_WispRune(Clone)";

	private const string RuneFocusItemName = "$item_runemagic_runefocus";

	private const int TestedMajor = 1;

	private const int TestedMinor = 5;

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<float> Radius;

	internal static ConfigEntry<float> EnergyCost;

	internal static ConfigEntry<float> Glow;

	internal static ConfigEntry<bool> AllowUntestedVersion;

	private static Harmony _harmony;

	private static GameObject _container;

	private static GameObject _clone;

	private static PieceTable _table;

	private static List<GameObject> _registeredPrefabs;

	private static Texture2D _glyph;

	private void Awake()
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Expected O, but got Unknown
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Expected O, but got Unknown
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When false the plugin does nothing at all (restart required). Multiplayer: install this add-on on the host (or dedicated server) AND on every client - a server without it permanently deletes engraved Wisp Runes when their area loads (unknown prefab); a client without it sees no rune and full mist.");
		Radius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Radius", 50f, new ConfigDescription("Radius in metres around the engraved rune in which Mistlands mist is held back. For scale: the Wisplight clears 15 m, a Wisp Torch 24 m, the large Dvergr demister 30 m. Changes apply to placed runes within a second. Applied per client (not synced by Rune Magic), so use the same value on every machine. The mist emitter does CPU work proportional to the radius squared, which is why the range is capped.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 100f), new object[0]));
		EnergyCost = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Energy cost", 100f, new ConfigDescription("Runic energy needed to engrave the rune. 0 = same as the Canopy Rune (Rune Magic's energyCost_runemagic_CanopyRune, 70 by default).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 400f), new object[0]));
		Glow = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Glow", 1.2f, new ConfigDescription("Brightness of the engraved glyph (the Canopy Rune uses 0.5 idle, 1.3 active).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), new object[0]));
		AllowUntestedVersion = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Allow untested Rune Magic version", false, "This add-on was verified against Rune Magic 1.5.x. With any other version it stays off unless this is true.");
		if (!Enabled.Value)
		{
			Log.LogWarning((object)"Wisp Rune is OFF on this game instance. If this instance is the host or server, any placed Wisp Runes are permanently deleted when their area loads.");
			return;
		}
		try
		{
			Setup();
			Log.LogInfo((object)"Wisp Rune registered. Multiplayer: the host/server and every client need this add-on; Radius, Glow and Energy cost come from each client's own config.");
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Setup failed - the Wisp Rune will not be available. Nothing else is affected. " + ex));
			Teardown();
			Log.LogWarning((object)"If this instance is the host or server, any placed Wisp Runes are permanently deleted when their area loads.");
		}
	}

	private void OnDestroy()
	{
		Teardown();
	}

	private static void Teardown()
	{
		try
		{
			if ((Object)(object)_table != (Object)null && (Object)(object)_clone != (Object)null)
			{
				_table.m_pieces.Remove(_clone);
			}
			if (_registeredPrefabs != null && (Object)(object)_clone != (Object)null)
			{
				_registeredPrefabs.Remove(_clone);
			}
			if ((Object)(object)_container != (Object)null)
			{
				Object.Destroy((Object)(object)_container);
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Unregister failed: " + ex.Message));
		}
		_clone = null;
		_container = null;
		_table = null;
		if (_harmony != null)
		{
			List<MethodBase> list;
			try
			{
				list = new List<MethodBase>(_harmony.GetPatchedMethods());
			}
			catch (Exception)
			{
				list = new List<MethodBase>();
			}
			foreach (MethodBase item in list)
			{
				try
				{
					_harmony.Unpatch(item, (HarmonyPatchType)0, "danpe.RuneMagicWispRune");
				}
				catch (Exception ex3)
				{
					Log.LogWarning((object)("Unpatch failed for " + item.Name + ": " + ex3.Message));
				}
			}
		}
		Patches.OrigPiece = null;
	}

	private static void CheckRuneMagicVersion()
	{
		if (!Chainloader.PluginInfos.TryGetValue("hyleanlegend.RuneMagic", out var value) || value == null)
		{
			throw new InvalidOperationException("Rune Magic is not loaded");
		}
		Version version = value.Metadata.Version;
		if (version.Major != 1 || version.Minor != 5)
		{
			if (!AllowUntestedVersion.Value)
			{
				throw new InvalidOperationException(string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x). Set 'Allow untested Rune Magic version' to true to try anyway."));
			}
			Log.LogWarning((object)string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x); continuing because the config allows it."));
		}
	}

	private static Type RequireType(string name)
	{
		Type type = AccessTools.TypeByName(name);
		if (type == null)
		{
			throw new InvalidOperationException("Rune Magic type not found: " + name);
		}
		return type;
	}

	private static MethodInfo RequireMethod(Type t, string name, Type[] args)
	{
		MethodInfo methodInfo = ((args == null) ? AccessTools.Method(t, name, (Type[])null, (Type[])null) : AccessTools.Method(t, name, args, (Type[])null));
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Method not found: " + t.FullName + "." + name);
		}
		return methodInfo;
	}

	private static FieldInfo RequireField(Type t, string name)
	{
		FieldInfo fieldInfo = AccessTools.Field(t, name);
		if (fieldInfo == null)
		{
			throw new InvalidOperationException("Field not found: " + t.FullName + "." + name);
		}
		return fieldInfo;
	}

	private static HarmonyMethod H(string name)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(typeof(Patches), name, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Patch method missing: " + name);
		}
		return new HarmonyMethod(methodInfo);
	}

	private static void Setup()
	{
		//IL_041d: Unknown result type (might be due to invalid IL or missing references)
		//IL_042c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0444: Unknown result type (might be due to invalid IL or missing references)
		//IL_044e: Expected O, but got Unknown
		//IL_04a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ae: Expected O, but got Unknown
		//IL_0545: Unknown result type (might be due to invalid IL or missing references)
		CheckRuneMagicVersion();
		Type t = RequireType("ValheimMod.ValheimMod");
		MethodInfo methodInfo = RequireMethod(t, "get_isModAwake", Type.EmptyTypes);
		if (!(bool)methodInfo.Invoke(null, null))
		{
			throw new InvalidOperationException("Rune Magic did not finish initialising (isModAwake is false)");
		}
		Type type = RequireType("ValheimMod.Monobehaviours.CanopyRune");
		Type type2 = RequireType("ValheimMod.Monobehaviours.RuneProjector");
		Type t2 = RequireType("ValheimMod.UnlockManager");
		Type type3 = RequireType("ValheimMod.RunemagicPieceConfig");
		Type t3 = RequireType("ValheimMod.CustomContentSetupHandler");
		MethodInfo methodInfo2 = RequireMethod(t2, "isUnlockable", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo3 = RequireMethod(t2, "isUnlocked", new Type[2]
		{
			typeof(Player),
			typeof(Piece)
		});
		MethodInfo methodInfo4 = RequireMethod(type3, "getEnergyCost", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo5 = RequireMethod(t3, "RegisterPrefab", new Type[1] { typeof(GameObject) });
		FieldInfo fieldInfo = RequireField(type2, "runeTexture");
		WispRuneController.SetIntensityMethod = RequireMethod(type2, "setIntensity", new Type[1] { typeof(float) });
		WispRuneController.ProjectorType = type2;
		ConstructorInfo constructor = type3.GetConstructor(new Type[3]
		{
			typeof(Biome),
			typeof(string),
			typeof(string)
		});
		if (constructor == null)
		{
			throw new InvalidOperationException("RunemagicPieceConfig(Biome, string, string) constructor not found");
		}
		List<GameObject> list = RequireField(t3, "RegisteredItemPrefabs").GetValue(null) as List<GameObject>;
		List<GameObject> list2 = RequireField(t3, "RegisteredNonItemPrefabs").GetValue(null) as List<GameObject>;
		if (list == null || list2 == null)
		{
			throw new InvalidOperationException("Rune Magic's prefab lists have an unexpected type");
		}
		Patches.IsUnlockedOriginal = (Func<Player, Piece, bool>)Delegate.CreateDelegate(typeof(Func<Player, Piece, bool>), methodInfo3);
		PieceTable val = null;
		foreach (GameObject item in list)
		{
			ItemDrop val2 = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null && val2.m_itemData.m_shared.m_name == "$item_runemagic_runefocus")
			{
				val = val2.m_itemData.m_shared.m_buildPieces;
				break;
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			throw new InvalidOperationException("Rune Focus piece table not found");
		}
		GameObject val3 = null;
		List<GameObject> list3 = new List<GameObject>();
		foreach (GameObject piece in val.m_pieces)
		{
			if ((Object)(object)piece != (Object)null && ((Object)piece).name == "runemagic_WispRune")
			{
				list3.Add(piece);
			}
			else if ((Object)(object)piece != (Object)null && ((Object)piece).name == "runemagic_CanopyRune")
			{
				val3 = piece;
			}
		}
		foreach (GameObject item2 in list3)
		{
			Log.LogInfo((object)"Replacing a stale Wisp Rune entry.");
			val.m_pieces.Remove(item2);
			list2.Remove(item2);
		}
		if ((Object)(object)val3 == (Object)null || (Object)(object)val3.GetComponent<Piece>() == (Object)null || (Object)(object)val3.GetComponent(type) == (Object)null || (Object)(object)val3.GetComponent<Demister>() == (Object)null || (Object)(object)val3.GetComponent<ParticleSystemForceField>() == (Object)null)
		{
			throw new InvalidOperationException("Canopy Rune prefab (with Demister + ParticleSystemForceField) not found in the Rune Focus piece table");
		}
		Patches.OrigPiece = val3.GetComponent<Piece>();
		_glyph = Glyph.Build();
		Sprite icon = Sprite.Create(_glyph, new Rect(0f, 0f, (float)((Texture)_glyph).width, (float)((Texture)_glyph).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
		_harmony = new Harmony("danpe.RuneMagicWispRune");
		_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, H("IsUnlockablePostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, H("IsUnlockedPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, H("EnergyCostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_container = new GameObject("RuneMagicWispRune_Prefabs");
		_container.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)_container);
		GameObject val4 = Object.Instantiate<GameObject>(val3, _container.transform);
		((Object)val4).name = "runemagic_WispRune";
		Component component = val4.GetComponent(type);
		if ((Object)(object)component != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component);
		}
		if ((Object)(object)val4.GetComponent(type) != (Object)null)
		{
			throw new InvalidOperationException("Could not remove the CanopyRune component from the clone");
		}
		val4.AddComponent<WispRuneController>();
		Demister component2 = val4.GetComponent<Demister>();
		ParticleSystemForceField component3 = val4.GetComponent<ParticleSystemForceField>();
		component2.m_disableForcefieldDelay = 5f;
		component3.gravity = new MinMaxCurve(-0.05f);
		component3.gravityFocus = 0f;
		Piece component4 = val4.GetComponent<Piece>();
		component4.m_name = "Wisp Rune";
		component4.m_description = "Engrave on a standing stone. Holds back the mist for a wide stretch around it, like a great unseen wisp.";
		component4.m_icon = icon;
		Component component5 = val4.GetComponent(type2);
		if ((Object)(object)component5 != (Object)null)
		{
			fieldInfo.SetValue(component5, _glyph);
		}
		_clone = val4;
		_table = val;
		_registeredPrefabs = list2;
		constructor.Invoke(new object[3]
		{
			(object)(Biome)8,
			"runemagic_WispRune",
			"runemagic_CanopyRune"
		});
		methodInfo5.Invoke(null, new object[1] { val4 });
		int num = val.m_pieces.IndexOf(val3);
		val.m_pieces.Insert(num + 1, val4);
	}
}
public class WispRuneController : MonoBehaviour
{
	internal static MethodInfo SetIntensityMethod;

	internal static Type ProjectorType;

	private Demister _demister;

	private ParticleSystemForceField _field;

	private Component _projector;

	private float _appliedRadius = -1f;

	private float _appliedGlow = -1f;

	private float _nextCheck;

	private bool _ghost;

	private void Awake()
	{
		_demister = ((Component)this).GetComponent<Demister>();
		_field = ((Component)this).GetComponent<ParticleSystemForceField>();
		_ghost = ZNetView.m_forceDisableInit;
		if (_ghost && (Object)(object)_demister != (Object)null)
		{
			((Behaviour)_demister).enabled = false;
		}
	}

	private void Start()
	{
		if (!_ghost)
		{
			Apply();
		}
	}

	private void Update()
	{
		if (!_ghost && !(Time.time < _nextCheck))
		{
			_nextCheck = Time.time + 1f;
			Apply();
		}
	}

	private void Apply()
	{
		try
		{
			float num = ((WispRunePlugin.Radius != null) ? Mathf.Clamp(WispRunePlugin.Radius.Value, 2f, 100f) : 50f);
			if ((Object)(object)_field != (Object)null && num != _appliedRadius)
			{
				_field.endRange = num;
				_appliedRadius = num;
			}
			float num2 = ((WispRunePlugin.Glow != null) ? WispRunePlugin.Glow.Value : 1.2f);
			if (num2 != _appliedGlow && SetIntensityMethod != null && ProjectorType != null)
			{
				if ((Object)(object)_projector == (Object)null)
				{
					_projector = ((Component)this).GetComponent(ProjectorType);
				}
				if ((Object)(object)_projector != (Object)null)
				{
					SetIntensityMethod.Invoke(_projector, new object[1] { num2 });
					_appliedGlow = num2;
				}
			}
		}
		catch (Exception ex)
		{
			Exception ex2 = ((ex.InnerException != null) ? ex.InnerException : ex);
			WispRunePlugin.Log.LogWarning((object)("Wisp Rune update failed: " + ex2.GetType().Name + ": " + ex2.Message));
			_nextCheck = Time.time + 30f;
		}
	}
}
public static class Patches
{
	internal static Piece OrigPiece;

	internal static Func<Player, Piece, bool> IsUnlockedOriginal;

	private static bool IsWispPiece(Piece piece)
	{
		if ((Object)(object)piece == (Object)null)
		{
			return false;
		}
		string name = ((Object)((Component)piece).gameObject).name;
		if (!(name == "runemagic_WispRune"))
		{
			return name == "runemagic_WispRune(Clone)";
		}
		return true;
	}

	public static void IsUnlockablePostfix(Piece piece, ref bool __result)
	{
		if (!__result && IsWispPiece(piece))
		{
			__result = true;
		}
	}

	public static void IsUnlockedPostfix(Player player, Piece piece, ref bool __result)
	{
		if (IsWispPiece(piece) && (Object)(object)OrigPiece != (Object)null && IsUnlockedOriginal != null)
		{
			__result = IsUnlockedOriginal(player, OrigPiece);
		}
	}

	public static void EnergyCostPostfix(Piece piece, ref float __result)
	{
		if (IsWispPiece(piece) && WispRunePlugin.EnergyCost != null && WispRunePlugin.EnergyCost.Value > 0f)
		{
			__result = WispRunePlugin.EnergyCost.Value;
		}
	}
}
internal static class Glyph
{
	private const int Size = 512;

	private const float Centre = 255.5f;

	private const float HalfLine = 2.4f;

	internal static Texture2D Build()
	{
		//IL_0323: Unknown result type (might be due to invalid IL or missing references)
		//IL_032a: Expected O, but got Unknown
		//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)
		List<float[]> list = new List<float[]>();
		List<float[]> list2 = new List<float[]>();
		float num = 26f;
		float num2 = 95f;
		float num3 = 190f;
		float num4 = 16f;
		list2.Add(new float[3] { 0f, 0f, num });
		list2.Add(new float[3] { 0f, 0f, num2 });
		list2.Add(new float[3]
		{
			0f,
			0f,
			num2 + 14f
		});
		for (int i = 0; i < 8; i++)
		{
			float num5 = (float)i * (float)Math.PI / 4f;
			float num6 = Mathf.Cos(num5);
			float num7 = Mathf.Sin(num5);
			list.Add(new float[4]
			{
				num6 * (num2 + 14f),
				num7 * (num2 + 14f),
				num6 * (num3 - num4),
				num7 * (num3 - num4)
			});
			list2.Add(new float[3]
			{
				num6 * num3,
				num7 * num3,
				num4
			});
			float num8 = num6 * (num2 + 48f);
			float num9 = num7 * (num2 + 48f);
			list.Add(new float[4]
			{
				num8 - num7 * 12f,
				num9 + num6 * 12f,
				num8 + num7 * 12f,
				num9 - num6 * 12f
			});
			if (i % 2 == 1)
			{
				list.Add(new float[4]
				{
					num6 * num,
					num7 * num,
					num6 * num2,
					num7 * num2
				});
			}
		}
		Color32[] array = (Color32[])(object)new Color32[262144];
		float num10 = num3 + num4 + 2.4f + 2f;
		for (int j = 0; j < 512; j++)
		{
			float num11 = (float)j - 255.5f;
			for (int k = 0; k < 512; k++)
			{
				float num12 = (float)k - 255.5f;
				byte b = 0;
				if (Mathf.Abs(num12) <= num10 && Mathf.Abs(num11) <= num10)
				{
					float num13 = float.MaxValue;
					for (int l = 0; l < list.Count; l++)
					{
						float num14 = DistanceToSegment(num12, num11, list[l]);
						if (num14 < num13)
						{
							num13 = num14;
						}
					}
					for (int m = 0; m < list2.Count; m++)
					{
						float num15 = num12 - list2[m][0];
						float num16 = num11 - list2[m][1];
						float num17 = Mathf.Abs(Mathf.Sqrt(num15 * num15 + num16 * num16) - list2[m][2]);
						if (num17 < num13)
						{
							num13 = num17;
						}
					}
					float num18 = Mathf.Clamp01(2.9f - num13);
					b = (byte)Mathf.RoundToInt(num18 * 255f);
				}
				ref Color32 reference = ref array[j * 512 + k];
				reference = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b);
			}
		}
		Texture2D val = new Texture2D(512, 512, (TextureFormat)4, true);
		((Object)val).name = "WispRuneGlyph";
		((Texture)val).wrapMode = (TextureWrapMode)1;
		((Texture)val).filterMode = (FilterMode)2;
		val.SetPixels32(array);
		val.Apply(true, false);
		return val;
	}

	private static float DistanceToSegment(float px, float py, float[] s)
	{
		float num = s[2] - s[0];
		float num2 = s[3] - s[1];
		float num3 = px - s[0];
		float num4 = py - s[1];
		float num5 = num * num + num2 * num2;
		float num6 = ((num5 > 0f) ? Mathf.Clamp01((num3 * num + num4 * num2) / num5) : 0f);
		float num7 = num3 - num6 * num;
		float num8 = num4 - num6 * num2;
		return Mathf.Sqrt(num7 * num7 + num8 * num8);
	}
}

plugins/StaminaRune.dll

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

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

[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("danpe.RuneMagicStaminaRune", "Rune Magic - Stamina Rune", "1.0.1")]
public class StaminaRunePlugin : BaseUnityPlugin
{
	public const string PluginGuid = "danpe.RuneMagicStaminaRune";

	public const string PluginName = "Rune Magic - Stamina Rune";

	public const string PluginVersion = "1.0.1";

	internal const string RuneMagicGuid = "hyleanlegend.RuneMagic";

	internal const string OrigName = "runemagic_CanopyRune";

	internal const string RuneName = "runemagic_StaminaRune";

	internal const string RuneCloneName = "runemagic_StaminaRune(Clone)";

	internal const string EffectName = "SE_danpe_StaminaRune";

	private const string RuneFocusItemName = "$item_runemagic_runefocus";

	private const int TestedMajor = 1;

	private const int TestedMinor = 5;

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<float> Radius;

	internal static ConfigEntry<float> RegenMultiplier;

	internal static ConfigEntry<bool> RegenWhileUsing;

	internal static ConfigEntry<float> EnergyCost;

	internal static ConfigEntry<float> Glow;

	internal static ConfigEntry<bool> AllowUntestedVersion;

	private static Harmony _harmony;

	private static GameObject _container;

	private static GameObject _clone;

	private static PieceTable _table;

	private static List<GameObject> _registeredPrefabs;

	private static Texture2D _glyph;

	private void Awake()
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Expected O, but got Unknown
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Expected O, but got Unknown
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Expected O, but got Unknown
		//IL_0134: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When false the plugin does nothing at all (restart required). Multiplayer: install this add-on on the host (or dedicated server) AND on every client - a server without it permanently deletes engraved Stamina Runes when their area loads (unknown prefab); a client without it sees no rune and gets no effect. The effect is applied per client, to each player's own character.");
		Radius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Radius", 30f, new ConfigDescription("Radius in metres around the engraved rune inside which your stamina regenerates faster (also counted up and down, so a cliff or cellar far above or below is outside). Capped at 64: beyond that the rune's zone can be unloaded while you are still inside. Applied per client.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 64f), new object[0]));
		RegenMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Regeneration multiplier", 10f, new ConfigDescription("How many times faster stamina regenerates inside the rune (the game's own regeneration is about 5 stamina a second with a full bar, rising to about 10 when it is nearly empty, times the world's stamina modifier). Adds to other regeneration buffs the way the game combines them. Changes apply within a second.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), new object[0]));
		RegenWhileUsing = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Regenerate while using stamina", true, "Normally stamina only starts coming back a second after you last used any, so there is no regeneration at all while you reel in a fish, run or build. On: inside the rune it keeps regenerating anyway (reeling counts as blocking, which the game regenerates at 80 %; still none while attacking, dodging, wall-running, swimming out of your depth or over-encumbered, like the game itself).");
		EnergyCost = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Energy cost", 120f, new ConfigDescription("Runic energy needed to engrave the rune. 0 = same as the Canopy Rune (energyCost_runemagic_CanopyRune, 70 by default).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f), new object[0]));
		Glow = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Glow", 1.4f, new ConfigDescription("Brightness of the engraved glyph.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), new object[0]));
		AllowUntestedVersion = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Allow untested Rune Magic version", false, "This add-on was verified against Rune Magic 1.5.x. With any other version it stays off unless this is true.");
		if (!Enabled.Value)
		{
			Log.LogWarning((object)"Stamina Rune is OFF on this game instance. If this instance is the host or server, any placed Stamina Runes are permanently deleted when their area loads.");
			return;
		}
		try
		{
			Setup();
			Log.LogInfo((object)"Stamina Rune registered. Multiplayer: the host/server and every client need this add-on; the effect is applied per client.");
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Setup failed - the Stamina Rune will not be available. Nothing else is affected. " + ex));
			Teardown();
			Log.LogWarning((object)"If this instance is the host or server, any placed Stamina Runes are permanently deleted when their area loads.");
		}
	}

	private void OnDestroy()
	{
		Teardown();
	}

	private static void Teardown()
	{
		Boost.Release();
		try
		{
			if ((Object)(object)_table != (Object)null && (Object)(object)_clone != (Object)null)
			{
				_table.m_pieces.Remove(_clone);
			}
			if (_registeredPrefabs != null && (Object)(object)_clone != (Object)null)
			{
				_registeredPrefabs.Remove(_clone);
			}
			if ((Object)(object)_container != (Object)null)
			{
				Object.Destroy((Object)(object)_container);
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Unregister failed: " + ex.Message));
		}
		_clone = null;
		_container = null;
		_table = null;
		if (_harmony != null)
		{
			List<MethodBase> list;
			try
			{
				list = new List<MethodBase>(_harmony.GetPatchedMethods());
			}
			catch (Exception)
			{
				list = new List<MethodBase>();
			}
			foreach (MethodBase item in list)
			{
				try
				{
					_harmony.Unpatch(item, (HarmonyPatchType)0, "danpe.RuneMagicStaminaRune");
				}
				catch (Exception ex3)
				{
					Log.LogWarning((object)("Unpatch failed for " + item.Name + ": " + ex3.Message));
				}
			}
		}
		Patches.OrigPiece = null;
	}

	private static void CheckRuneMagicVersion()
	{
		if (!Chainloader.PluginInfos.TryGetValue("hyleanlegend.RuneMagic", out var value) || value == null)
		{
			throw new InvalidOperationException("Rune Magic is not loaded");
		}
		Version version = value.Metadata.Version;
		if (version.Major != 1 || version.Minor != 5)
		{
			if (!AllowUntestedVersion.Value)
			{
				throw new InvalidOperationException(string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x). Set 'Allow untested Rune Magic version' to true to try anyway."));
			}
			Log.LogWarning((object)string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x); continuing because the config allows it."));
		}
	}

	private static Type RequireType(string name)
	{
		Type type = AccessTools.TypeByName(name);
		if (type == null)
		{
			throw new InvalidOperationException("Rune Magic type not found: " + name);
		}
		return type;
	}

	private static MethodInfo RequireMethod(Type t, string name, Type[] args)
	{
		MethodInfo methodInfo = ((args == null) ? AccessTools.Method(t, name, (Type[])null, (Type[])null) : AccessTools.Method(t, name, args, (Type[])null));
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Method not found: " + t.FullName + "." + name);
		}
		return methodInfo;
	}

	private static FieldInfo RequireField(Type t, string name)
	{
		FieldInfo fieldInfo = AccessTools.Field(t, name);
		if (fieldInfo == null)
		{
			throw new InvalidOperationException("Field not found: " + t.FullName + "." + name);
		}
		return fieldInfo;
	}

	private static HarmonyMethod H(string name)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(typeof(Patches), name, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Patch method missing: " + name);
		}
		return new HarmonyMethod(methodInfo);
	}

	private static void Setup()
	{
		//IL_048b: Unknown result type (might be due to invalid IL or missing references)
		//IL_049a: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c3: Expected O, but got Unknown
		//IL_0581: Unknown result type (might be due to invalid IL or missing references)
		//IL_058b: Expected O, but got Unknown
		CheckRuneMagicVersion();
		Type t = RequireType("ValheimMod.ValheimMod");
		MethodInfo methodInfo = RequireMethod(t, "get_isModAwake", Type.EmptyTypes);
		if (!(bool)methodInfo.Invoke(null, null))
		{
			throw new InvalidOperationException("Rune Magic did not finish initialising (isModAwake is false)");
		}
		Type type = RequireType("ValheimMod.Monobehaviours.CanopyRune");
		Type type2 = RequireType("ValheimMod.Monobehaviours.RuneProjector");
		Type t2 = RequireType("ValheimMod.UnlockManager");
		Type type3 = RequireType("ValheimMod.RunemagicPieceConfig");
		Type t3 = RequireType("ValheimMod.CustomContentSetupHandler");
		MethodInfo methodInfo2 = RequireMethod(t2, "isUnlockable", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo3 = RequireMethod(t2, "isUnlocked", new Type[2]
		{
			typeof(Player),
			typeof(Piece)
		});
		MethodInfo methodInfo4 = RequireMethod(type3, "getEnergyCost", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo5 = RequireMethod(t3, "RegisterPrefab", new Type[1] { typeof(GameObject) });
		MethodInfo methodInfo6 = RequireMethod(typeof(Player), "UpdateStats", new Type[1] { typeof(float) });
		MethodInfo methodInfo7 = RequireMethod(typeof(ObjectDB), "Awake", Type.EmptyTypes);
		MethodInfo methodInfo8 = RequireMethod(typeof(ObjectDB), "CopyOtherDB", new Type[1] { typeof(ObjectDB) });
		RequireField(typeof(Player), "m_staminaRegenTimer");
		FieldInfo fieldInfo = RequireField(type2, "runeTexture");
		StaminaRuneController.SetIntensityMethod = RequireMethod(type2, "setIntensity", new Type[1] { typeof(float) });
		StaminaRuneController.ProjectorType = type2;
		ConstructorInfo constructor = type3.GetConstructor(new Type[3]
		{
			typeof(Biome),
			typeof(string),
			typeof(string)
		});
		if (constructor == null)
		{
			throw new InvalidOperationException("RunemagicPieceConfig(Biome, string, string) constructor not found");
		}
		List<GameObject> list = RequireField(t3, "RegisteredItemPrefabs").GetValue(null) as List<GameObject>;
		List<GameObject> list2 = RequireField(t3, "RegisteredNonItemPrefabs").GetValue(null) as List<GameObject>;
		if (list == null || list2 == null)
		{
			throw new InvalidOperationException("Rune Magic's prefab lists have an unexpected type");
		}
		Patches.IsUnlockedOriginal = (Func<Player, Piece, bool>)Delegate.CreateDelegate(typeof(Func<Player, Piece, bool>), methodInfo3);
		PieceTable val = null;
		foreach (GameObject item in list)
		{
			ItemDrop val2 = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null && val2.m_itemData.m_shared.m_name == "$item_runemagic_runefocus")
			{
				val = val2.m_itemData.m_shared.m_buildPieces;
				break;
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			throw new InvalidOperationException("Rune Focus piece table not found");
		}
		GameObject val3 = null;
		List<GameObject> list3 = new List<GameObject>();
		foreach (GameObject piece in val.m_pieces)
		{
			if ((Object)(object)piece != (Object)null && ((Object)piece).name == "runemagic_StaminaRune")
			{
				list3.Add(piece);
			}
			else if ((Object)(object)piece != (Object)null && ((Object)piece).name == "runemagic_CanopyRune")
			{
				val3 = piece;
			}
		}
		foreach (GameObject item2 in list3)
		{
			Log.LogInfo((object)"Replacing a stale Stamina Rune entry.");
			val.m_pieces.Remove(item2);
			list2.Remove(item2);
		}
		if ((Object)(object)val3 == (Object)null || (Object)(object)val3.GetComponent<Piece>() == (Object)null || (Object)(object)val3.GetComponent(type) == (Object)null)
		{
			throw new InvalidOperationException("Canopy Rune prefab not found in the Rune Focus piece table");
		}
		Patches.OrigPiece = val3.GetComponent<Piece>();
		_glyph = Glyph.Build();
		Sprite icon = Sprite.Create(_glyph, new Rect(0f, 0f, (float)((Texture)_glyph).width, (float)((Texture)_glyph).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
		Boost.CreateEffect(icon);
		_harmony = new Harmony("danpe.RuneMagicStaminaRune");
		_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, H("IsUnlockablePostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, H("IsUnlockedPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, H("EnergyCostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo6, H("UpdateStatsPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, H("ObjectDBPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo8, (HarmonyMethod)null, H("ObjectDBPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		if ((Object)(object)ObjectDB.instance != (Object)null)
		{
			Boost.Register(ObjectDB.instance);
		}
		_container = new GameObject("RuneMagicStaminaRune_Prefabs");
		_container.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)_container);
		GameObject val4 = Object.Instantiate<GameObject>(val3, _container.transform);
		((Object)val4).name = "runemagic_StaminaRune";
		Component component = val4.GetComponent(type);
		if ((Object)(object)component != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component);
		}
		Demister component2 = val4.GetComponent<Demister>();
		if ((Object)(object)component2 != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component2);
		}
		ParticleSystemForceField component3 = val4.GetComponent<ParticleSystemForceField>();
		if ((Object)(object)component3 != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component3);
		}
		if ((Object)(object)val4.GetComponent(type) != (Object)null)
		{
			throw new InvalidOperationException("Could not remove the CanopyRune component from the clone");
		}
		val4.AddComponent<StaminaRuneController>();
		Piece component4 = val4.GetComponent<Piece>();
		component4.m_name = "Stamina Rune";
		component4.m_description = "Engrave on a standing stone. Within its reach your stamina surges back many times faster, and keeps coming back even while you spend it - reel, run and build without pause.";
		component4.m_icon = icon;
		Component component5 = val4.GetComponent(type2);
		if ((Object)(object)component5 != (Object)null)
		{
			fieldInfo.SetValue(component5, _glyph);
		}
		_clone = val4;
		_table = val;
		_registeredPrefabs = list2;
		constructor.Invoke(new object[3]
		{
			(object)(Biome)8,
			"runemagic_StaminaRune",
			"runemagic_CanopyRune"
		});
		methodInfo5.Invoke(null, new object[1] { val4 });
		int num = val.m_pieces.IndexOf(val3);
		val.m_pieces.Insert(num + 1, val4);
	}
}
public class StaminaRuneController : MonoBehaviour
{
	internal static MethodInfo SetIntensityMethod;

	internal static Type ProjectorType;

	internal static readonly List<StaminaRuneController> Live = new List<StaminaRuneController>();

	private Component _projector;

	private float _appliedGlow = -1f;

	private float _nextCheck;

	private bool _ghost;

	private void Awake()
	{
		_ghost = ZNetView.m_forceDisableInit;
	}

	private void OnEnable()
	{
		if (!_ghost && !Live.Contains(this))
		{
			Live.Add(this);
		}
	}

	private void OnDisable()
	{
		Live.Remove(this);
	}

	private void Start()
	{
		if (!_ghost)
		{
			Apply();
		}
	}

	private void Update()
	{
		if (!_ghost && !(Time.time < _nextCheck))
		{
			_nextCheck = Time.time + 1f;
			Apply();
		}
	}

	private void Apply()
	{
		try
		{
			float num = ((StaminaRunePlugin.Glow != null) ? StaminaRunePlugin.Glow.Value : 1.4f);
			if (num != _appliedGlow && SetIntensityMethod != null && ProjectorType != null)
			{
				if ((Object)(object)_projector == (Object)null)
				{
					_projector = ((Component)this).GetComponent(ProjectorType);
				}
				if ((Object)(object)_projector != (Object)null)
				{
					SetIntensityMethod.Invoke(_projector, new object[1] { num });
					_appliedGlow = num;
				}
			}
		}
		catch (Exception ex)
		{
			Exception ex2 = ((ex.InnerException != null) ? ex.InnerException : ex);
			StaminaRunePlugin.Log.LogWarning((object)("Stamina Rune update failed: " + ex2.GetType().Name + ": " + ex2.Message));
			_nextCheck = Time.time + 30f;
		}
	}
}
internal static class Boost
{
	private const float CheckSeconds = 0.25f;

	private static SE_Stats _template;

	private static int _hash;

	private static float _nextCheck;

	private static bool _inside;

	private static Player _player;

	internal static bool Inside => _inside;

	internal static void CreateEffect(Sprite icon)
	{
		SE_Stats val = ScriptableObject.CreateInstance<SE_Stats>();
		((Object)val).name = "SE_danpe_StaminaRune";
		((StatusEffect)val).m_name = "Stamina Rune";
		((StatusEffect)val).m_tooltip = "The rune's power runs through you: stamina comes back fast.";
		((StatusEffect)val).m_icon = icon;
		((StatusEffect)val).m_ttl = 0f;
		val.m_staminaRegenMultiplier = StaminaRunePlugin.RegenMultiplier.Value;
		Object.DontDestroyOnLoad((Object)(object)val);
		_template = val;
		_hash = ((StatusEffect)val).NameHash();
	}

	internal static void Register(ObjectDB db)
	{
		if ((Object)(object)_template != (Object)null && (Object)(object)db != (Object)null && db.m_StatusEffects != null && (Object)(object)db.GetStatusEffect(_hash) == (Object)null)
		{
			db.m_StatusEffects.Add((StatusEffect)(object)_template);
		}
	}

	internal static void Tick(Player player)
	{
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		float time = Time.time;
		if (time < _nextCheck)
		{
			return;
		}
		_nextCheck = time + 0.25f;
		if ((Object)(object)_player != (Object)null && !object.ReferenceEquals(_player, player))
		{
			Release();
		}
		bool flag = !((Character)player).IsDead() && !((Character)player).InInterior() && StaminaRuneController.Live.Count > 0 && Near(((Component)player).transform.position);
		SEMan sEMan = ((Character)player).GetSEMan();
		if (sEMan == null || (Object)(object)_template == (Object)null)
		{
			_inside = false;
			return;
		}
		if (flag)
		{
			float value = StaminaRunePlugin.RegenMultiplier.Value;
			_template.m_staminaRegenMultiplier = value;
			StatusEffect statusEffect = sEMan.GetStatusEffect(_hash);
			SE_Stats val = (SE_Stats)(object)((statusEffect is SE_Stats) ? statusEffect : null);
			if ((Object)(object)val == (Object)null)
			{
				sEMan.AddStatusEffect((StatusEffect)(object)_template, false, 0, 0f, (short)(-1));
			}
			else if (val.m_staminaRegenMultiplier != value)
			{
				val.m_staminaRegenMultiplier = value;
			}
			_player = player;
		}
		else if (sEMan.HaveStatusEffect(_hash))
		{
			sEMan.RemoveStatusEffect(_hash, true);
			_player = null;
		}
		_inside = flag;
	}

	private static bool Near(Vector3 pos)
	{
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		float value = StaminaRunePlugin.Radius.Value;
		List<StaminaRuneController> live = StaminaRuneController.Live;
		for (int num = live.Count - 1; num >= 0; num--)
		{
			StaminaRuneController staminaRuneController = live[num];
			if ((Object)(object)staminaRuneController == (Object)null)
			{
				live.RemoveAt(num);
			}
			else
			{
				Vector3 position = ((Component)staminaRuneController).transform.position;
				if (Mathf.Abs(position.y - pos.y) <= value && Utils.DistanceXZ(position, pos) <= value)
				{
					return true;
				}
			}
		}
		return false;
	}

	internal static void Release()
	{
		try
		{
			if ((Object)(object)_player != (Object)null)
			{
				SEMan sEMan = ((Character)_player).GetSEMan();
				if (sEMan != null && sEMan.HaveStatusEffect(_hash))
				{
					sEMan.RemoveStatusEffect(_hash, true);
				}
			}
		}
		catch (Exception)
		{
		}
		_player = null;
		_inside = false;
	}
}
public static class Patches
{
	internal static Piece OrigPiece;

	internal static Func<Player, Piece, bool> IsUnlockedOriginal;

	private static bool _failed;

	private static bool IsOurPiece(Piece piece)
	{
		if ((Object)(object)piece == (Object)null)
		{
			return false;
		}
		string name = ((Object)((Component)piece).gameObject).name;
		if (!(name == "runemagic_StaminaRune"))
		{
			return name == "runemagic_StaminaRune(Clone)";
		}
		return true;
	}

	public static void IsUnlockablePostfix(Piece piece, ref bool __result)
	{
		if (!__result && IsOurPiece(piece))
		{
			__result = true;
		}
	}

	public static void IsUnlockedPostfix(Player player, Piece piece, ref bool __result)
	{
		if (IsOurPiece(piece) && (Object)(object)OrigPiece != (Object)null && IsUnlockedOriginal != null)
		{
			__result = IsUnlockedOriginal(player, OrigPiece);
		}
	}

	public static void EnergyCostPostfix(Piece piece, ref float __result)
	{
		if (IsOurPiece(piece) && StaminaRunePlugin.EnergyCost != null && StaminaRunePlugin.EnergyCost.Value > 0f)
		{
			__result = StaminaRunePlugin.EnergyCost.Value;
		}
	}

	public static void ObjectDBPostfix(ObjectDB __instance)
	{
		try
		{
			Boost.Register(__instance);
		}
		catch (Exception ex)
		{
			StaminaRunePlugin.Log.LogWarning((object)("Could not list the Stamina Rune effect in the item database: " + ex.Message));
		}
	}

	public static void UpdateStatsPrefix(Player __instance, ref float ___m_staminaRegenTimer)
	{
		if (_failed || (Object)(object)__instance == (Object)null || !object.ReferenceEquals(__instance, Player.m_localPlayer))
		{
			return;
		}
		try
		{
			Boost.Tick(__instance);
			if (Boost.Inside && StaminaRunePlugin.RegenWhileUsing.Value && ___m_staminaRegenTimer > 0f)
			{
				___m_staminaRegenTimer = 0f;
			}
		}
		catch (Exception ex)
		{
			_failed = true;
			Boost.Release();
			StaminaRunePlugin.Log.LogError((object)("Stamina Rune disabled for this session after an error: " + ex));
		}
	}
}
internal static class Glyph
{
	private delegate float Distance(float px, float py);

	private const int Size = 512;

	private const float Centre = 255.5f;

	private const float HalfLine = 2.4f;

	internal static Texture2D Build()
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Expected O, but got Unknown
		byte[] array = Alpha();
		Color32[] array2 = (Color32[])(object)new Color32[262144];
		for (int i = 0; i < array2.Length; i++)
		{
			ref Color32 reference = ref array2[i];
			reference = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, array[i]);
		}
		Texture2D val = new Texture2D(512, 512, (TextureFormat)4, true);
		((Object)val).name = "StaminaRuneGlyph";
		((Texture)val).wrapMode = (TextureWrapMode)1;
		((Texture)val).filterMode = (FilterMode)2;
		val.SetPixels32(array2);
		val.Apply(true, false);
		return val;
	}

	internal static byte[] Alpha()
	{
		List<float[]> list = new List<float[]>();
		List<float[]> list2 = new List<float[]>();
		float[] array = new float[14]
		{
			38f, 128f, -48f, -2f, 2f, -2f, -32f, -128f, 54f, 18f,
			6f, 18f, 38f, 128f
		};
		for (int i = 0; i + 3 < array.Length; i += 2)
		{
			list.Add(new float[4]
			{
				array[i],
				array[i + 1],
				array[i + 2],
				array[i + 3]
			});
		}
		list2.Add(new float[3] { 0f, 0f, 165f });
		for (int j = 0; j < 4; j++)
		{
			float num = (float)j * (float)Math.PI / 2f;
			float num2 = Mathf.Cos(num);
			float num3 = Mathf.Sin(num);
			list.Add(new float[4]
			{
				num2 * 175f,
				num3 * 175f,
				num2 * 200f,
				num3 * 200f
			});
			list2.Add(new float[3]
			{
				num2 * 209f,
				num3 * 209f,
				9f
			});
		}
		float[] array2 = new float[262144];
		for (int k = 0; k < array2.Length; k++)
		{
			array2[k] = float.MaxValue;
		}
		float num4 = 4.4f;
		foreach (float[] item in list)
		{
			float[] g = item;
			Stamp(array2, Mathf.Min(g[0], g[2]) - num4, Mathf.Min(g[1], g[3]) - num4, Mathf.Max(g[0], g[2]) + num4, Mathf.Max(g[1], g[3]) + num4, (float px, float py) => DistanceToSegment(px, py, g));
		}
		foreach (float[] item2 in list2)
		{
			float[] c = item2;
			Stamp(array2, c[0] - c[2] - num4, c[1] - c[2] - num4, c[0] + c[2] + num4, c[1] + c[2] + num4, delegate(float px, float py)
			{
				float num7 = px - c[0];
				float num8 = py - c[1];
				return Mathf.Abs(Mathf.Sqrt(num7 * num7 + num8 * num8) - c[2]);
			});
		}
		byte[] array3 = new byte[262144];
		for (int num5 = 0; num5 < array3.Length; num5++)
		{
			float num6 = Mathf.Clamp01(2.9f - array2[num5]);
			array3[num5] = (byte)Mathf.RoundToInt(num6 * 255f);
		}
		return array3;
	}

	private static void Stamp(float[] best, float x0, float y0, float x1, float y1, Distance distance)
	{
		int num = Mathf.Max(0, Mathf.FloorToInt(x0 + 255.5f));
		int num2 = Mathf.Max(0, Mathf.FloorToInt(y0 + 255.5f));
		int num3 = Mathf.Min(511, Mathf.CeilToInt(x1 + 255.5f));
		int num4 = Mathf.Min(511, Mathf.CeilToInt(y1 + 255.5f));
		for (int i = num2; i <= num4; i++)
		{
			float py = (float)i - 255.5f;
			for (int j = num; j <= num3; j++)
			{
				float num5 = distance((float)j - 255.5f, py);
				int num6 = i * 512 + j;
				if (num5 < best[num6])
				{
					best[num6] = num5;
				}
			}
		}
	}

	private static float DistanceToSegment(float px, float py, float[] s)
	{
		float num = s[2] - s[0];
		float num2 = s[3] - s[1];
		float num3 = px - s[0];
		float num4 = py - s[1];
		float num5 = num * num + num2 * num2;
		float num6 = ((num5 > 0f) ? Mathf.Clamp01((num3 * num + num4 * num2) / num5) : 0f);
		float num7 = num3 - num6 * num;
		float num8 = num4 - num6 * num2;
		return Mathf.Sqrt(num7 * num7 + num8 * num8);
	}
}

plugins/FishingRune.dll

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

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

[BepInPlugin("danpe.RuneMagicFishingRune", "Rune Magic - Fishing Rune", "1.2.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class FishingRunePlugin : BaseUnityPlugin
{
	public const string PluginGuid = "danpe.RuneMagicFishingRune";

	public const string PluginName = "Rune Magic - Fishing Rune";

	public const string PluginVersion = "1.2.0";

	internal const string RuneMagicGuid = "hyleanlegend.RuneMagic";

	internal const string OrigName = "runemagic_CanopyRune";

	internal const string RuneName = "runemagic_FishingRune";

	private const string RuneFocusItemName = "$item_runemagic_runefocus";

	private const int TestedMajor = 1;

	private const int TestedMinor = 5;

	internal const string SpeciesNames = "Fish1 Perch, Fish2 Pike, Fish3 Tuna, Fish4_cave Tetra, Fish5 Trollfish, Fish6 Giant herring, Fish7 Grouper, Fish8 Coral cod, Fish9 Anglerfish, Fish10 Northern salmon, Fish11 Magmafish, Fish12 Pufferfish.";

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<float> Radius;

	internal static ConfigEntry<int> FishKept;

	internal static ConfigEntry<float> Interval;

	internal static ConfigEntry<bool> Splash;

	internal static ConfigEntry<float> EnergyCost;

	internal static ConfigEntry<float> BiomeEnergyCost;

	internal static ConfigEntry<float> Glow;

	internal static ConfigEntry<bool> AllowUntestedVersion;

	internal static readonly List<RuneVariant> Variants = new List<RuneVariant>();

	private static readonly Dictionary<string, RuneVariant> ByName = new Dictionary<string, RuneVariant>();

	private static Harmony _harmony;

	private static GameObject _container;

	private static PieceTable _table;

	private static List<GameObject> _registeredPrefabs;

	private void Awake()
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Expected O, but got Unknown
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Expected O, but got Unknown
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Expected O, but got Unknown
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Expected O, but got Unknown
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Expected O, but got Unknown
		//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01af: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When false the plugin does nothing at all (restart required). Multiplayer: install this add-on on the host (or dedicated server) AND on every client - a server without it permanently deletes engraved Fishing Runes when their area loads (unknown prefab), and while a player without it owns a rune, that rune releases nothing. Fish are released by whichever machine owns the rune (the first player whose loaded area took it in, until that player leaves), using that machine's settings, so keep them the same for everyone.");
		Radius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Radius", 20f, new ConfigDescription("Radius in metres around an engraved rune. New fish are released only in water inside this circle that is deep enough for them (about 1.7 m for most kinds, 4.2 m for Tuna); a fish then roams 10-20 m around the spot it was released.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(6f, 48f), new object[0]));
		FishKept = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Fish kept", 6, new ConfigDescription("A rune releases fish while fewer than this many of its own kinds live within its radius: fish swimming inside it, and fish whose home spot is inside it even while they roam a little outside. Fish that were already there count too. A biome rune, or any rune with a Species list, counts only the kinds it releases, so runes for different biomes side by side each keep their own stock (a kind on both lists counts for both - Perch and Pike for the Meadows, Black Forest and Plains runes, Pufferfish for the Ocean and Mistlands runes). The Fishing Rune without a Species list releases whatever lives there, so it counts every fish.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), new object[0]));
		Interval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Seconds between fish", 20f, new ConfigDescription("Wait between two released fish. While the water is fully stocked the wait keeps restarting, so a caught fish is replaced this long after it was taken.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 600f), new object[0]));
		Splash = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Splash", true, "Show a splash where a fish is released and make the glyph flare for a moment. Applied per client.");
		EnergyCost = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Energy cost", 100f, new ConfigDescription("Runic energy needed to engrave the Fishing Rune. 0 = same as the Canopy Rune (energyCost_runemagic_CanopyRune, 70 by default).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f), new object[0]));
		BiomeEnergyCost = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Energy cost (biome runes)", 150f, new ConfigDescription("Runic energy needed to engrave one of the biome Fishing Runes. 0 = same as the Canopy Rune.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f), new object[0]));
		Glow = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Glow", 1.4f, new ConfigDescription("Brightness of the engraved glyphs.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), new object[0]));
		AllowUntestedVersion = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Allow untested Rune Magic version", false, "This add-on was verified against Rune Magic 1.5.x. With any other version it stays off unless this is true.");
		AddVariant((Biome)0, "", "", -1, "");
		AddVariant((Biome)1, "Meadows", "Meadows", 0, "Perch, Pike");
		AddVariant((Biome)8, "BlackForest", "Black Forest", 1, "Perch, Pike, Trollfish");
		AddVariant((Biome)2, "Swamp", "Swamp", 2, "Giant herring");
		AddVariant((Biome)4, "Mountain", "Mountain", 3, "Tetra");
		AddVariant((Biome)16, "Plains", "Plains", 4, "Perch, Pike, Grouper");
		AddVariant((Biome)256, "Ocean", "Ocean", 5, "Tuna, Coral cod, Pufferfish");
		AddVariant((Biome)512, "Mistlands", "Mistlands", 6, "Anglerfish, Pufferfish");
		AddVariant((Biome)32, "AshLands", "Ashlands", 7, "Magmafish");
		AddVariant((Biome)64, "DeepNorth", "Deep North", 8, "Northern salmon");
		if (!Enabled.Value)
		{
			Log.LogWarning((object)"Fishing Runes are OFF on this game instance. If this instance is the host or server, any placed Fishing Runes are permanently deleted when their area loads.");
			return;
		}
		try
		{
			Setup();
			Log.LogInfo((object)("Fishing Runes registered (" + Variants.Count + " runes). Multiplayer: the host/server and every client need this add-on."));
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Setup failed - the Fishing Runes will not be available. Nothing else is affected. " + ex));
			Teardown();
			Log.LogWarning((object)"If this instance is the host or server, any placed Fishing Runes are permanently deleted when their area loads.");
		}
	}

	private void AddVariant(Biome biome, string key, string label, int emblem, string fish)
	{
		//IL_0017: 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_002d: 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)
		//IL_0069: 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_009f: Invalid comparison between Unknown and I4
		RuneVariant runeVariant = new RuneVariant();
		runeVariant.Index = Variants.Count;
		runeVariant.Biome = biome;
		runeVariant.Label = label;
		runeVariant.Emblem = emblem;
		runeVariant.PrefabName = (((int)biome == 0) ? "runemagic_FishingRune" : ("runemagic_FishingRune_" + key));
		runeVariant.DisplayName = (((int)biome == 0) ? "Fishing Rune" : (label + " Fishing Rune"));
		string displayName = runeVariant.DisplayName;
		if ((int)biome == 0)
		{
			runeVariant.Species = ((BaseUnityPlugin)this).Config.Bind<string>(displayName, "Species", "", "Leave empty for the fish that naturally live in that water: the kinds the game itself would spawn at that spot (same biome and depth rules), else the kinds of the biome the rune stands in, else Perch. Or give a comma-separated list of fish prefabs to release instead, e.g. 'Fish1, Fish2'. Fish1 Perch, Fish2 Pike, Fish3 Tuna, Fish4_cave Tetra, Fish5 Trollfish, Fish6 Giant herring, Fish7 Grouper, Fish8 Coral cod, Fish9 Anglerfish, Fish10 Northern salmon, Fish11 Magmafish, Fish12 Pufferfish.");
			runeVariant.Description = "Engrave on a standing stone by the water. The rune keeps the water within its reach stocked: whenever fewer fish swim there than it should hold, it calls up a new one of a kind that lives in these waters.";
		}
		else if ((int)biome == 4)
		{
			runeVariant.Species = ((BaseUnityPlugin)this).Config.Bind<string>(displayName, "Species", "", "Leave empty for the Mountain's fish: the Tetra of its frost caves (the game spawns no fish in open Mountain water; if a mod adds Mountain fish to the spawn lists, those are used instead). Or give a comma-separated list of fish prefabs, e.g. 'Fish4_cave'. Fish1 Perch, Fish2 Pike, Fish3 Tuna, Fish4_cave Tetra, Fish5 Trollfish, Fish6 Giant herring, Fish7 Grouper, Fish8 Coral cod, Fish9 Anglerfish, Fish10 Northern salmon, Fish11 Magmafish, Fish12 Pufferfish.");
			runeVariant.Description = "Engrave on a standing stone by the water. Wherever it is carved, it keeps the water within its reach stocked with the Tetra of the Mountain's frost caves.";
		}
		else
		{
			runeVariant.Species = ((BaseUnityPlugin)this).Config.Bind<string>(displayName, "Species", "", "Leave empty for every fish the game spawns in the " + label + " (" + fish + "; fish that mods add to the " + label + " spawn list come along). Each kind is released only where the water is deep enough for it. Or give a comma-separated list of fish prefabs to release instead, e.g. just one kind. Fish1 Perch, Fish2 Pike, Fish3 Tuna, Fish4_cave Tetra, Fish5 Trollfish, Fish6 Giant herring, Fish7 Grouper, Fish8 Coral cod, Fish9 Anglerfish, Fish10 Northern salmon, Fish11 Magmafish, Fish12 Pufferfish.");
			runeVariant.Description = "Engrave on a standing stone by the water. Wherever it is carved, it keeps the water within its reach stocked with the fish of the " + label + ": " + fish + ".";
		}
		runeVariant.InMenu = ((BaseUnityPlugin)this).Config.Bind<bool>(displayName, "In build menu", true, "Show this rune in the Rune Focus menu. Hiding it keeps runes already engraved working. Applies after a restart.");
		Variants.Add(runeVariant);
		ByName[runeVariant.PrefabName] = runeVariant;
		ByName[runeVariant.PrefabName + "(Clone)"] = runeVariant;
	}

	internal static RuneVariant VariantOf(Piece piece)
	{
		if (!((Object)(object)piece != (Object)null) || !ByName.TryGetValue(((Object)((Component)piece).gameObject).name, out var value))
		{
			return null;
		}
		return value;
	}

	internal static RuneVariant VariantAt(int index)
	{
		if (index < 0 || index >= Variants.Count)
		{
			return null;
		}
		return Variants[index];
	}

	private void OnDestroy()
	{
		Teardown();
	}

	private static void Teardown()
	{
		try
		{
			foreach (RuneVariant variant in Variants)
			{
				if (!((Object)(object)variant.Clone == (Object)null))
				{
					if ((Object)(object)_table != (Object)null)
					{
						_table.m_pieces.Remove(variant.Clone);
					}
					if (_registeredPrefabs != null)
					{
						_registeredPrefabs.Remove(variant.Clone);
					}
					variant.Clone = null;
				}
			}
			if ((Object)(object)_container != (Object)null)
			{
				Object.Destroy((Object)(object)_container);
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Unregister failed: " + ex.Message));
		}
		_container = null;
		_table = null;
		if (_harmony != null)
		{
			List<MethodBase> list;
			try
			{
				list = new List<MethodBase>(_harmony.GetPatchedMethods());
			}
			catch (Exception)
			{
				list = new List<MethodBase>();
			}
			foreach (MethodBase item in list)
			{
				try
				{
					_harmony.Unpatch(item, (HarmonyPatchType)0, "danpe.RuneMagicFishingRune");
				}
				catch (Exception ex3)
				{
					Log.LogWarning((object)("Unpatch failed for " + item.Name + ": " + ex3.Message));
				}
			}
		}
		Patches.OrigPiece = null;
	}

	private static void CheckRuneMagicVersion()
	{
		if (!Chainloader.PluginInfos.TryGetValue("hyleanlegend.RuneMagic", out var value) || value == null)
		{
			throw new InvalidOperationException("Rune Magic is not loaded");
		}
		Version version = value.Metadata.Version;
		if (version.Major != 1 || version.Minor != 5)
		{
			if (!AllowUntestedVersion.Value)
			{
				throw new InvalidOperationException(string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x). Set 'Allow untested Rune Magic version' to true to try anyway."));
			}
			Log.LogWarning((object)string.Concat("Rune Magic ", version, " is untested with this add-on (verified with 1.5.x); continuing because the config allows it."));
		}
	}

	private static Type RequireType(string name)
	{
		Type type = AccessTools.TypeByName(name);
		if (type == null)
		{
			throw new InvalidOperationException("Rune Magic type not found: " + name);
		}
		return type;
	}

	private static MethodInfo RequireMethod(Type t, string name, Type[] args)
	{
		MethodInfo methodInfo = ((args == null) ? AccessTools.Method(t, name, (Type[])null, (Type[])null) : AccessTools.Method(t, name, args, (Type[])null));
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Method not found: " + t.FullName + "." + name);
		}
		return methodInfo;
	}

	private static FieldInfo RequireField(Type t, string name)
	{
		FieldInfo fieldInfo = AccessTools.Field(t, name);
		if (fieldInfo == null)
		{
			throw new InvalidOperationException("Field not found: " + t.FullName + "." + name);
		}
		return fieldInfo;
	}

	private static HarmonyMethod H(string name)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(typeof(Patches), name, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Patch method missing: " + name);
		}
		return new HarmonyMethod(methodInfo);
	}

	private static void Setup()
	{
		//IL_03ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f9: Expected O, but got Unknown
		//IL_044f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0459: Expected O, but got Unknown
		//IL_059b: Unknown result type (might be due to invalid IL or missing references)
		//IL_05aa: Unknown result type (might be due to invalid IL or missing references)
		CheckRuneMagicVersion();
		Type t = RequireType("ValheimMod.ValheimMod");
		MethodInfo methodInfo = RequireMethod(t, "get_isModAwake", Type.EmptyTypes);
		if (!(bool)methodInfo.Invoke(null, null))
		{
			throw new InvalidOperationException("Rune Magic did not finish initialising (isModAwake is false)");
		}
		Type type = RequireType("ValheimMod.Monobehaviours.CanopyRune");
		Type type2 = RequireType("ValheimMod.Monobehaviours.RuneProjector");
		Type t2 = RequireType("ValheimMod.UnlockManager");
		Type type3 = RequireType("ValheimMod.RunemagicPieceConfig");
		Type t3 = RequireType("ValheimMod.CustomContentSetupHandler");
		MethodInfo methodInfo2 = RequireMethod(t2, "isUnlockable", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo3 = RequireMethod(t2, "isUnlocked", new Type[2]
		{
			typeof(Player),
			typeof(Piece)
		});
		MethodInfo methodInfo4 = RequireMethod(type3, "getEnergyCost", new Type[1] { typeof(Piece) });
		MethodInfo methodInfo5 = RequireMethod(t3, "RegisterPrefab", new Type[1] { typeof(GameObject) });
		FieldInfo fieldInfo = RequireField(type2, "runeTexture");
		FishingRuneController.SetIntensityMethod = RequireMethod(type2, "setIntensity", new Type[1] { typeof(float) });
		FishingRuneController.ProjectorType = type2;
		ConstructorInfo constructor = type3.GetConstructor(new Type[3]
		{
			typeof(Biome),
			typeof(string),
			typeof(string)
		});
		if (constructor == null)
		{
			throw new InvalidOperationException("RunemagicPieceConfig(Biome, string, string) constructor not found");
		}
		List<GameObject> list = RequireField(t3, "RegisteredItemPrefabs").GetValue(null) as List<GameObject>;
		List<GameObject> list2 = RequireField(t3, "RegisteredNonItemPrefabs").GetValue(null) as List<GameObject>;
		if (list == null || list2 == null)
		{
			throw new InvalidOperationException("Rune Magic's prefab lists have an unexpected type");
		}
		Patches.IsUnlockedOriginal = (Func<Player, Piece, bool>)Delegate.CreateDelegate(typeof(Func<Player, Piece, bool>), methodInfo3);
		PieceTable val = null;
		foreach (GameObject item in list)
		{
			ItemDrop val2 = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null && val2.m_itemData.m_shared.m_name == "$item_runemagic_runefocus")
			{
				val = val2.m_itemData.m_shared.m_buildPieces;
				break;
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			throw new InvalidOperationException("Rune Focus piece table not found");
		}
		GameObject val3 = null;
		List<GameObject> list3 = new List<GameObject>();
		foreach (GameObject piece in val.m_pieces)
		{
			if ((Object)(object)piece != (Object)null && ByName.ContainsKey(((Object)piece).name))
			{
				list3.Add(piece);
			}
			else if ((Object)(object)piece != (Object)null && ((Object)piece).name == "runemagic_CanopyRune")
			{
				val3 = piece;
			}
		}
		foreach (GameObject item2 in list3)
		{
			Log.LogInfo((object)"Replacing a stale Fishing Rune entry.");
			val.m_pieces.Remove(item2);
			list2.Remove(item2);
		}
		if ((Object)(object)val3 == (Object)null || (Object)(object)val3.GetComponent<Piece>() == (Object)null || (Object)(object)val3.GetComponent(type) == (Object)null)
		{
			throw new InvalidOperationException("Canopy Rune prefab not found in the Rune Focus piece table");
		}
		if ((Object)(object)val3.GetComponent<ZNetView>() == (Object)null)
		{
			throw new InvalidOperationException("The Canopy Rune prefab has no ZNetView on its root");
		}
		Patches.OrigPiece = val3.GetComponent<Piece>();
		_harmony = new Harmony("danpe.RuneMagicFishingRune");
		_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, H("IsUnlockablePostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, H("IsUnlockedPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, H("EnergyCostPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_container = new GameObject("RuneMagicFishingRune_Prefabs");
		_container.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)_container);
		_table = val;
		_registeredPrefabs = list2;
		int num = val.m_pieces.IndexOf(val3) + 1;
		foreach (RuneVariant variant in Variants)
		{
			GameObject val4 = Object.Instantiate<GameObject>(val3, _container.transform);
			((Object)val4).name = variant.PrefabName;
			Component component = val4.GetComponent(type);
			if ((Object)(object)component != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component);
			}
			Demister component2 = val4.GetComponent<Demister>();
			if ((Object)(object)component2 != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component2);
			}
			ParticleSystemForceField component3 = val4.GetComponent<ParticleSystemForceField>();
			if ((Object)(object)component3 != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component3);
			}
			if ((Object)(object)val4.GetComponent(type) != (Object)null)
			{
				throw new InvalidOperationException("Could not remove the CanopyRune component from the clone");
			}
			FishingRuneController fishingRuneController = val4.AddComponent<FishingRuneController>();
			fishingRuneController.Variant = variant.Index;
			Texture2D val5 = Glyph.Build(variant.Emblem);
			Piece component4 = val4.GetComponent<Piece>();
			component4.m_name = variant.DisplayName;
			component4.m_description = variant.Description;
			component4.m_icon = Sprite.Create(val5, new Rect(0f, 0f, (float)((Texture)val5).width, (float)((Texture)val5).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
			Component component5 = val4.GetComponent(type2);
			if ((Object)(object)component5 != (Object)null)
			{
				fieldInfo.SetValue(component5, val5);
			}
			variant.Clone = val4;
			constructor.Invoke(new object[3]
			{
				(object)(Biome)8,
				variant.PrefabName,
				"runemagic_CanopyRune"
			});
			methodInfo5.Invoke(null, new object[1] { val4 });
			if (variant.InMenu.Value)
			{
				val.m_pieces.Insert(num++, val4);
			}
		}
	}
}
internal class RuneVariant
{
	public int Index;

	public Biome Biome;

	public string Label;

	public int Emblem;

	public string PrefabName;

	public string DisplayName;

	public string Description;

	public ConfigEntry<string> Species;

	public ConfigEntry<bool> InMenu;

	public GameObject Clone;

	public string ForcedKey;

	public ZNetScene ForcedScene;

	public List<FishKind> ForcedKinds;

	public string WarnedNames;

	public HashSet<int> Counted;

	public List<FishKind> CountedFrom;
}
public class FishingRuneController : MonoBehaviour
{
	internal const string ReleaseRpc = "danpe_FishingRune_Release";

	internal const float HomeMargin = 1f;

	private const float CheckSeconds = 2f;

	private const float SettleSeconds = 5f;

	internal static MethodInfo SetIntensityMethod;

	internal static Type ProjectorType;

	private static readonly int LastReleaseKey = StringExtensionMethods.GetStableHashCode("danpe_FishingRune_lastRelease");

	public int Variant;

	private ZNetView _nview;

	private Component _projector;

	private float _appliedGlow = -1f;

	private float _nextGlowCheck;

	private float _flareUntil;

	private float _nextCheck;

	private float _nextRelease;

	private float _ownedSince = -1f;

	private bool _ghost;

	private bool _registered;

	private bool _loggedFirst;

	private bool _warnedNoWater;

	private bool _warnedNoFish;

	private void Awake()
	{
		_ghost = ZNetView.m_forceDisableInit;
		_nview = ((Component)this).GetComponent<ZNetView>();
		RegisterRpc();
	}

	private void Start()
	{
		if (!_ghost)
		{
			RegisterRpc();
			_nextCheck = Time.time + Random.Range(0.5f, 2f);
			ApplyGlow(force: false);
		}
	}

	private void Update()
	{
		if (_ghost)
		{
			return;
		}
		float time = Time.time;
		if (_flareUntil > 0f && time >= _flareUntil)
		{
			_flareUntil = 0f;
			ApplyGlow(force: true);
		}
		else if (_flareUntil <= 0f && time >= _nextGlowCheck)
		{
			_nextGlowCheck = time + 1f;
			ApplyGlow(force: false);
		}
		if (time < _nextCheck)
		{
			return;
		}
		_nextCheck = time + 2f;
		try
		{
			Tick(time);
		}
		catch (Exception ex)
		{
			Exception ex2 = ((ex.InnerException != null) ? ex.InnerException : ex);
			FishingRunePlugin.Log.LogWarning((object)("Fishing Rune update failed (retrying in 30 s): " + ex2));
			_nextCheck = time + 30f;
		}
	}

	private void Tick(float now)
	{
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0146: 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)
		//IL_040a: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner())
		{
			_ownedSince = -1f;
			return;
		}
		RuneVariant runeVariant = FishingRunePlugin.VariantAt(Variant);
		ZNetScene instance = ZNetScene.instance;
		if (runeVariant == null || (Object)(object)instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null || SpawnSystem.m_nospawn)
		{
			return;
		}
		Vector3 position = ((Component)this).transform.position;
		if (instance.OutsideActiveArea(position))
		{
			_ownedSince = -1f;
			return;
		}
		float value = FishingRunePlugin.Interval.Value;
		if (_ownedSince < 0f)
		{
			_ownedSince = now;
			float num = Mathf.Min(value, 5f);
			long num2 = _nview.GetZDO().GetLong(LastReleaseKey, 0L);
			if (num2 > 0 && (Object)(object)ZNet.instance != (Object)null)
			{
				float num3 = (float)((double)(ZNet.instance.GetTime().Ticks - num2) / 10000000.0);
				num = Mathf.Clamp(value - num3, num, value);
			}
			_nextRelease = Mathf.Max(_nextRelease, now + num);
		}
		if (now - _ownedSince < 5f)
		{
			return;
		}
		float value2 = FishingRunePlugin.Radius.Value;
		int num4 = Stock.CountFish(position, value2 + 1f, ZoneSystem.instance.m_waterLevel, Stock.CountedKinds(instance, runeVariant));
		if (num4 >= FishingRunePlugin.FishKept.Value)
		{
			_nextRelease = Mathf.Max(_nextRelease, now + value);
		}
		else
		{
			if (now < _nextRelease)
			{
				return;
			}
			if (!Stock.TryRelease(position, value2, runeVariant, out var released, out var noFish))
			{
				_nextRelease = now + Mathf.Max(value, 15f);
				if (noFish && !_warnedNoFish)
				{
					_warnedNoFish = true;
					FishingRunePlugin.Log.LogWarning((object)("The " + runeVariant.DisplayName + " has no fish to release: the game's spawn lists have none for that biome and its Species setting names none. Set Species in the [" + runeVariant.DisplayName + "] config section."));
				}
				else if (!noFish && !_warnedNoWater)
				{
					_warnedNoWater = true;
					FishingRunePlugin.Log.LogWarning((object)("A " + runeVariant.DisplayName + " at " + Mathf.RoundToInt(position.x) + ", " + Mathf.RoundToInt(position.z) + " found no open water deep enough for its fish (about 1.7 m for most kinds, 4.2 m for Tuna) within its " + Mathf.RoundToInt(value2) + " m radius, at least not in the part of it this machine has loaded. Engrave one closer to deeper water, or raise the Radius."));
				}
				return;
			}
			_warnedNoWater = false;
			_warnedNoFish = false;
			_nextRelease = now + value;
			if ((Object)(object)ZNet.instance != (Object)null)
			{
				_nview.GetZDO().Set(LastReleaseKey, ZNet.instance.GetTime().Ticks);
			}
			if (!_loggedFirst)
			{
				_loggedFirst = true;
				FishingRunePlugin.Log.LogInfo((object)("A " + runeVariant.DisplayName + " at " + Mathf.RoundToInt(position.x) + ", " + Mathf.RoundToInt(position.z) + " released " + released.Name + " (quality " + released.Quality + "); " + num4 + " fish were in reach, it keeps " + FishingRunePlugin.FishKept.Value + "."));
			}
			_nview.InvokeRPC(ZNetView.Everybody, "danpe_FishingRune_Release", new object[2] { released.Surface, released.PrefabHash });
		}
	}

	private void RegisterRpc()
	{
		if (!_ghost && !_registered && (Object)(object)_nview != (Object)null && _nview.IsValid())
		{
			_nview.Register<Vector3, int>("danpe_FishingRune_Release", (Action<long, Vector3, int>)RPC_Release);
			_registered = true;
		}
	}

	private void RPC_Release(long sender, Vector3 surface, int prefabHash)
	{
		//IL_0057: 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_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (FishingRunePlugin.Splash.Value)
			{
				GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(prefabHash) : null);
				Fish val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Fish>() : null);
				if ((Object)(object)val2 != (Object)null && val2.m_jumpEffects != null)
				{
					val2.m_jumpEffects.Create(surface, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
				}
				Flare();
			}
		}
		catch (Exception ex)
		{
			FishingRunePlugin.Log.LogWarning((object)("Fishing Rune splash failed: " + ex.Message));
		}
	}

	private void Flare()
	{
		float value = FishingRunePlugin.Glow.Value;
		if (!(value <= 0f) && SetGlow(Mathf.Min(value * 2f + 0.6f, 4f)))
		{
			_flareUntil = Time.time + 1.2f;
		}
	}

	private void ApplyGlow(bool force)
	{
		float num = ((FishingRunePlugin.Glow != null) ? FishingRunePlugin.Glow.Value : 1.4f);
		if (force || num != _appliedGlow)
		{
			SetGlow(num);
			_appliedGlow = num;
		}
	}

	private bool SetGlow(float value)
	{
		try
		{
			if (SetIntensityMethod == null || ProjectorType == null)
			{
				return false;
			}
			if ((Object)(object)_projector == (Object)null)
			{
				_projector = ((Component)this).GetComponent(ProjectorType);
			}
			if ((Object)(object)_projector == (Object)null)
			{
				return false;
			}
			SetIntensityMethod.Invoke(_projector, new object[1] { value });
			return true;
		}
		catch (Exception ex)
		{
			Exception ex2 = ((ex.InnerException != null) ? ex.InnerException : ex);
			FishingRunePlugin.Log.LogWarning((object)("Fishing Rune glow failed: " + ex2.GetType().Name + ": " + ex2.Message));
			SetIntensityMethod = null;
			return false;
		}
	}
}
internal class FishKind
{
	public GameObject Prefab;

	public Fish Fish;

	public SpawnData Data;

	public float Weight;
}
internal static class Stock
{
	internal struct Released
	{
		public Vector3 Surface;

		public int PrefabHash;

		public string Name;

		public int Quality;
	}

	private const int Attempts = 24;

	private const float WildLevelUpChance = 20f;

	private const float MinWater = 0.7f;

	private const float DepthMargin = 0.2f;

	private const string FallbackPrefab = "Fish1";

	private const string CavePrefab = "Fish4_cave";

	private const float InteriorGap = 100f;

	private const float MaxReleaseDepth = 30f;

	private static readonly FieldInfo SpawnSystemsField = AccessTools.Field(typeof(SpawnSystem), "m_instances");

	private static readonly List<ZDO> Zdos = new List<ZDO>();

	private static readonly Dictionary<int, bool> FishPrefabs = new Dictionary<int, bool>();

	private static List<FishKind> _natural;

	private static float _naturalBuilt;

	private static ZNetScene _naturalScene;

	private static readonly Dictionary<Biome, List<FishKind>> ByBiome = new Dictionary<Biome, List<FishKind>>();

	private static readonly List<FishKind> Native = new List<FishKind>();

	private static readonly List<FishKind> Local = new List<FishKind>();

	private static readonly List<FishKind> Nearby = new List<FishKind>();

	private static readonly List<FishKind> Best = new List<FishKind>();

	internal static int CountFish(Vector3 centre, float r, float water, HashSet<int> kinds)
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: 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_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_018a: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_019e: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
		ZNetScene instance = ZNetScene.instance;
		List<IMonoUpdater> instances = Fish.Instances;
		int num = 0;
		for (int i = 0; i < instances.Count; i++)
		{
			IMonoUpdater obj = instances[i];
			Fish val = (Fish)(object)((obj is Fish) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			Vector3 position = ((Component)val).transform.position;
			if (Mathf.Abs(position.y - water) > 100f || (position.y > water && val.IsOutOfWater()))
			{
				continue;
			}
			ZDO val2 = null;
			if (kinds != null)
			{
				val2 = ZdoOf(val);
				if (val2 == null || !kinds.Contains(val2.GetPrefab()))
				{
					continue;
				}
			}
			if (Within(position, centre, r))
			{
				num++;
				continue;
			}
			if (val2 == null)
			{
				val2 = ZdoOf(val);
			}
			if (val2 != null && Within(val2.GetVec3(ZDOVars.s_spawnPoint, position), centre, r))
			{
				num++;
			}
		}
		if (ZDOMan.instance == null || (Object)(object)instance == (Object)null)
		{
			return num;
		}
		Zdos.Clear();
		ZDOMan.instance.FindSectorObjects(ZoneSystem.GetZone(centre), new SimulationDistance(1, 0, false), Zdos, (List<ZDO>)null);
		for (int j = 0; j < Zdos.Count; j++)
		{
			ZDO val3 = Zdos[j];
			if (val3 == null)
			{
				continue;
			}
			int prefab = val3.GetPrefab();
			if (!((kinds != null) ? (!kinds.Contains(prefab)) : (!IsFishPrefab(instance, prefab))) && !((Object)(object)instance.FindInstance(val3) != (Object)null))
			{
				Vector3 position2 = val3.GetPosition();
				if (!(Mathf.Abs(position2.y - water) > 100f) && !(position2.y > water) && (Within(position2, centre, r) || Within(val3.GetVec3(ZDOVars.s_spawnPoint, position2), centre, r)))
				{
					num++;
				}
			}
		}
		Zdos.Clear();
		return num;
	}

	private static ZDO ZdoOf(Fish f)
	{
		ZNetView component = ((Component)f).GetComponent<ZNetView>();
		if (!((Object)(object)component != (Object)null) || !component.IsValid())
		{
			return null;
		}
		return component.GetZDO();
	}

	internal static HashSet<int> CountedKinds(ZNetScene scene, RuneVariant variant)
	{
		//IL_000c: 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)
		List<FishKind> list = Forced(scene, variant);
		if (list == null && (int)variant.Biome != 0)
		{
			list = BiomeKinds(scene, variant.Biome);
		}
		if (list == null)
		{
			return null;
		}
		if (variant.Counted == null || !object.ReferenceEquals(list, variant.CountedFrom))
		{
			HashSet<int> hashSet = new HashSet<int>();
			foreach (FishKind item in list)
			{
				hashSet.Add(StringExtensionMethods.GetStableHashCode(((Object)item.Prefab).name));
			}
			variant.Counted = hashSet;
			variant.CountedFrom = list;
		}
		return variant.Counted;
	}

	private static bool IsFishPrefab(ZNetScene scene, int hash)
	{
		if (!FishPrefabs.TryGetValue(hash, out var value))
		{
			GameObject prefab = scene.GetPrefab(hash);
			value = (Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent<Fish>() != (Object)null;
			FishPrefabs[hash] = value;
		}
		return value;
	}

	private static bool Within(Vector3 p, Vector3 centre, float r)
	{
		float num = p.x - centre.x;
		float num2 = p.z - centre.z;
		return num * num + num2 * num2 <= r * r;
	}

	internal static bool TryRelease(Vector3 centre, float radius, RuneVariant variant, out Released released, out bool noFish)
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: 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_009c: 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)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		//IL_040d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_016d: Unknown result type (might be due to invalid IL or missing references)
		//IL_025b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0260: Unknown result type (might be due to invalid IL or missing references)
		//IL_0262: Unknown result type (might be due to invalid IL or missing references)
		//IL_0264: Invalid comparison between Unknown and I4
		//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02be: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0271: Unknown result type (might be due to invalid IL or missing references)
		//IL_0276: Unknown result type (might be due to invalid IL or missing references)
		//IL_0278: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_0295: Unknown result type (might be due to invalid IL or missing references)
		//IL_036e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0370: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
		released = default(Released);
		noFish = false;
		ZoneSystem instance = ZoneSystem.instance;
		ZNetScene instance2 = ZNetScene.instance;
		List<FishKind> list = Forced(instance2, variant);
		if (list == null && (int)variant.Biome != 0)
		{
			list = BiomeKinds(instance2, variant.Biome);
		}
		if (list != null && list.Count == 0)
		{
			noFish = true;
			return false;
		}
		List<FishKind> list2 = ((list == null) ? Natural(instance2) : null);
		GameObject val = ((list == null) ? instance2.GetPrefab("Fish1") : null);
		Fish val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Fish>() : null);
		Heightmap val3 = Heightmap.FindHeightmap(centre);
		Biome val4 = (Biome)(((Object)(object)val3 != (Object)null) ? ((int)val3.GetBiome(centre, 0.02f, false)) : 0);
		float waterLevel = instance.m_waterLevel;
		int num = int.MaxValue;
		Vector3 ground = Vector3.zero;
		float depth = 0f;
		Best.Clear();
		Vector3 val7 = default(Vector3);
		Biome val8 = default(Biome);
		BiomeArea val9 = default(BiomeArea);
		Heightmap val10 = default(Heightmap);
		for (int i = 0; i < 24; i++)
		{
			Vector2 val5 = Random.insideUnitCircle * radius;
			Vector3 val6 = new Vector3(centre.x + val5.x, centre.y, centre.z + val5.y);
			if (!instance.IsZoneLoaded(val6) || instance2.OutsideActiveArea(val6))
			{
				continue;
			}
			instance.GetGroundData(ref val6, ref val7, ref val8, ref val9, ref val10);
			if ((Object)(object)val10 == (Object)null)
			{
				continue;
			}
			float num2 = waterLevel - val6.y;
			if (num2 < 0.7f || instance.IsBlocked(val6) || instance.IsLava(val6, true))
			{
				continue;
			}
			if (list != null)
			{
				Native.Clear();
				foreach (FishKind item in list)
				{
					if (num2 >= item.Fish.m_minDepth + 0.2f)
					{
						Native.Add(item);
					}
				}
				if (Native.Count > 0)
				{
					return Spawn(Native, val6, num2, waterLevel, out released);
				}
				continue;
			}
			Native.Clear();
			Local.Clear();
			Nearby.Clear();
			float num3 = val6.y - waterLevel;
			foreach (FishKind item2 in list2)
			{
				if (!(num2 < item2.Fish.m_minDepth + 0.2f))
				{
					SpawnData data = item2.Data;
					bool flag = (data.m_biome & val8) != 0;
					if (flag && (data.m_biomeArea & val9) != 0 && num3 >= data.m_minAltitude && num3 <= data.m_maxAltitude && OceanDepthOk(data, val10, val6) && CentreDistanceOk(data, val6))
					{
						Native.Add(item2);
					}
					else if ((data.m_biome & val4) != 0)
					{
						Local.Add(item2);
					}
					else if (flag)
					{
						Nearby.Add(item2);
					}
				}
			}
			if (Native.Count > 0)
			{
				return Spawn(Native, val6, num2, waterLevel, out released);
			}
			int num4 = ((Local.Count > 0) ? 1 : ((Nearby.Count > 0) ? 2 : (((Object)(object)val2 != (Object)null && num2 >= val2.m_minDepth + 0.2f) ? 3 : int.MaxValue)));
			if (num4 < num)
			{
				num = num4;
				ground = val6;
				depth = num2;
				Best.Clear();
				switch (num4)
				{
				case 1:
					Best.AddRange(Local);
					continue;
				case 2:
					Best.AddRange(Nearby);
					continue;
				}
				FishKind fishKind = new FishKind();
				fishKind.Prefab = val;
				fishKind.Fish = val2;
				fishKind.Data = DataFor(list2, val);
				fishKind.Weight = 1f;
				Best.Add(fishKind);
			}
		}
		if (Best.Count > 0)
		{
			return Spawn(Best, ground, depth, waterLevel, out released);
		}
		return false;
	}

	private static bool OceanDepthOk(SpawnData d, Heightmap map, Vector3 p)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		if (d.m_minOceanDepth == d.m_maxOceanDepth)
		{
			return true;
		}
		float oceanDepth = map.GetOceanDepth(p);
		if (oceanDepth >= d.m_minOceanDepth)
		{
			return oceanDepth <= d.m_maxOceanDepth;
		}
		return false;
	}

	private static bool CentreDistanceOk(SpawnData d, Vector3 p)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		float num = Utils.LengthXZ(p);
		if (d.m_minDistanceFromCenter > 0f && num < d.m_minDistanceFromCenter)
		{
			return false;
		}
		if (!(d.m_maxDistanceFromCenter <= 0f))
		{
			return num <= d.m_maxDistanceFromCenter;
		}
		return true;
	}

	private static bool Spawn(List<FishKind> kinds, Vector3 ground, float depth, float water, out Released released)
	{
		//IL_0086: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		released = default(Released);
		FishKind fishKind = Pick(kinds);
		if (fishKind == null)
		{
			return false;
		}
		Fish fish = fishKind.Fish;
		float num = Mathf.Max(0.5f, fish.m_minDepth);
		float num2 = Mathf.Min(Mathf.Min(fish.m_maxDepth, depth - fish.m_height - 0.1f), 30f);
		float num3 = ((num2 > num) ? Random.Range(num, num2) : Mathf.Min(num, depth * 0.5f));
		Vector3 val = default(Vector3);
		((Vector3)(ref val))..ctor(ground.x, water - num3, ground.z);
		int num4 = RollQuality(fishKind, val);
		GameObject val2 = Object.Instantiate<GameObject>(fishKind.Prefab, val, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f));
		if (num4 > 1)
		{
			ItemDrop component = val2.GetComponent<ItemDrop>();
			if ((Object)(object)component != (Object)null)
			{
				component.SetQuality(num4);
			}
		}
		released.Surface = new Vector3(ground.x, water, ground.z);
		released.PrefabHash = StringExtensionMethods.GetStableHashCode(((Object)fishKind.Prefab).name);
		released.Name = ((Object)fishKind.Prefab).name;
		released.Quality = num4;
		return true;
	}

	private static FishKind Pick(List<FishKind> kinds)
	{
		float num = 0f;
		foreach (FishKind kind in kinds)
		{
			num += kind.Weight;
		}
		float num2 = Random.Range(0f, num);
		foreach (FishKind kind2 in kinds)
		{
			num2 -= kind2.Weight;
			if (num2 <= 0f)
			{
				return kind2;
			}
		}
		if (kinds.Count <= 0)
		{
			return null;
		}
		return kinds[kinds.Count - 1];
	}

	private static int RollQuality(FishKind kind, Vector3 pos)
	{
		//IL_00a2: 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)
		int num = 5;
		ItemDrop component = kind.Prefab.GetComponent<ItemDrop>();
		if ((Object)(object)component != (Object)null && component.m_itemData != null && component.m_itemData.m_shared != null)
		{
			num = Mathf.Max(1, component.m_itemData.m_shared.m_maxQuality);
		}
		SpawnData data = kind.Data;
		if (data != null && data.m_levelUpMinCenterDistance > 0f && ((Vector3)(ref pos)).magnitude <= data.m_levelUpMinCenterDistance)
		{
			return 1;
		}
		int i = ((data == null) ? 1 : Mathf.Max(1, data.m_minLevel));
		int num2 = Mathf.Min(num, data?.m_maxLevel ?? num);
		float num3 = ((data != null) ? SpawnSystem.GetLevelUpChance(pos, data) : SpawnSystem.GetLevelUpChance(pos, 20f));
		for (; i < num2; i++)
		{
			if (!(Random.Range(0f, 100f) <= num3))
			{
				break;
			}
		}
		return i;
	}

	private static List<FishKind> Natural(ZNetScene scene)
	{
		if (_natural != null && object.ReferenceEquals(scene, _naturalScene) && Time.time - _naturalBuilt < 120f)
		{
			return _natural;
		}
		List<FishKind> list = new List<FishKind>();
		foreach (SpawnSystemList item in SpawnLists())
		{
			if ((Object)(object)item == (Object)null || item.m_spawners == null)
			{
				continue;
			}
			foreach (SpawnData spawner in item.m_spawners)
			{
				if (spawner != null && spawner.m_enabled && !spawner.m_devDisabled && !((Object)(object)spawner.m_prefab == (Object)null) && string.IsNullOrEmpty(spawner.m_requiredPersistentEvent))
				{
					Fish component = spawner.m_prefab.GetComponent<Fish>();
					if (!((Object)(object)component == (Object)null) && (string.IsNullOrEmpty(spawner.m_requiredGlobalKey) || ZoneSystem.instance.GetGlobalKey(spawner.m_requiredGlobalKey)))
					{
						FishKind fishKind = new FishKind();
						fishKind.Prefab = spawner.m_prefab;
						fishKind.Fish = component;
						fishKind.Data = spawner;
						fishKind.Weight = (float)Mathf.Max(1, spawner.m_maxSpawned) * Mathf.Clamp(spawner.m_spawnChance, 1f, 100f) / 100f;
						list.Add(fishKind);
					}
				}
			}
		}
		if (list.Count == 0 && _natural == null)
		{
			FishingRunePlugin.Log.LogWarning((object)"No fish were found in the game's spawn lists; the Fishing Rune releases Perch everywhere.");
		}
		_natural = list;
		_naturalScene = scene;
		_naturalBuilt = Time.time;
		ByBiome.Clear();
		return list;
	}

	private static SpawnData DataFor(List<FishKind> natural, GameObject prefab)
	{
		if (natural != null)
		{
			foreach (FishKind item in natural)
			{
				if ((Object)(object)item.Prefab == (Object)(object)prefab)
				{
					return item.Data;
				}
			}
		}
		return null;
	}

	private static List<FishKind> BiomeKinds(ZNetScene scene, Biome biome)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//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)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Invalid comparison between Unknown and I4
		List<FishKind> list = Natural(scene);
		if (ByBiome.TryGetValue(biome, out var value))
		{
			return value;
		}
		value = new List<FishKind>();
		Dictionary<GameObject, FishKind> dictionary = new Dictionary<GameObject, FishKind>();
		foreach (FishKind item in list)
		{
			if ((item.Data.m_biome & biome) != 0)
			{
				if (dictionary.TryGetValue(item.Prefab, out var value2))
				{
					value2.Weight += item.Weight;
					continue;
				}
				value2 = new FishKind();
				value2.Prefab = item.Prefab;
				value2.Fish = item.Fish;
				value2.Data = item.Data;
				value2.Weight = item.Weight;
				dictionary[item.Prefab] = value2;
				value.Add(value2);
			}
		}
		if (value.Count == 0 && (int)biome == 4)
		{
			GameObject prefab = scene.GetPrefab("Fish4_cave");
			Fish val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Fish>() : null);
			if ((Object)(object)val != (Object)null)
			{
				FishKind fishKind = new FishKind();
				fishKind.Prefab = prefab;
				fishKind.Fish = val;
				fishKind.Weight = 1f;
				value.Add(fishKind);
			}
		}
		ByBiome[biome] = value;
		return value;
	}

	private static List<SpawnSystemList> SpawnLists()
	{
		List<SpawnSystemList> list = new List<SpawnSystemList>();
		SpawnSystem val = null;
		List<SpawnSystem> list2 = ((SpawnSystemsField != null) ? (SpawnSystemsField.GetValue(null) as List<SpawnSystem>) : null);
		if (list2 != null)
		{
			foreach (SpawnSystem item in list2)
			{
				if ((Object)(object)item != (Object)null && item.m_spawnLists != null && item.m_spawnLists.Count > 0)
				{
					val = item;
					break;
				}
			}
		}
		if ((Object)(object)val == (Object)null && (Object)(object)ZoneSystem.instance != (Object)null && (Object)(object)ZoneSystem.instance.m_zoneCtrlPrefab != (Object)null)
		{
			val = ZoneSystem.instance.m_zoneCtrlPrefab.GetComponent<SpawnSystem>();
		}
		if ((Object)(object)val != (Object)null && val.m_spawnLists != null)
		{
			list.AddRange(val.m_spawnLists);
		}
		return list;
	}

	private static List<FishKind> Forced(ZNetScene scene, RuneVariant variant)
	{
		string value = variant.Species.Value;
		if (string.IsNullOrEmpty(value) || value.Trim().Length == 0)
		{
			return null;
		}
		if (variant.ForcedKinds != null && value == variant.ForcedKey && object.ReferenceEquals(scene, variant.ForcedScene))
		{
			if (variant.ForcedKinds.Count <= 0)
			{
				return null;
			}
			return variant.ForcedKinds;
		}
		List<FishKind> list = new List<FishKind>();
		List<string> list2 = new List<string>();
		List<FishKind> natural = Natural(scene);
		string[] array = value.Split(new char[3] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries);
		foreach (string text in array)
		{
			string text2 = text.Trim();
			GameObject prefab = scene.GetPrefab(text2);
			Fish val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Fish>() : null);
			if ((Object)(object)val == (Object)null)
			{
				list2.Add(text2);
				continue;
			}
			FishKind fishKind = new FishKind();
			fishKind.Prefab = prefab;
			fishKind.Fish = val;
			fishKind.Weight = 1f;
			fishKind.Data = DataFor(natural, prefab);
			list.Add(fishKind);
		}
		if (list2.Count > 0 && variant.WarnedNames != value)
		{
			variant.WarnedNames = value;
			FishingRunePlugin.Log.LogWarning((object)(variant.DisplayName + " Species: " + string.Join(", ", list2.ToArray()) + " is not a fish prefab and is ignored" + ((list.Count == 0) ? "; releasing the rune's usual fish instead." : ".")));
		}
		variant.ForcedKinds = list;
		variant.ForcedKey = value;
		variant.ForcedScene = scene;
		if (list.Count <= 0)
		{
			return null;
		}
		return list;
	}
}
public static class Patches
{
	internal static Piece OrigPiece;

	internal static Func<Player, Piece, bool> IsUnlockedOriginal;

	public static void IsUnlockablePostfix(Piece piece, ref bool __result)
	{
		if (!__result && FishingRunePlugin.VariantOf(piece) != null)
		{
			__result = true;
		}
	}

	public static void IsUnlockedPostfix(Player player, Piece piece, ref bool __result)
	{
		if ((Object)(object)OrigPiece != (Object)null && IsUnlockedOriginal != null && FishingRunePlugin.VariantOf(piece) != null)
		{
			__result = IsUnlockedOriginal(player, OrigPiece);
		}
	}

	public static void EnergyCostPostfix(Piece piece, ref float __result)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		RuneVariant runeVariant = FishingRunePlugin.VariantOf(piece);
		if (runeVariant != null)
		{
			ConfigEntry<float> val = (((int)runeVariant.Biome == 0) ? FishingRunePlugin.EnergyCost : FishingRunePlugin.BiomeEnergyCost);
			if (val != null && val.Value > 0f)
			{
				__result = val.Value;
			}
		}
	}
}
internal static class Glyph
{
	private delegate float Distance(float px, float py);

	private class Strokes
	{
		public readonly List<float[]> Segments = new List<float[]>();

		public readonly List<float[]> Circles = new List<float[]>();

		public readonly List<float[]> ShapeBoxes = new List<float[]>();

		public readonly List<Distance> Shapes = new List<Distance>();

		public float Scale = 1f;

		public float OffsetY;

		public Vector2 P(float x, float y)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2(x * Scale, y * Scale + OffsetY);
		}

		public void Line(float x0, float y0, float x1, float y1)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = P(x0, y0);
			Vector2 val2 = P(x1, y1);
			Segments.Add(new float[4] { val.x, val.y, val2.x, val2.y });
		}

		public void Ring(float cx, float cy, float r)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = P(cx, cy);
			Circles.Add(new float[3]
			{
				val.x,
				val.y,
				r * Scale
			});
		}

		public void Polyline(List<Vector2> local)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 1; i < local.Count; i++)
			{
				Line(local[i - 1].x, local[i - 1].y, local[i].x, local[i].y);
			}
		}

		public void Curve(float ax, float ay, float cx, float cy, float bx, float by)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			List<Vector2> list = new List<Vector2>();
			for (int i = 0; i <= 16; i++)
			{
				float num = (float)i / 16f;
				float num2 = 1f - num;
				list.Add(new Vector2(num2 * num2 * ax + 2f * num2 * num * cx + num * num * bx, num2 * num2 * ay + 2f * num2 * num * cy + num * num * by));
			}
			Polyline(list);
		}

		public void Ellipse(float cx, float cy, float rx, float ry)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			List<Vector2> list = new List<Vector2>();
			for (int i = 0; i <= 40; i++)
			{
				float num = (float)i * (float)Math.PI * 2f / 40f;
				list.Add(new Vector2(cx + rx * Mathf.Cos(num), cy + ry * Mathf.Sin(num)));
			}
			Polyline(list);
		}

		public void Shape(float x0, float y0, float x1, float y1, Distance signedLocal)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			float scale = Scale;
			float offsetY = OffsetY;
			Vector2 val = P(x0, y0);
			Vector2 val2 = P(x1, y1);
			ShapeBoxes.Add(new float[4] { val.x, val.y, val2.x, val2.y });
			Shapes.Add((float px, float py) => Mathf.Abs(signedLocal(px / scale, (py - offsetY) / scale)) * scale);
		}
	}

	internal const int None = -1;

	internal const int Meadows = 0;

	internal const int BlackForest = 1;

	internal const int Swamp = 2;

	internal const int Mountain = 3;

	internal const int Plains = 4;

	internal const int Ocean = 5;

	internal const int Mistlands = 6;

	internal const int Ashlands = 7;

	internal const int DeepNorth = 8;

	private const int Size = 512;

	private const float Centre = 255.5f;

	private const float HalfLine = 2.4f;

	private const float EmblemY = -155f;

	private const float EmblemScale = 1.2f;

	internal static Texture2D Build(int emblem)
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Expected O, but got Unknown
		byte[] array = Alpha(emblem);
		Color32[] array2 = (Color32[])(object)new Color32[262144];
		for (int i = 0; i < array2.Length; i++)
		{
			ref Color32 reference = ref array2[i];
			reference = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, array[i]);
		}
		Texture2D val = new Texture2D(512, 512, (TextureFormat)4, true);
		((Object)val).name = "FishingRuneGlyph" + ((emblem >= 0) ? emblem.ToString() : "");
		((Texture)val).wrapMode = (TextureWrapMode)1;
		((Texture)val).filterMode = (FilterMode)2;
		val.SetPixels32(array2);
		val.Apply(true, false);
		return val;
	}

	internal static byte[] Alpha(int emblem)
	{
		Strokes strokes = new Strokes();
		if (emblem < 0)
		{
			FishAndWaves(strokes);
		}
		else
		{
			strokes.Scale = 0.8f;
			strokes.OffsetY = 45f;
			FishAndWaves(strokes);
			strokes.Scale = 1.2f;
			strokes.OffsetY = -155f;
			Emblem(strokes, emblem);
		}
		float[] array = new float[262144];
		for (int i = 0; i < array.Length; i++)
		{
			array[i] = float.MaxValue;
		}
		float num = 4.4f;
		foreach (float[] segment in strokes.Segments)
		{
			float[] g = segment;
			Stamp(array, Mathf.Min(g[0], g[2]) - num, Mathf.Min(g[1], g[3]) - num, Mathf.Max(g[0], g[2]) + num, Mathf.Max(g[1], g[3]) + num, (float px, float py) => DistanceToSegment(px, py, g));
		}
		foreach (float[] circle in strokes.Circles)
		{
			float[] c = circle;
			Stamp(array, c[0] - c[2] - num, c[1] - c[2] - num, c[0] + c[2] + num, c[1] + c[2] + num, delegate(float px, float py)
			{
				float num5 = px - c[0];
				float num6 = py - c[1];
				return Mathf.Abs(Mathf.Sqrt(num5 * num5 + num6 * num6) - c[2]);
			});
		}
		for (int num2 = 0; num2 < strokes.Shapes.Count; num2++)
		{
			float[] array2 = strokes.ShapeBoxes[num2];
			Stamp(array, Mathf.Min(array2[0], array2[2]) - num, Mathf.Min(array2[1], array2[3]) - num, Mathf.Max(array2[0], array2[2]) + num, Mathf.Max(array2[1], array2[3]) + num, strokes.Shapes[num2]);
		}
		byte[] array3 = new byte[262144];
		for (int num3 = 0; num3 < array3.Length; num3++)
		{
			float num4 = Mathf.Clamp01(2.9f - array[num3]);
			array3[num3] = (byte)Mathf.RoundToInt(num4 * 255f);
		}
		return array3;
	}

	private static void FishAndWaves(Strokes s)
	{
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
		List<Vector2> list = new List<Vector2>();
		List<Vector2> list2 = new List<Vector2>();
		for (int i = 0; i <= 32; i++)
		{
			float num = (float)i / 32f;
			float num2 = Mathf.Lerp(-125f, 75f, num);
			float num3 = Mathf.Sin((float)Math.PI * Mathf.Pow(num, 0.8f));
			list.Add(new Vector2(num2, -45f - 58f * num3));
			list2.Add(new Vector2(num2, -45f + 50f * num3));
		}
		s.Polyline(list);
		s.Polyline(list2);
		s.Line(75f, -45f, 135f, -100f);
		s.Line(135f, -100f, 115f, -45f);
		s.Line(115f, -45f, 135f, 10f);
		s.Line(135f, 10f, 75f, -45f);
		s.Ring(-88f, -58f, 7f);
		List<Vector2> list3 = new List<Vector2>();
		for (int j = 0; j <= 12; j++)
		{
			float num4 = (float)j / 12f;
			list3.Add(new Vector2(-55f - 12f * Mathf.Sin((float)Math.PI * num4), Mathf.Lerp(-90f, -4f, num4)));
		}
		s.Polyline(list3);
		float[] array = new float[2] { 60f, 108f };
		for (int k = 0; k < array.Length; k++)
		{
			List<Vector2> list4 = new List<Vector2>();
			for (int l = 0; l <= 48; l++)
			{
				float num5 = (float)l / 48f;
				list4.Add(new Vector2(Mathf.Lerp(-145f, 145f, num5), array[k] + 11f * Mathf.Sin(num5 * (float)Math.PI * 6f)));
			}
			s.Polyline(list4);
			s.Ring(-155f, array[k], 9f);
			s.Ring(155f, array[k], 9f);
		}
	}

	private static void Emblem(Strokes s, int emblem)
	{
		switch (emblem)
		{
		case 0:
			s.Line(-64f, -62f, 64f, -62f);
			s.Curve(0f, -62f, -8f, 5f, -46f, 44f);
			s.Curve(0f, -62f, 2f, 10f, 4f, 58f);
			s.Ring(5f, 68f, 10f);
			s.Curve(0f, -62f, 14f, 0f, 50f, 36f);
			s.Curve(-22f, -62f, -30f, -30f, -62f, -10f);
			s.Curve(22f, -62f, 32f, -34f, 62f, -16f);
			break;
		case 1:
			s.Polyline(Points(0f, 68f, -24f, 34f, -12f, 34f, -40f, -2f, -18f, -2f, -56f, -40f, 56f, -40f, 18f, -2f, 40f, -2f, 12f, 34f, 24f, 34f, 0f, 68f));
			s.Polyline(Points(-8f, -40f, -8f, -66f, 8f, -66f, 8f, -40f));
			break;
		case 2:
			s.Line(-64f, -62f, 64f, -62f);
			s.Line(-36f, -72f, 36f, -72f);
			s.Curve(-18f, -62f, -20f, -18f, -27f, 20f);
			s.Ellipse(-28f, 40f, 8f, 20f);
			s.Line(-28f, 60f, -29f, 72f);
			s.Curve(18f, -62f, 22f, -24f, 30f, 6f);
			s.Ellipse(30f, 24f, 8f, 18f);
			s.Line(30f, 42f, 31f, 54f);
			s.Curve(-2f, -62f, -6f, 0f, -56f, 26f);
			s.Curve(4f, -62f, 34f, -24f, 62f, -4f);
			break;
		case 3:
			s.Polyline(Points(-72f, -58f, -28f, 36f, -4f, -2f, 26f, 62f, 72f, -58f, -72f, -58f));
			s.Polyline(Points(11f, 30f, 17.5f, 22f, 24.5f, 31f, 31.5f, 22f, 38f, 30f));
			s.Polyline(Points(-39f, 12f, -33f, 5f, -26f, 13f, -19f, 5f, -13f, 12f));
			break;
		case 4:
		{
			s.Line(0f, -68f, 0f, 58f);
			s.Line(0f, 58f, 0f, 74f);
			for (int num4 = 0; num4 < 5; num4++)
			{
				float num5 = -6f + (float)num4 * 15f;
				s.Line(0f, num5, -17f, num5 + 13f);
				s.Line(0f, num5, 17f, num5 + 13f);
			}
			s.Curve(0f, -40f, -30f, -40f, -46f, -14f);
			s.Curve(0f, -54f, 30f, -54f, 46f, -28f);
			break;
		}
		case 5:
			Anchor(s);
			break;
		case 6:
			s.Shape(-56f, -30f, 58f, 46f, delegate(float x, float y)
			{
				float num6 = Box(x, y, 0f, -16f, 40f, 10f);
				num6 = Mathf.Min(num6, Circle(x, y, -28f, -4f, 22f));
				num6 = Mathf.Min(num6, Circle(x, y, 2f, 12f, 30f));
				return Mathf.Min(num6, Circle(x, y, 32f, -4f, 22f));
			});
			s.Line(-54f, -42f, 38f, -42f);
			s.Line(-30f, -56f, 58f, -56f);
			s.Line(-46f, -70f, 20f, -70f);
			break;
		case 7:
			s.Polyline(Teardrop(0f, 8f, 40f, 62f));
			s.Polyline(Teardrop(0f, -16f, 20f, 30f));
			s.Ring(-44f, 38f, 4f);
			s.Ring(46f, 18f, 4f);
			break;
		case 8:
		{
			for (int i = 0; i < 6; i++)
			{
				float num = (float)Math.PI / 2f + (float)i * (float)Math.PI / 3f;
				float num2 = Mathf.Cos(num);
				float num3 = Mathf.Sin(num);
				s.Line(0f, 0f, num2 * 66f, num3 * 66f);
				Branch(s, num2, num3, 36f, 20f);
				Branch(s, num2, num3, 54f, 11f);
			}
			s.Ring(0f, 0f, 9f);
			break;
		}
		}
	}

	private static void Anchor(Strokes s)
	{
		//IL_00b4: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
		s.Ring(0f, 58f, 10f);
		s.Line(0f, 48f, 0f, -58f);
		s.Line(-26f, 30f, 26f, 30f);
		s.Ring(-30f, 30f, 4f);
		s.Ring(30f, 30f, 4f);
		List<Vector2> list = new List<Vector2>();
		for (int i = 0; i <= 28; i++)
		{
			float num = Mathf.Lerp(3.4906585f, 5.934119f, (float)i / 28f);
			list.Add(new Vector2(46f * Mathf.Cos(num), -12f + 46f * Mathf.Sin(num)));
		}
		s.Polyline(list);
		Barb(s, list[0], 3.4906585f, -1f);
		Barb(s, list[list.Count - 1], 5.934119f, 1f);
	}

	private static void Barb(Strokes s, Vector2 tip, float angle, float sense)
	{
		float num = (0f - Mathf.Sin(angle)) * sense;
		float num2 = Mathf.Cos(angle) * sense;
		float num3 = 0f - num2;
		float num4 = num;
		s.Line(tip.x, tip.y, tip.x - num * 14f + num3 * 9f, tip.y - num2 * 14f + num4 * 9f);
		s.Line(tip.x, tip.y, tip.x - num * 14f - num3 * 9f, tip.y - num2 * 14f - num4 * 9f);
	}

	private static void Branch(Strokes s, float dx, float dy, float at, float length)
	{
		float num = dx * at;
		float num2 = dy * at;
		float num3 = Mathf.Cos(0.8f);
		float num4 = Mathf.Sin(0.8f);
		s.Line(num, num2, num + (dx * num3 - dy * num4) * length, num2 + (dy * num3 + dx * num4) * length);
		s.Line(num, num2, num + (dx * num3 + dy * num4) * length, num2 + (dy * num3 - dx * num4) * length);
	}

	private static List<Vector2> Teardrop(float cx, float cy, float w, float h)
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		List<Vector2> list = new List<Vector2>();
		for (int i = 0; i <= 48; i++)
		{
			float num = (float)i * (float)Math.PI * 2f / 48f;
			list.Add(new Vector2(cx + w * Mathf.Sin(num) * Mathf.Sin(num / 2f), cy + h * Mathf.Cos(num)));
		}
		return list;
	}

	private static List<Vector2> Points(params float[] xy)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		List<Vector2> list = new List<Vector2>();
		for (int i = 0; i + 1 < xy.Length; i += 2)
		{
			list.Add(new Vector2(xy[i], xy[i + 1]));
		}
		return list;
	}

	private static float Circle(float x, float y, float cx, float cy, float r)
	{
		float num = x - cx;
		float num2 = y - cy;
		return Mathf.Sqrt(num * num + num2 * num2) - r;
	}

	private static float Box(float x, float y, float cx, float cy, float hx, float hy)
	{
		float num = Mathf.Abs(x - cx) - hx;
		float num2 = Mathf.Abs(y - cy) - hy;
		float num3 = Mathf.Max(num, 0f);
		float num4 = Mathf.Max(num2, 0f);
		return Mathf.Sqrt(num3 * num3 + num4 * num4) + Mathf.Min(Mathf.Max(num, num2), 0f);
	}

	private static void Stamp(float[] best, float x0, float y0, float x1, float y1, Distance distance)
	{
		int num = Mathf.Max(0, Mathf.FloorToInt(x0 + 255.5f));
		int num2 = Mathf.Max(0, Mathf.FloorToInt(y0 + 255.5f));
		int num3 = Mathf.Min(511, Mathf.CeilToInt(x1 + 255.5f));
		int num4 = Mathf.Min(511, Mathf.CeilToInt(y1 + 255.5f));
		for (int i = num2; i <= num4; i++)
		{
			float py = (float)i - 255.5f;
			for (int j = num; j <= num3; j++)
			{
				float num5 = distance((float)j - 255.5f, py);
				int num6 = i * 512 + j;
				if (num5 < best[num6])
				{
					best[num6] = num5;
				}
			}
		}
	}

	private static float DistanceToSegment(float px, float py, float[] s)
	{
		float num = s[2] - s[0];
		float num2 = s[3] - s[1];
		float num3 = px - s[0];
		float num4 = py - s[1];
		float num5 = num * num + num2 * num2;
		float num6 = ((num5 > 0f) ? Mathf.Clamp01((num3 * num + num4 * num2) / num5) : 0f);
		float num7 = num3 - num6 * num;
		float num8 = num4 - num6 * num2;
		return Mathf.Sqrt(num7 * num7 + num8 * num8);
	}
}

plugins/RuneFocusCapacity.dll

Decompiled a month 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: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace RuneFocusCapacity;

[BepInPlugin("danpe.RuneFocusCapacity", "Rune Focus Capacity", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class RuneFocusCapacityPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "danpe.RuneFocusCapacity";

	public const string PluginName = "Rune Focus Capacity";

	public const string PluginVersion = "1.0.0";

	internal const string RuneMagicGuid = "hyleanlegend.RuneMagic";

	internal const string FocusPrefab = "RuneFocus";

	internal const string FocusItemName = "$item_runemagic_runefocus";

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<float> BaseEnergy;

	internal static ConfigEntry<float> EnergyPerLevel;

	private static readonly Dictionary<SharedData, Vector2> Originals = new Dictionary<SharedData, Vector2>();

	private static Harmony _harmony;

	private static string _lastReport;

	private void Awake()
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Expected O, but got Unknown
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Expected O, but got Unknown
		//IL_016e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0178: Expected O, but got Unknown
		//IL_018e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0195: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. Off: the Rune Focus holds Rune Magic's own amounts (100 / 200 / 300 / 400).");
		BaseEnergy = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Energy at quality 1", 250f, new ConfigDescription("Most runic energy a quality 1 Rune Focus can hold (Rune Magic: 100).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 10000f), new object[0]));
		EnergyPerLevel = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Energy per quality level", 250f, new ConfigDescription("Added for each quality level above 1 (Rune Magic: 100). The defaults give 250 / 500 / 750 / 1000 at qualities 1 to 4. Applies at once, also to foci already in your inventory; their current energy is kept.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10000f), new object[0]));
		Enabled.SettingChanged += OnSettingChanged;
		BaseEnergy.SettingChanged += OnSettingChanged;
		EnergyPerLevel.SettingChanged += OnSettingChanged;
		try
		{
			Type type = AccessTools.TypeByName("ValheimMod.CustomContentSetupHandler");
			FieldInfo fieldInfo = ((type != null) ? AccessTools.Field(type, "RegisteredItemPrefabs") : null);
			List<GameObject> list = ((fieldInfo != null) ? (fieldInfo.GetValue(null) as List<GameObject>) : null);
			if (list != null)
			{
				foreach (GameObject item in list)
				{
					Track(item);
				}
			}
			else
			{
				Log.LogWarning((object)"Rune Magic's item list was not found; the Rune Focus will be changed when the item database loads.");
			}
			_harmony = new Harmony("danpe.RuneFocusCapacity");
			HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(RuneFocusCapacityPlugin), "ObjectDBPostfix", (Type[])null, (Type[])null));
			val.priority = 200;
			_harmony.Patch((MethodBase)AccessTools.Method(typeof(ObjectDB), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			_harmony.Patch((MethodBase)AccessTools.Method(typeof(ObjectDB), "CopyOtherDB", (Type[])null, (Type[])null), (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Apply();
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Rune Focus Capacity failed to start; the Rune Focus keeps Rune Magic's amounts. " + ex));
			Restore();
		}
	}

	private void OnDestroy()
	{
		Restore();
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}

	private static void OnSettingChanged(object sender, EventArgs e)
	{
		Apply();
	}

	private static bool Track(GameObject prefab)
	{
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		ItemDrop val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>() : null);
		SharedData val2 = (((Object)(object)val != (Object)null && val.m_itemData != null) ? val.m_itemData.m_shared : null);
		if (val2 == null || val2.m_name != "$item_runemagic_runefocus")
		{
			return false;
		}
		if (!Originals.ContainsKey(val2))
		{
			Originals[val2] = new Vector2(val2.m_maxDurability, val2.m_durabilityPerLevel);
		}
		return true;
	}

	public static void ObjectDBPostfix(ObjectDB __instance)
	{
		try
		{
			if (!((Object)(object)__instance == (Object)null) && Track(__instance.GetItemPrefab("RuneFocus")))
			{
				Apply();
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Could not update the Rune Focus: " + ex.Message));
		}
	}

	private static void Apply()
	{
		if (!Enabled.Value)
		{
			Restore();
			return;
		}
		float num = Mathf.Max(1f, BaseEnergy.Value);
		float num2 = Mathf.Max(0f, EnergyPerLevel.Value);
		int num3 = 1;
		foreach (SharedData key in Originals.Keys)
		{
			key.m_maxDurability = num;
			key.m_durabilityPerLevel = num2;
			num3 = Mathf.Max(num3, key.m_maxQuality);
		}
		if (Originals.Count != 0)
		{
			List<string> list = new List<string>();
			for (int i = 1; i <= num3; i++)
			{
				list.Add(Mathf.RoundToInt(num + (float)(i - 1) * num2).ToString());
			}
			string text = "Rune Focus holds " + string.Join(" / ", list.ToArray()) + " runic energy at quality 1-" + num3 + ".";
			if (text != _lastReport)
			{
				_lastReport = text;
				Log.LogInfo((object)text);
			}
		}
	}

	private static void Restore()
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		foreach (KeyValuePair<SharedData, Vector2> original in Originals)
		{
			original.Key.m_maxDurability = original.Value.x;
			original.Key.m_durabilityPerLevel = original.Value.y;
		}
		if (Originals.Count > 0 && _lastReport != "restored")
		{
			_lastReport = "restored";
			Log.LogInfo((object)"Rune Focus capacity back to Rune Magic's own amounts.");
		}
	}
}

plugins/RunicEitrRegen.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
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 RunicEitrRegen;

[BepInPlugin("danpe.RunicEitrRegen", "Runic Eitr Regen", "1.0.1")]
public class RunicEitrRegenPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "danpe.RunicEitrRegen";

	public const string PluginName = "Runic Eitr Regen";

	public const string PluginVersion = "1.0.1";

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<float> EnergyPerEitr;

	internal static ConfigEntry<bool> RequireEitrPool;

	internal static ConfigEntry<bool> SplitBetweenFoci;

	internal static ConfigEntry<string> FocusItemName;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Expected O, but got Unknown
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Expected O, but got Unknown
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch.");
		EnergyPerEitr = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Energy per eitr", 0.25f, new ConfigDescription("Runic energy gained per point of eitr that would have regenerated while eitr is already full.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), new object[0]));
		RequireEitrPool = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Require eitr pool", true, "If true, nothing is charged while your maximum eitr is 0 (no eitr food). If false, a player with no eitr pool counts as 'full'.");
		SplitBetweenFoci = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Split between foci", false, "If false, every Rune Focus in the inventory (including extra/quick slots, not inside backpacks) receives the full amount. If true, the amount is divided between the foci that still have room.");
		FocusItemName = ((BaseUnityPlugin)this).Config.Bind<string>("Advanced", "Focus item name", "$item_runemagic_runefocus", "Shared item name (localization token) that identifies a Rune Focus. Rune Magic uses the same check.");
		_harmony = new Harmony("danpe.RunicEitrRegen");
		_harmony.PatchAll(typeof(RunicEitrRegenPlugin).Assembly);
	}

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

	internal static void ChargeFoci(Player player, float energy)
	{
		Inventory inventory = ((Humanoid)player).GetInventory();
		if (inventory == null)
		{
			return;
		}
		List<ItemData> allItems = inventory.GetAllItems();
		string value = FocusItemName.Value;
		if (SplitBetweenFoci.Value)
		{
			int num = 0;
			for (int i = 0; i < allItems.Count; i++)
			{
				if (CanCharge(allItems[i], value))
				{
					num++;
				}
			}
			if (num == 0)
			{
				return;
			}
			energy /= (float)num;
		}
		for (int j = 0; j < allItems.Count; j++)
		{
			ItemData val = allItems[j];
			if (CanCharge(val, value))
			{
				val.m_durability = Mathf.Min(val.GetMaxDurability(), val.m_durability + energy);
			}
		}
	}

	private static bool CanCharge(ItemData item, string focusName)
	{
		if (!IsFocus(item, focusName))
		{
			return false;
		}
		if (item.m_equipped && item.m_durability <= 0f)
		{
			return false;
		}
		return item.m_durability < item.GetMaxDurability();
	}

	private static bool IsFocus(ItemData item, string focusName)
	{
		if (item != null && item.m_shared != null)
		{
			return item.m_shared.m_name == focusName;
		}
		return false;
	}
}
[HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })]
internal static class Player_UpdateStats_RunicOverflow
{
	private static bool _failed;

	[HarmonyPriority(0)]
	private static void Postfix(Player __instance, float dt, float ___m_eitrRegenTimer)
	{
		if (_failed)
		{
			return;
		}
		try
		{
			Charge(__instance, dt, ___m_eitrRegenTimer);
		}
		catch (Exception ex)
		{
			_failed = true;
			Debug.LogError((object)("[Runic Eitr Regen] disabled for this session after an error: " + ex));
		}
	}

	private static void Charge(Player __instance, float dt, float ___m_eitrRegenTimer)
	{
		if (!RunicEitrRegenPlugin.Enabled.Value || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || ((Character)__instance).InIntro() || ((Character)__instance).IsTeleporting() || ((Character)__instance).IsDead())
		{
			return;
		}
		float value = RunicEitrRegenPlugin.EnergyPerEitr.Value;
		if (value <= 0f || dt <= 0f || ___m_eitrRegenTimer > 0f)
		{
			return;
		}
		float maxEitr = ((Character)__instance).GetMaxEitr();
		if (maxEitr <= 0f)
		{
			if (RunicEitrRegenPlugin.RequireEitrPool.Value)
			{
				return;
			}
		}
		else if (__instance.GetEitr() < maxEitr)
		{
			return;
		}
		if (!((Character)__instance).InAttack() && !((Character)__instance).InDodge())
		{
			float num = (((Character)__instance).IsBlocking() ? 0.8f : 1f);
			float num2 = 1f;
			((Character)__instance).GetSEMan().ModifyEitrRegen(ref num2);
			num2 += __instance.GetEquipmentEitrRegenModifier();
			float num3 = __instance.m_eiterRegen * num * num2;
			if (!(num3 <= 0f) && !float.IsNaN(num3) && !float.IsInfinity(num3))
			{
				RunicEitrRegenPlugin.ChargeFoci(__instance, num3 * dt * value);
			}
		}
	}
}

plugins/MagicRevampHaste.dll

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

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

[BepInPlugin("danpe.MagicRevampHaste", "Magic Revamp - Haste Spell", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class HastePlugin : BaseUnityPlugin
{
	public const string PluginGuid = "danpe.MagicRevampHaste";

	public const string PluginName = "Magic Revamp - Haste Spell";

	public const string PluginVersion = "1.0.0";

	internal const string MagicRevampGuid = "blacks7ar.MagicRevamp";

	internal const string SourceScroll = "BMR_SailingScroll";

	internal const string SpellTable = "BMR_SpellTable";

	internal const string ScrollName = "danpe_HasteScroll";

	internal const string CloudName = "danpe_haste_aoe";

	internal const string EffectName = "danpe_Haste_SE";

	internal const string StartEffect = "fx_GP_Stone";

	internal static ManualLogSource Log;

	internal static ConfigEntry<float> DurationMinutes;

	internal static ConfigEntry<float> SpeedBonus;

	internal static ConfigEntry<float> StaminaRegenBonus;

	internal static ConfigEntry<float> Radius;

	internal static ConfigEntry<bool> BuffTames;

	internal static ConfigEntry<float> EitrCost;

	internal static ConfigEntry<string> CraftingCosts;

	internal static ConfigEntry<int> CraftAmount;

	internal static ConfigEntry<int> StationLevel;

	private static Harmony _harmony;

	private void Awake()
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Expected O, but got Unknown
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Expected O, but got Unknown
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Expected O, but got Unknown
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Expected O, but got Unknown
		//IL_0152: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Expected O, but got Unknown
		//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b4: Expected O, but got Unknown
		//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e6: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		DurationMinutes = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Haste", "Duration (minutes)", 5f, new ConfigDescription("How long the buff lasts. Casting again refreshes it to the full duration.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 60f), new object[0]));
		SpeedBonus = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Haste", "Movement speed bonus (%)", 25f, new ConfigDescription("Extra walking, running and swimming speed while hasted (swimming gets half, as with every vanilla speed buff).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), new object[0]));
		StaminaRegenBonus = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Haste", "Stamina regeneration bonus (%)", 100f, new ConfigDescription("Extra stamina regeneration while hasted. 100 = twice as fast.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 500f), new object[0]));
		Radius = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Haste", "Radius", 10f, new ConfigDescription("Reach of the spell in metres, measured from the spot just in front of the caster where the spell lands. Applies to the caster's own casts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 40f), new object[0]));
		BuffTames = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Haste", "Buff tamed creatures", true, "Tamed creatures within reach are allies too and get the speed bonus (stamina means nothing to them). Decided by the config of whoever owns the creature (usually the host or the player nearest to it).");
		EitrCost = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Casting", "Eitr cost", 20f, new ConfigDescription("Eitr used per cast (the Wind Spell costs 8, the Shield Spell 45).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), new object[0]));
		CraftingCosts = ((BaseUnityPlugin)this).Config.Bind<string>("3 - Crafting", "Crafting costs", "BMR_PaperHigh:20,Feathers:10,Honey:10", "Ingredients for one craft, as PrefabName:Amount separated by commas. Crafted at the same station as the Wind Spell (the Spell Table unless Magic Revamp's Wind Spell config moved it).");
		CraftAmount = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Crafting", "Scrolls per craft", 20, new ConfigDescription("How many Haste Spells one craft makes (Magic Revamp's spells make 20).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), new object[0]));
		StationLevel = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Crafting", "Crafting station level", 2, new ConfigDescription("Spell Table level needed (the Wind Spell needs 2).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), new object[0]));
		try
		{
			Setup();
			Log.LogInfo((object)"Haste Spell registered. Multiplayer: every player needs this add-on to receive the buff (and to keep the scroll).");
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Setup failed - the Haste Spell will not be available. Nothing else is affected. " + ex));
			Teardown();
		}
	}

	private void OnDestroy()
	{
		Teardown();
	}

	private static void Teardown()
	{
		if (_harmony != null)
		{
			try
			{
				_harmony.UnpatchSelf();
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Unpatch failed: " + ex.Message));
			}
			_harmony = null;
		}
	}

	private static MethodInfo RequireMethod(Type t, string name, Type[] args)
	{
		MethodInfo methodInfo = ((args == null) ? AccessTools.Method(t, name, (Type[])null, (Type[])null) : AccessTools.Method(t, name, args, (Type[])null));
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Method not found: " + t.FullName + "." + name);
		}
		return methodInfo;
	}

	private static FieldInfo RequireField(Type t, string name)
	{
		FieldInfo fieldInfo = AccessTools.Field(t, name);
		if (fieldInfo == null)
		{
			throw new InvalidOperationException("Field not found: " + t.FullName + "." + name);
		}
		return fieldInfo;
	}

	private static HarmonyMethod Last(string name)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(typeof(Patches), name, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Patch method missing: " + name);
		}
		HarmonyMethod val = new HarmonyMethod(methodInfo);
		val.priority = 0;
		return val;
	}

	private static void Setup()
	{
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_018e: Expected O, but got Unknown
		if (Chainloader.PluginInfos.TryGetValue("blacks7ar.MagicRevamp", out var value) && value != null)
		{
			Log.LogInfo((object)string.Concat("Magic Revamp ", value.Metadata.Version, " found (this add-on was made against 1.5.1)."));
		}
		MethodInfo methodInfo = RequireMethod(typeof(ObjectDB), "Awake", Type.EmptyTypes);
		MethodInfo methodInfo2 = RequireMethod(typeof(ObjectDB), "CopyOtherDB", new Type[1] { typeof(ObjectDB) });
		MethodInfo methodInfo3 = RequireMethod(typeof(ZNetScene), "Awake", Type.EmptyTypes);
		MethodInfo methodInfo4 = RequireMethod(typeof(Localization), "SetupLanguage", new Type[1] { typeof(string) });
		Registry.UpdateRegisters = RequireMethod(typeof(ObjectDB), "UpdateRegisters", Type.EmptyTypes);
		Registry.NamedPrefabs = RequireField(typeof(ZNetScene), "m_namedPrefabs");
		Words.AddWord = RequireMethod(typeof(Localization), "AddWord", new Type[2]
		{
			typeof(string),
			typeof(string)
		});
		if (AccessTools.Method(typeof(StatusEffect), "CanAdd", new Type[1] { typeof(Character) }, (Type[])null) == null)
		{
			throw new InvalidOperationException("StatusEffect.CanAdd(Character) not found");
		}
		_harmony = new Harmony("danpe.MagicRevampHaste");
		_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, Last("ObjectDBPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, Last("ObjectDBPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, Last("ZNetSceneAwakePostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		_harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, Last("SetupLanguagePostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		EventHandler eventHandler = delegate
		{
			Spell.Apply();
			Words.Refresh();
		};
		DurationMinutes.SettingChanged += eventHandler;
		SpeedBonus.SettingChanged += eventHandler;
		StaminaRegenBonus.SettingChanged += eventHandler;
		Radius.SettingChanged += eventHandler;
		EitrCost.SettingChanged += eventHandler;
		EventHandler eventHandler2 = delegate
		{
			Registry.RefreshRecipe();
		};
		CraftingCosts.SettingChanged += eventHandler2;
		CraftAmount.SettingChanged += eventHandler2;
		StationLevel.SettingChanged += eventHandler2;
	}
}
public class HasteEffect : SE_Stats
{
	public override bool CanAdd(Character character)
	{
		if ((Object)(object)character != (Object)null && !character.IsPlayer() && !HastePlugin.BuffTames.Value)
		{
			return false;
		}
		return ((StatusEffect)this).CanAdd(character);
	}

	public override void Setup(Character character)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Expected O, but got Unknown
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Expected O, but got Unknown
		try
		{
			if (((StatusEffect)this).m_startEffects == null)
			{
				((StatusEffect)this).m_startEffects = new EffectList();
			}
			if ((((StatusEffect)this).m_startEffects.m_effectPrefabs == null || ((StatusEffect)this).m_startEffects.m_effectPrefabs.Length == 0) && (Object)(object)ZNetScene.instance != (Object)null)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab("fx_GP_Stone");
				if ((Object)(object)prefab != (Object)null)
				{
					EffectData val = new EffectData();
					val.m_prefab = prefab;
					val.m_enabled = true;
					val.m_variant = -1;
					((StatusEffect)this).m_startEffects.m_effectPrefabs = (EffectData[])(object)new EffectData[1] { val };
				}
			}
		}
		catch (Exception)
		{
		}
		((SE_Stats)this).Setup(character);
	}
}
internal static class Spell
{
	internal static GameObject Scroll;

	internal static GameObject Cloud;

	internal static HasteEffect Effect;

	private static GameObject _holder;

	private static bool _failed;

	internal static bool Ensure(GameObject source)
	{
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Expected O, but got Unknown
		//IL_027c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0286: Expected O, but got Unknown
		//IL_0288: Unknown result type (might be due to invalid IL or missing references)
		//IL_0292: Expected O, but got Unknown
		if ((Object)(object)Scroll != (Object)null)
		{
			return true;
		}
		if ((Object)(object)source == (Object)null || _failed)
		{
			return false;
		}
		try
		{
			ItemDrop component = source.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null)
			{
				throw new InvalidOperationException("BMR_SailingScroll has no item data");
			}
			SharedData shared = component.m_itemData.m_shared;
			GameObject val = ((shared.m_attack != null) ? shared.m_attack.m_attackProjectile : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<Aoe>() == (Object)null)
			{
				throw new InvalidOperationException("BMR_SailingScroll no longer casts an Aoe cloud");
			}
			_holder = new GameObject("danpe_MagicRevampHaste_Prefabs");
			_holder.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)_holder);
			GameObject val2 = Object.Instantiate<GameObject>(val, _holder.transform, false);
			((Object)val2).name = "danpe_haste_aoe";
			Aoe component2 = val2.GetComponent<Aoe>();
			component2.m_statusEffect = "danpe_Haste_SE";
			component2.m_statusEffectIfBoss = "";
			component2.m_statusEffectIfPlayer = "";
			component2.m_useAttackSettings = false;
			component2.m_hitOwner = true;
			component2.m_hitSame = true;
			component2.m_hitFriendly = true;
			component2.m_hitEnemy = false;
			component2.m_hitProps = false;
			component2.m_hitTerrain = false;
			component2.m_ignorePVP = true;
			component2.m_blockable = false;
			component2.m_dodgeable = false;
			component2.m_hitInterval = 0f;
			component2.m_ttl = 1f;
			GameObject val3 = Object.Instantiate<GameObject>(source, _holder.transform, false);
			((Object)val3).name = "danpe_HasteScroll";
			ItemDrop component3 = val3.GetComponent<ItemDrop>();
			SharedData shared2 = component3.m_itemData.m_shared;
			if (object.ReferenceEquals(shared2, shared) || object.ReferenceEquals(shared2.m_attack, shared.m_attack))
			{
				throw new InvalidOperationException("the cloned scroll still shares the Wind Spell's data");
			}
			shared2.m_name = "$bmr_scroll_haste";
			shared2.m_description = "$bmr_scroll_haste_description";
			shared2.m_attack.m_attackProjectile = val2;
			component3.m_itemData.m_dropPrefab = val3;
			Sprite val4 = HasteIcon.Make((shared2.m_icons != null && shared2.m_icons.Length > 0) ? shared2.m_icons[0] : null);
			if ((Object)(object)val4 != (Object)null)
			{
				shared2.m_icons = (Sprite[])(object)new Sprite[1] { val4 };
			}
			HasteEffect hasteEffect = ScriptableObject.CreateInstance<HasteEffect>();
			((Object)hasteEffect).name = "danpe_Haste_SE";
			((StatusEffect)hasteEffect).m_name = "$danpe_haste";
			((StatusEffect)hasteEffect).m_tooltip = "$danpe_haste_tooltip";
			((StatusEffect)hasteEffect).m_icon = val4;
			((StatusEffect)hasteEffect).m_startEffects = new EffectList();
			((StatusEffect)hasteEffect).m_stopEffects = new EffectList();
			shared2.m_attackStatusEffect = (StatusEffect)(object)hasteEffect;
			Cloud = val2;
			Effect = hasteEffect;
			Scroll = val3;
			Apply();
			HastePlugin.Log.LogInfo((object)"Haste Spell built from the Wind Spell.");
			return true;
		}
		catch (Exception ex)
		{
			_failed = true;
			HastePlugin.Log.LogError((object)("Could not build the Haste Spell from the Wind Spell - the spell is unavailable: " + ex));
			if ((Object)(object)_holder != (Object)null)
			{
				Object.Destroy((Object)(object)_holder);
				_holder = null;
			}
			Scroll = null;
			Cloud = null;
			Effect = null;
			return false;
		}
	}

	internal static void Apply()
	{
		if (!((Object)(object)Scroll == (Object)null))
		{
			((StatusEffect)Effect).m_ttl = HastePlugin.DurationMinutes.Value * 60f;
			((SE_Stats)Effect).m_speedModifier = HastePlugin.SpeedBonus.Value / 100f;
			((SE_Stats)Effect).m_staminaRegenMultiplier = 1f + HastePlugin.StaminaRegenBonus.Value / 100f;
			Cloud.GetComponent<Aoe>().m_radius = HastePlugin.Radius.Value;
			Scroll.GetComponent<ItemDrop>().m_itemData.m_shared.m_attack.m_attackEitr = HastePlugin.EitrCost.Value;
		}
	}
}
internal static class Registry
{
	internal static MethodInfo UpdateRegisters;

	internal static FieldInfo NamedPrefabs;

	private static Recipe _recipe;

	internal static void AddToObjectDB(ObjectDB db)
	{
		if (!((Object)(object)db == (Object)null) && !((Object)(object)Spell.Scroll == (Object)null))
		{
			bool flag = false;
			if (!db.m_items.Contains(Spell.Scroll))
			{
				db.m_items.Add(Spell.Scroll);
				flag = true;
			}
			if (!db.m_StatusEffects.Contains((StatusEffect)(object)Spell.Effect))
			{
				db.m_StatusEffects.Add((StatusEffect)(object)Spell.Effect);
			}
			if (flag)
			{
				UpdateRegisters.Invoke(db, null);
			}
			if ((Object)(object)_recipe == (Object)null)
			{
				_recipe = ScriptableObject.CreateInstance<Recipe>();
				((Object)_recipe).name = "Recipe_danpe_HasteScroll";
				_recipe.m_item = Spell.Scroll.GetComponent<ItemDrop>();
			}
			if (!db.m_recipes.Contains(_recipe))
			{
				db.m_recipes.Add(_recipe);
			}
			FillRecipe(db);
		}
	}

	internal static void AddToScene(ZNetScene scene)
	{
		if ((Object)(object)scene == (Object)null || (Object)(object)Spell.Scroll == (Object)null)
		{
			return;
		}
		Dictionary<int, GameObject> dictionary = NamedPrefabs.GetValue(scene) as Dictionary<int, GameObject>;
		GameObject[] array = (GameObject[])(object)new GameObject[2]
		{
			Spell.Scroll,
			Spell.Cloud
		};
		foreach (GameObject val in array)
		{
			if (!scene.m_prefabs.Contains(val))
			{
				scene.m_prefabs.Add(val);
			}
			int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)val).name);
			if (dictionary != null && !dictionary.ContainsKey(stableHashCode))
			{
				dictionary[stableHashCode] = val;
			}
		}
	}

	internal static void RefreshRecipe()
	{
		if ((Object)(object)ObjectDB.instance != (Object)null && (Object)(object)_recipe != (Object)null)
		{
			FillRecipe(ObjectDB.instance);
		}
	}

	private static GameObject FindItem(ObjectDB db, string name)
	{
		GameObject itemPrefab = db.GetItemPrefab(name);
		if ((Object)(object)itemPrefab != (Object)null)
		{
			return itemPrefab;
		}
		foreach (GameObject item in db.m_items)
		{
			if ((Object)(object)item != (Object)null && ((Object)item).name == name)
			{
				return item;
			}
		}
		return null;
	}

	private static void FillRecipe(ObjectDB db)
	{
		CraftingStation val = null;
		GameObject val2 = FindItem(db, "BMR_SailingScroll");
		if ((Object)(object)val2 != (Object)null)
		{
			foreach (Recipe recipe in db.m_recipes)
			{
				if ((Object)(object)recipe != (Object)null && (Object)(object)recipe != (Object)(object)_recipe && (Object)(object)recipe.m_item != (Object)null && (Object)(object)((Component)recipe.m_item).gameObject == (Object)(object)val2 && (Object)(object)recipe.m_craftingStation != (Object)null)
				{
					val = recipe.m_craftingStation;
					break;
				}
			}
		}
		if ((Object)(object)val == (Object)null && (Object)(object)ZNetScene.instance != (Object)null)
		{
			GameObject prefab = ZNetScene.instance.GetPrefab("BMR_SpellTable");
			if ((Object)(object)prefab != (Object)null)
			{
				val = prefab.GetComponent<CraftingStation>();
			}
		}
		_recipe.m_craftingStation = val;
		_recipe.m_minStationLevel = HastePlugin.StationLevel.Value;
		_recipe.m_amount = HastePlugin.CraftAmount.Value;
		_recipe.m_resources = ParseCosts(db, HastePlugin.CraftingCosts.Value);
		_recipe.m_enabled = (Object)(object)val != (Object)null && _recipe.m_resources.Length > 0;
	}

	private static Requirement[] ParseCosts(ObjectDB db, string text)
	{
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: Expected O, but got Unknown
		List<Requirement> list = new List<Requirement>();
		string[] array = (text ?? "").Split(new char[1] { ',' });
		foreach (string text2 in array)
		{
			string text3 = text2.Trim();
			if (text3.Length == 0)
			{
				continue;
			}
			string[] array2 = text3.Split(new char[1] { ':' });
			int result = 1;
			if (array2.Length > 1 && !int.TryParse(array2[1].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out result))
			{
				HastePlugin.Log.LogWarning((object)("Crafting costs: '" + text3 + "' has no valid amount - skipped."));
				continue;
			}
			GameObject val = FindItem(db, array2[0].Trim());
			ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 == (Object)null)
			{
				if ((Object)(object)db.GetItemPrefab("Wood") != (Object)null)
				{
					HastePlugin.Log.LogWarning((object)("Crafting costs: no item named '" + array2[0].Trim() + "' - skipped."));
				}
				continue;
			}
			Requirement val3 = new Requirement();
			val3.m_resItem = val2;
			val3.m_amount = Mathf.Max(1, result);
			val3.m_amountPerLevel = 0;
			val3.m_recover = true;
			list.Add(val3);
		}
		return list.ToArray();
	}
}
internal static class Words
{
	internal static MethodInfo AddWord;

	internal static void AddTo(Localization loc)
	{
		if (loc == null || AddWord == null)
		{
			return;
		}
		try
		{
			Add(loc, "bmr_scroll_haste", "Haste Spell");
			Add(loc, "bmr_scroll_haste_description", Description());
			Add(loc, "danpe_haste", "Haste");
			Add(loc, "danpe_haste_tooltip", "The wind is at your heels.");
		}
		catch (Exception ex)
		{
			HastePlugin.Log.LogWarning((object)("Could not add the Haste Spell texts: " + ex.Message));
		}
	}

	internal static void Refresh()
	{
		AddTo(Localization.instance);
	}

	private static void Add(Localization loc, string key, string text)
	{
		AddWord.Invoke(loc, new object[2] { key, text });
	}

	private static string Description()
	{
		List<string> list = new List<string>();
		if (HastePlugin.SpeedBonus.Value > 0f)
		{
			list.Add("move " + Mathf.RoundToInt(HastePlugin.SpeedBonus.Value) + "% faster");
		}
		if (HastePlugin.StaminaRegenBonus.Value > 0f)
		{
			list.Add("regain stamina " + Mathf.RoundToInt(HastePlugin.StaminaRegenBonus.Value) + "% faster");
		}
		string text = ((list.Count == 0) ? "are hasted" : string.Join(" and ", list.ToArray()));
		float value = HastePlugin.DurationMinutes.Value;
		string text2 = (Mathf.Approximately(value, Mathf.Round(value)) ? (Mathf.RoundToInt(value) + ((Mathf.RoundToInt(value) == 1) ? " minute" : " minutes")) : (Mathf.RoundToInt(value * 60f) + " seconds"));
		return "A gust of wind gathers at the caster's heels and spreads to every ally within " + Mathf.RoundToInt(HastePlugin.Radius.Value) + " m. For " + text2 + " they " + text + ".";
	}
}
internal static class Patches
{
	private static bool _warned;

	public static void ObjectDBPostfix(ObjectDB __instance)
	{
		try
		{
			if ((Object)(object)__instance == (Object)null || __instance.m_items == null || __instance.m_items.Count == 0)
			{
				return;
			}
			GameObject val = __instance.GetItemPrefab("BMR_SailingScroll");
			if ((Object)(object)val == (Object)null)
			{
				foreach (GameObject item in __instance.m_items)
				{
					if ((Object)(object)item != (Object)null && ((Object)item).name == "BMR_SailingScroll")
					{
						val = item;
						break;
					}
				}
			}
			if (!Spell.Ensure(val))
			{
				WarnMissing((Object)(object)__instance.GetItemPrefab("Wood") != (Object)null && (Object)(object)val == (Object)null);
				return;
			}
			Registry.AddToObjectDB(__instance);
			Words.Refresh();
		}
		catch (Exception ex)
		{
			HastePlugin.Log.LogError((object)("Registering the Haste Spell in the item database failed: " + ex));
		}
	}

	public static void ZNetSceneAwakePostfix(ZNetScene __instance)
	{
		try
		{
			if (!Spell.Ensure(__instance.GetPrefab("BMR_SailingScroll")))
			{
				WarnMissing(really: true);
				return;
			}
			Registry.AddToScene(__instance);
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				Registry.AddToObjectDB(ObjectDB.instance);
			}
		}
		catch (Exception ex)
		{
			HastePlugin.Log.LogError((object)("Registering the Haste Spell prefabs failed: " + ex));
		}
	}

	public static void SetupLanguagePostfix(Localization __instance)
	{
		Words.AddTo(__instance);
	}

	private static void WarnMissing(bool really)
	{
		if (really && !_warned)
		{
			_warned = true;
			HastePlugin.Log.LogWarning((object)"Magic Revamp's Wind Spell (BMR_SailingScroll) was not found - the Haste Spell is unavailable.");
		}
	}
}
internal static class HasteIcon
{
	private const float TargetHue = 1f / 9f;

	internal static Sprite Make(Sprite source)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Expected O, but got Unknown
		//IL_014b: 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)
		if ((Object)(object)source == (Object)null || (Object)(object)source.texture == (Object)null || Application.isBatchMode)
		{
			return source;
		}
		try
		{
			int width;
			int height;
			Color[] array = ReadSprite(source, out width, out height);
			float num = default(float);
			float num2 = default(float);
			float num3 = default(float);
			for (int i = 0; i < array.Length; i++)
			{
				Color val = array[i];
				Color.RGBToHSV(val, ref num, ref num2, ref num3);
				Color val2 = Color.HSVToRGB(1f / 9f, Mathf.Clamp01(num2 * 1.15f), num3);
				float num4 = Mathf.Max(0f, num3 - 0.75f) / 0.25f * 0.55f;
				val2.r += (1f - val2.r) * num4;
				val2.g += (0.97f - val2.g) * num4;
				val2.b += (0.85f - val2.b) * num4;
				val2.a = val.a;
				array[i] = val2;
			}
			Texture2D val3 = new Texture2D(width, height, (TextureFormat)4, false);
			((Object)val3).name = "HasteSpellIcon";
			((Texture)val3).wrapMode = (TextureWrapMode)1;
			val3.SetPixels(array);
			val3.Apply(false, false);
			return Sprite.Create(val3, new Rect(0f, 0f, (float)width, (float)height), new Vector2(0.5f, 0.5f), 100f);
		}
		catch (Exception ex)
		{
			HastePlugin.Log.LogWarning((object)("Could not draw the Haste Spell icon, using the Wind Spell's: " + ex.Message));
			return source;
		}
	}

	private static Color[] ReadSprite(Sprite sprite, out int width, out int height)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Expected O, but got Unknown
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		Texture texture = (Texture)(object)sprite.texture;
		Rect textureRect = sprite.textureRect;
		width = Mathf.Max(1, Mathf.RoundToInt(((Rect)(ref textureRect)).width));
		height = Mathf.Max(1, Mathf.RoundToInt(((Rect)(ref textureRect)).height));
		RenderTexture temporary = RenderTexture.GetTemporary(texture.width, texture.height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
		RenderTexture active = RenderTexture.active;
		Texture2D val = null;
		try
		{
			Graphics.Blit(texture, temporary);
			RenderTexture.active = temporary;
			val = new Texture2D(width, height, (TextureFormat)4, false);
			val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)width, (float)height), 0, 0);
			val.Apply();
			return val.GetPixels();
		}
		finally
		{
			RenderTexture.active = active;
			RenderTexture.ReleaseTemporary(temporary);
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)val);
			}
		}
	}
}

plugins/PoVGive.dll

Decompiled a month 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: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace PoVGive;

[BepInPlugin("danpe.PoVGive", "Path of Valheiman - Give Levels", "1.0.2")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class PoVGivePlugin : BaseUnityPlugin
{
	public const string PluginGuid = "danpe.PoVGive";

	public const string PluginName = "Path of Valheiman - Give Levels";

	public const string PluginVersion = "1.0.2";

	internal const string RpcGrant = "PoVGive_Grant";

	internal const string RpcAck = "PoVGive_Ack";

	internal static ManualLogSource Log;

	internal static ConfigEntry<int> MaxLevels;

	internal static ConfigEntry<int> MaxXp;

	internal static ConfigEntry<int> MaxPoints;

	internal static ConfigEntry<bool> AnnounceToTarget;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Expected O, but got Unknown
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Expected O, but got Unknown
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Expected O, but got Unknown
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		MaxLevels = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "Max levels per command", 200, new ConfigDescription("Upper bound for one pt_give.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000), new object[0]));
		MaxXp = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "Max xp per command", 1000000, new ConfigDescription("Upper bound for one pt_givexp.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100000000), new object[0]));
		MaxPoints = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "Max points per command", 500, new ConfigDescription("Upper bound for one pt_givepoints.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10000), new object[0]));
		AnnounceToTarget = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Announce to target", true, "Show the receiving player a centre-screen message saying what they were given and by whom.");
		try
		{
			Bridge.Init();
			_harmony = new Harmony("danpe.PoVGive");
			_harmony.PatchAll(typeof(PoVGivePlugin).Assembly);
			Log.LogInfo((object)"pt_give / pt_givexp / pt_givepoints ready (run them on the host after devcommands).");
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Setup failed - the give commands are unavailable. " + ex));
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}
}
internal static class Bridge
{
	private static MethodInfo _getCurrent;

	private static MethodInfo _getXpToNext;

	private static MethodInfo _addXp;

	private static int _addXpArity;

	private static MethodInfo _addBonusPoints;

	private static FieldInfo _level;

	private static FieldInfo _xp;

	private static readonly Type[][] AddXpSignatures = new Type[4][]
	{
		new Type[6]
		{
			typeof(float),
			typeof(string),
			typeof(bool),
			typeof(Vector3?),
			typeof(bool),
			typeof(string)
		},
		new Type[5]
		{
			typeof(float),
			typeof(string),
			typeof(bool),
			typeof(Vector3?),
			typeof(bool)
		},
		new Type[4]
		{
			typeof(float),
			typeof(string),
			typeof(bool),
			typeof(Vector3?)
		},
		new Type[3]
		{
			typeof(float),
			typeof(string),
			typeof(bool)
		}
	};

	private static readonly Vector3 NeutralBiomePoint = new Vector3(1000000f, 0f, 1000000f);

	internal static void Init()
	{
		Type type = AccessTools.TypeByName("PassiveTree.Progress");
		if (type == null)
		{
			throw new InvalidOperationException("PassiveTree.Progress not found");
		}
		_getCurrent = Require(type, "get_Current", Type.EmptyTypes);
		_getXpToNext = Require(type, "get_XpToNext", Type.EmptyTypes);
		_addXp = FindAddXp(type);
		if (_addXp == null)
		{
			throw new InvalidOperationException("PassiveTree.Progress.AddXp not found with any known parameter list (Path of Valheiman changed). Present: " + DescribeAddXp(type));
		}
		_addXpArity = _addXp.GetParameters().Length;
		_addBonusPoints = Require(type, "AddBonusPoints", new Type[1] { typeof(int) });
		_level = AccessTools.Field(type, "Level");
		_xp = AccessTools.Field(type, "Xp");
		PoVGivePlugin.Log.LogInfo((object)("Using PassiveTree.Progress." + Describe(_addXp) + "."));
	}

	private static MethodInfo Require(Type t, string name, Type[] args)
	{
		MethodInfo methodInfo = AccessTools.Method(t, name, args, (Type[])null);
		if (methodInfo == null)
		{
			throw new InvalidOperationException("PassiveTree.Progress." + name + " not found (Path of Valheiman changed)");
		}
		return methodInfo;
	}

	private static MethodInfo FindAddXp(Type progress)
	{
		MethodInfo[] methods = progress.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		Type[][] addXpSignatures = AddXpSignatures;
		foreach (Type[] wanted in addXpSignatures)
		{
			MethodInfo[] array = methods;
			foreach (MethodInfo methodInfo in array)
			{
				if (methodInfo.Name == "AddXp" && !methodInfo.IsGenericMethodDefinition && SameParameters(methodInfo.GetParameters(), wanted))
				{
					return methodInfo;
				}
			}
		}
		return null;
	}

	private static bool SameParameters(ParameterInfo[] ps, Type[] wanted)
	{
		if (ps.Length != wanted.Length)
		{
			return false;
		}
		for (int i = 0; i < ps.Length; i++)
		{
			if (ps[i].ParameterType != wanted[i])
			{
				return false;
			}
		}
		return true;
	}

	private static string Describe(MethodInfo m)
	{
		List<string> list = new List<string>();
		ParameterInfo[] parameters = m.GetParameters();
		foreach (ParameterInfo parameterInfo in parameters)
		{
			Type underlyingType = Nullable.GetUnderlyingType(parameterInfo.ParameterType);
			list.Add(((underlyingType != null) ? (underlyingType.Name + "?") : parameterInfo.ParameterType.Name) + " " + parameterInfo.Name);
		}
		return m.Name + "(" + string.Join(", ", list.ToArray()) + ")";
	}

	private static string DescribeAddXp(Type progress)
	{
		List<string> list = new List<string>();
		MethodInfo[] methods = progress.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (MethodInfo methodInfo in methods)
		{
			if (methodInfo.Name == "AddXp")
			{
				list.Add(Describe(methodInfo));
			}
		}
		if (list.Count != 0)
		{
			return string.Join("; ", list.ToArray());
		}
		return "none";
	}

	private static object[] XpArgs(float amount, string source, bool announce)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		object[] array = new object[_addXpArity];
		array[0] = amount;
		array[1] = source;
		array[2] = announce;
		if (_addXpArity > 3)
		{
			array[3] = NeutralBiomePoint;
		}
		if (_addXpArity > 4)
		{
			array[4] = false;
		}
		if (_addXpArity > 5)
		{
			array[5] = null;
		}
		return array;
	}

	private static void CallAddXp(object progress, float amount, string source, bool announce)
	{
		_addXp.Invoke(progress, XpArgs(amount, source, announce));
	}

	internal static object Current()
	{
		return _getCurrent.Invoke(null, null);
	}

	internal static int LevelOf(object progress)
	{
		if (_level == null)
		{
			return -1;
		}
		object value = _level.GetValue(progress);
		if (!(value is int))
		{
			return -1;
		}
		return (int)value;
	}

	internal static float XpOf(object progress)
	{
		if (_xp == null)
		{
			return -1f;
		}
		object value = _xp.GetValue(progress);
		if (!(value is float))
		{
			return -1f;
		}
		return (float)value;
	}

	internal static int AddLevels(object progress, int n)
	{
		int num = LevelOf(progress);
		if (_xp == null || num < 0)
		{
			for (int i = 0; i < n; i++)
			{
				float amount = (float)_getXpToNext.Invoke(progress, null);
				CallAddXp(progress, amount, null, announce: false);
			}
			return LevelOf(progress) - num;
		}
		for (int j = 0; j < n; j++)
		{
			int num2 = LevelOf(progress);
			float num3 = XpOf(progress);
			float num4 = (float)_getXpToNext.Invoke(progress, null);
			_xp.SetValue(progress, num3 + num4);
			CallAddXp(progress, 0.001f, null, announce: false);
			if (LevelOf(progress) == num2)
			{
				_xp.SetValue(progress, num3);
				break;
			}
		}
		return LevelOf(progress) - num;
	}

	internal static void AddXp(object progress, float amount, bool announce)
	{
		CallAddXp(progress, amount, "gift", announce);
	}

	internal static void AddPoints(object progress, int n)
	{
		_addBonusPoints.Invoke(progress, new object[1] { n });
	}
}
[HarmonyPatch]
public static class Patches
{
	private static readonly MethodInfo GetServerPeerId = AccessTools.Method(typeof(ZRoutedRpc), "GetServerPeerID", (Type[])null, (Type[])null);

	private static readonly int GrantHash = StringExtensionMethods.GetStableHashCode("PoVGive_Grant");

	private static ZRoutedRpc _registeredOn;

	private static Terminal _lastConsole;

	private static bool _commandsRegistered;

	[HarmonyPrefix]
	[HarmonyPatch(typeof(ZRoutedRpc), "RPC_RoutedRPC")]
	public static bool DropInboundGrants(ZPackage pkg)
	{
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		if (pkg == null || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
		{
			return true;
		}
		int pos = pkg.GetPos();
		try
		{
			pkg.ReadLong();
			long num = pkg.ReadLong();
			pkg.ReadLong();
			pkg.ReadZDOID();
			int num2 = pkg.ReadInt();
			if (num2 == GrantHash)
			{
				PoVGivePlugin.Log.LogWarning((object)("Dropped a PoVGive_Grant that arrived over the network (claimed sender " + num + "); grants can only be created on the server."));
				return false;
			}
		}
		catch (Exception)
		{
		}
		finally
		{
			pkg.SetPos(pos);
		}
		return true;
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(ZNet), "Awake")]
	public static void ZNetAwakePostfix()
	{
		try
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null && _registeredOn != instance)
			{
				instance.Register<string, int, string>("PoVGive_Grant", (Action<long, string, int, string>)OnGrant);
				instance.Register<string>("PoVGive_Ack", (Action<long, string>)OnAck);
				_registeredOn = instance;
			}
		}
		catch (Exception ex)
		{
			PoVGivePlugin.Log.LogError((object)("Could not register RPCs: " + ex));
		}
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	public static void InitTerminalPostfix()
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Expected O, but got Unknown
		//IL_004a: 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_0030: Expected O, but got Unknown
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Expected O, but got Unknown
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Expected O, but got Unknown
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Expected O, but got Unknown
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Expected O, but got Unknown
		if (_commandsRegistered)
		{
			return;
		}
		try
		{
			_commandsRegistered = true;
			new ConsoleCommand("pt_give", "<player|all> [levels] - raise another player's Path of Valheiman level (host only)", (ConsoleEvent)delegate(ConsoleEventArgs args)
			{
				Give(args, "levels");
			}, true, false, false, false, false, false, new ConsoleOptionsFetcher(PlayerOptions), true, false, false);
			new ConsoleCommand("pt_givexp", "<player|all> <xp> - add Path of Valheiman experience to another player (host only)", (ConsoleEvent)delegate(ConsoleEventArgs args)
			{
				Give(args, "xp");
			}, true, false, false, false, false, false, new ConsoleOptionsFetcher(PlayerOptions), true, false, false);
			new ConsoleCommand("pt_givepoints", "<player|all> [points] - grant Path of Valheiman tree points to another player (host only)", (ConsoleEvent)delegate(ConsoleEventArgs args)
			{
				Give(args, "points");
			}, true, false, false, false, false, false, new ConsoleOptionsFetcher(PlayerOptions), true, false, false);
		}
		catch (Exception ex)
		{
			PoVGivePlugin.Log.LogError((object)("Could not register console commands: " + ex));
		}
	}

	private static List<string> PlayerOptions()
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		List<string> list = new List<string>();
		list.Add("all");
		if ((Object)(object)ZNet.instance != (Object)null)
		{
			foreach (PlayerInfo player in ZNet.instance.GetPlayerList())
			{
				if (!string.IsNullOrEmpty(player.m_name) && !list.Contains(player.m_name))
				{
					list.Add(player.m_name);
				}
			}
		}
		return list;
	}

	private static void Say(Terminal t, string text)
	{
		if ((Object)(object)t != (Object)null)
		{
			t.AddString(text);
		}
		else
		{
			PoVGivePlugin.Log.LogInfo((object)text);
		}
	}

	private static void Give(ConsoleEventArgs args, string kind)
	{
		//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		Terminal t = (_lastConsole = args.Context);
		if ((Object)(object)ZNet.instance == (Object)null || ZRoutedRpc.instance == null)
		{
			Say(t, "Not in a world.");
			return;
		}
		if (!ZNet.instance.IsServer())
		{
			Say(t, "pt_give only works from the host (the game that runs the world) or a dedicated server's console.");
			return;
		}
		if (args.Length < 2)
		{
			Say(t, "Usage: " + args[0] + " <player|all> <amount>   (player names: " + string.Join(", ", PlayerOptions().ToArray()) + ")");
			return;
		}
		string text = args[1];
		if (string.IsNullOrEmpty(text))
		{
			Say(t, "Usage: " + args[0] + " <player|all> <amount>");
			return;
		}
		int num = default(int);
		if (args.Length < 3)
		{
			num = ((!(kind == "xp")) ? 1 : 0);
		}
		else if (!args.TryParameterInt(2, ref num))
		{
			Say(t, "Amount must be a whole number.");
			return;
		}
		int num2 = ((kind == "xp") ? PoVGivePlugin.MaxXp.Value : ((kind == "points") ? PoVGivePlugin.MaxPoints.Value : PoVGivePlugin.MaxLevels.Value));
		if (num < 1 || num > num2)
		{
			Say(t, "Amount must be between 1 and " + num2 + ".");
			return;
		}
		List<PlayerInfo> list = ResolveTargets(text);
		if (list.Count == 0)
		{
			Say(t, "No player matches '" + text + "'. Online: " + string.Join(", ", PlayerOptions().ToArray()));
			return;
		}
		string text2 = (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerName() : "the server");
		foreach (PlayerInfo item in list)
		{
			ZDOID characterID = item.m_characterID;
			long userID = ((ZDOID)(ref characterID)).UserID;
			if (userID == 0)
			{
				Say(t, item.m_name + ": not spawned yet, skipped.");
				continue;
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(userID, "PoVGive_Grant", new object[3] { kind, num, text2 });
			Say(t, "Sent " + num + " " + kind + " to " + item.m_name + " (no reply means they do not have this plugin).");
		}
	}

	private static List<PlayerInfo> ResolveTargets(string who)
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: 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)
		List<PlayerInfo> playerList = ZNet.instance.GetPlayerList();
		List<PlayerInfo> list = new List<PlayerInfo>();
		if (string.Equals(who, "all", StringComparison.OrdinalIgnoreCase))
		{
			list.AddRange(playerList);
			return list;
		}
		foreach (PlayerInfo item in playerList)
		{
			if (string.Equals(item.m_name, who, StringComparison.OrdinalIgnoreCase))
			{
				list.Add(item);
				return list;
			}
		}
		foreach (PlayerInfo item2 in playerList)
		{
			if (item2.m_name != null && item2.m_name.StartsWith(who, StringComparison.OrdinalIgnoreCase))
			{
				list.Add(item2);
			}
		}
		if (list.Count == 1)
		{
			return list;
		}
		list.Clear();
		foreach (PlayerInfo item3 in playerList)
		{
			if (item3.m_name != null && item3.m_name.IndexOf(who, StringComparison.OrdinalIgnoreCase) >= 0)
			{
				list.Add(item3);
			}
		}
		if (list.Count != 1)
		{
			list.Clear();
		}
		return list;
	}

	private static bool FromServer(long sender)
	{
		if (ZRoutedRpc.instance == null || GetServerPeerId == null)
		{
			return false;
		}
		object obj = GetServerPeerId.Invoke(ZRoutedRpc.instance, null);
		if (obj is long)
		{
			return (long)obj == sender;
		}
		return false;
	}

	private static void OnGrant(long sender, string kind, int amount, string from)
	{
		try
		{
			if (!FromServer(sender))
			{
				PoVGivePlugin.Log.LogWarning((object)("Ignored a " + kind + " grant that did not come from the server (peer " + sender + ")."));
			}
			else
			{
				if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					return;
				}
				object obj = Bridge.Current();
				if (obj == null)
				{
					Reply(sender, Player.m_localPlayer.GetPlayerName() + ": no Path of Valheiman progress loaded yet.");
					return;
				}
				bool value = PoVGivePlugin.AnnounceToTarget.Value;
				int num = Bridge.LevelOf(obj);
				float num2 = Bridge.XpOf(obj);
				string text = "";
				string text2;
				if (kind == "xp")
				{
					amount = Math.Min(amount, PoVGivePlugin.MaxXp.Value);
					Bridge.AddXp(obj, amount, !value);
					text2 = amount + " XP";
					int num3 = Bridge.LevelOf(obj) - num;
					if (num2 >= 0f && num3 == 0)
					{
						text = " (" + Mathf.RoundToInt(Bridge.XpOf(obj) - num2) + " after the mod's multipliers)";
					}
					else if (num3 > 0)
					{
						text = " (+" + num3 + " level" + ((num3 == 1) ? "" : "s") + ")";
					}
				}
				else if (kind == "points")
				{
					amount = Math.Min(amount, PoVGivePlugin.MaxPoints.Value);
					Bridge.AddPoints(obj, amount);
					text2 = amount + " tree point" + ((amount == 1) ? "" : "s");
				}
				else
				{
					amount = Math.Min(amount, PoVGivePlugin.MaxLevels.Value);
					int num4 = Bridge.AddLevels(obj, amount);
					text2 = num4 + " level" + ((num4 == 1) ? "" : "s");
					if (num4 < amount)
					{
						text = " (max level reached)";
					}
				}
				if (value)
				{
					((Character)Player.m_localPlayer).Message((MessageType)2, from + " granted you " + text2, 0, (Sprite)null, false);
				}
				int num5 = Bridge.LevelOf(obj);
				Reply(sender, Player.m_localPlayer.GetPlayerName() + " received " + text2 + text + ((num5 >= 0) ? (" (now level " + num5 + ")") : "") + ".");
			}
		}
		catch (Exception ex)
		{
			PoVGivePlugin.Log.LogError((object)("Grant failed: " + ex));
			Exception ex2 = ex;
			while (ex2 is TargetInvocationException && ex2.InnerException != null)
			{
				ex2 = ex2.InnerException;
			}
			Reply(sender, "Grant failed on " + (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerName() : "a client") + ": " + ex2.Message);
		}
	}

	private static void Reply(long to, string text)
	{
		try
		{
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(to, "PoVGive_Ack", new object[1] { text });
			}
		}
		catch (Exception ex)
		{
			PoVGivePlugin.Log.LogWarning((object)("Reply failed: " + ex.Message));
		}
	}

	private static void OnAck(long sender, string text)
	{
		Say((Terminal)(((Object)(object)_lastConsole != (Object)null) ? ((object)_lastConsole) : ((object)Console.instance)), "[pt_give] " + text);
	}
}

plugins/EnemyHealthNumbers.dll

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

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

[BepInPlugin("danpe.EnemyHealthNumbers", "Enemy Health Numbers", "1.0.1")]
public class EnemyHealthNumbersPlugin : BaseUnityPlugin
{
	public enum HealthFormat
	{
		CurrentAndMax,
		CurrentOnly,
		Percent,
		CurrentMaxAndPercent
	}

	public const string PluginGuid = "danpe.EnemyHealthNumbers";

	public const string PluginName = "Enemy Health Numbers";

	public const string PluginVersion = "1.0.1";

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<bool> ShowOnEnemies;

	internal static ConfigEntry<bool> ShowOnBosses;

	internal static ConfigEntry<bool> ShowOnPlayers;

	internal static ConfigEntry<bool> ShowOnMount;

	internal static ConfigEntry<HealthFormat> Format;

	internal static ConfigEntry<int> EnemyFontSize;

	internal static ConfigEntry<int> BossFontSize;

	internal static ConfigEntry<float> EnemyOffsetY;

	internal static ConfigEntry<float> BossOffsetY;

	internal static ConfigEntry<float> PlayerOffsetY;

	internal static ConfigEntry<float> OffsetX;

	internal static ConfigEntry<Color> TextColor;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: Expected O, but got Unknown
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Expected O, but got Unknown
		//IL_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Expected O, but got Unknown
		//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01aa: Expected O, but got Unknown
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e8: Expected O, but got Unknown
		//IL_021c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0226: Expected O, but got Unknown
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_026c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0276: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. Turning it off blanks the numbers on existing bars.");
		ShowOnEnemies = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show on enemies", true, "Add a health number to normal enemy bars.");
		ShowOnBosses = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show on bosses", true, "Add a health number to the big boss bar.");
		ShowOnPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show on players", true, "Add a health number to other players' bars.");
		ShowOnMount = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show on mount", true, "Your ridden mount's panel already shows its current health; this changes it to the chosen format.");
		Format = ((BaseUnityPlugin)this).Config.Bind<HealthFormat>("General", "Format", HealthFormat.CurrentAndMax, "CurrentAndMax = 245/400, CurrentOnly = 245, Percent = 61%, CurrentMaxAndPercent = 245/400 (61%).");
		EnemyFontSize = ((BaseUnityPlugin)this).Config.Bind<int>("Look", "Enemy font size", 14, new ConfigDescription("Font size of the number on enemy and player bars.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(6, 40), new object[0]));
		BossFontSize = ((BaseUnityPlugin)this).Config.Bind<int>("Look", "Boss font size", 18, new ConfigDescription("Font size of the number on the boss bar.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(6, 60), new object[0]));
		EnemyOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Look", "Enemy text Y offset", 7f, new ConfigDescription("Vertical position of the number on enemy bars (BetterUI used 7, but it also made the bar three times taller). Applies to bars created from now on.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-60f, 60f), new object[0]));
		BossOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Look", "Boss text Y offset", 0f, new ConfigDescription("Vertical position of the number on the boss bar (BetterUI used 0). Applies to bars created from now on.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-100f, 100f), new object[0]));
		PlayerOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Look", "Player text Y offset", 3.5f, new ConfigDescription("Vertical position of the number on other players' bars (BetterUI used 3.5). Applies to bars created from now on.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-60f, 60f), new object[0]));
		OffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("Look", "Text X offset", 0f, new ConfigDescription("Horizontal shift relative to the name label. Applies to bars created from now on.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-200f, 200f), new object[0]));
		TextColor = ((BaseUnityPlugin)this).Config.Bind<Color>("Look", "Text color", Color.white, "Color of the number. Applies to bars created from now on.");
		((BaseUnityPlugin)this).Config.SettingChanged += OnSettingChanged;
		_harmony = new Harmony("danpe.EnemyHealthNumbers");
		try
		{
			Patches.Init();
			_harmony.PatchAll(typeof(EnemyHealthNumbersPlugin).Assembly);
			Log.LogInfo((object)"Enemy health numbers enabled.");
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Setup failed - health numbers will not be shown. " + ex));
			_harmony.UnpatchSelf();
		}
	}

	private void OnSettingChanged(object sender, SettingChangedEventArgs e)
	{
		Patches.ForgetSkipped();
	}

	private void OnDestroy()
	{
		((BaseUnityPlugin)this).Config.SettingChanged -= OnSettingChanged;
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}
}
internal class Entry
{
	public TextMeshProUGUI Text;

	public Character Character;

	public bool IsBoss;

	public int LastHealth = -1;

	public int LastMax = -1;

	public int LastFontSize = -1;

	public EnemyHealthNumbersPlugin.HealthFormat LastFormat;

	public bool Blanked;
}
[HarmonyPatch]
public static class Patches
{
	private static FieldInfo _fGui;

	private static FieldInfo _fName;

	private static readonly Dictionary<Character, Entry> Entries = new Dictionary<Character, Entry>();

	private static readonly List<Entry> Live = new List<Entry>();

	private static readonly Entry Skipped = new Entry();

	private static bool _failed;

	private static int _errors;

	internal static void Init()
	{
		Type type = AccessTools.Inner(typeof(EnemyHud), "HudData");
		if (type == null)
		{
			throw new InvalidOperationException("EnemyHud.HudData not found");
		}
		_fGui = Require(type, "m_gui");
		_fName = Require(type, "m_name");
		if (AccessTools.Field(typeof(EnemyHud), "m_huds") == null)
		{
			throw new InvalidOperationException("EnemyHud.m_huds not found");
		}
		if (AccessTools.Field(typeof(Hud), "m_mountHealthText") == null)
		{
			throw new InvalidOperationException("Hud.m_mountHealthText not found");
		}
	}

	private static FieldInfo Require(Type t, string name)
	{
		FieldInfo fieldInfo = AccessTools.Field(t, name);
		if (fieldInfo == null)
		{
			throw new InvalidOperationException("Field not found: " + t.FullName + "." + name);
		}
		return fieldInfo;
	}

	internal static void ForgetSkipped()
	{
		List<Character> list = new List<Character>();
		foreach (KeyValuePair<Character, Entry> entry in Entries)
		{
			if (entry.Value == Skipped)
			{
				list.Add(entry.Key);
			}
		}
		for (int i = 0; i < list.Count; i++)
		{
			Entries.Remove(list[i]);
		}
	}

	[HarmonyPatch(typeof(EnemyHud), "ShowHud")]
	[HarmonyPostfix]
	public static void ShowHudPostfix(Character c, bool isMount, object ___m_huds)
	{
		if (_failed || (Object)(object)c == (Object)null || !EnemyHealthNumbersPlugin.Enabled.Value || (Entries.TryGetValue(c, out var value) && (value == Skipped || (Object)(object)value.Text != (Object)null)))
		{
			return;
		}
		try
		{
			object obj = ((___m_huds is IDictionary dictionary) ? dictionary[c] : null);
			if (obj != null)
			{
				Entry entry = Create(obj, c, isMount);
				if (value != null)
				{
					Live.Remove(value);
				}
				Entries[c] = ((entry != null) ? entry : Skipped);
				if (entry != null)
				{
					Live.Add(entry);
					Refresh(entry);
				}
			}
		}
		catch (Exception e)
		{
			Entries[c] = Skipped;
			Trouble("creating a health number", e);
		}
	}

	[HarmonyPatch(typeof(EnemyHud), "UpdateHuds")]
	[HarmonyPostfix]
	public static void UpdateHudsPostfix()
	{
		if (_failed)
		{
			return;
		}
		bool value = EnemyHealthNumbersPlugin.Enabled.Value;
		for (int num = Live.Count - 1; num >= 0; num--)
		{
			Entry entry = Live[num];
			if ((Object)(object)entry.Text == (Object)null || (Object)(object)entry.Character == (Object)null)
			{
				Live.RemoveAt(num);
				if ((Object)(object)entry.Character != (Object)null)
				{
					Entries.Remove(entry.Character);
				}
			}
			else
			{
				try
				{
					if (!value)
					{
						Blank(entry);
					}
					else
					{
						Refresh(entry);
					}
				}
				catch (Exception e)
				{
					Live.RemoveAt(num);
					entry.Text = null;
					Trouble("updating a health number", e);
				}
			}
		}
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(Hud), "UpdateMount")]
	public static void UpdateMountPostfix(Hud __instance, Player player)
	{
		if (_failed || !EnemyHealthNumbersPlugin.Enabled.Value || !EnemyHealthNumbersPlugin.ShowOnMount.Value)
		{
			return;
		}
		try
		{
			Sadle val = (Sadle)(((Object)(object)player != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
			if (!((Object)(object)val == (Object)null) && !((Object)(object)__instance.m_mountHealthText == (Object)null))
			{
				Character character = val.GetCharacter();
				if (!((Object)(object)character == (Object)null))
				{
					((TMP_Text)__instance.m_mountHealthText).text = Compose(Mathf.CeilToInt(character.GetHealth()), Mathf.CeilToInt(character.GetMaxHealth()), EnemyHealthNumbersPlugin.Format.Value);
				}
			}
		}
		catch (Exception e)
		{
			Trouble("updating the mount health number", e);
		}
	}

	private static void Trouble(string what, Exception e)
	{
		_errors++;
		if (_errors <= 3)
		{
			EnemyHealthNumbersPlugin.Log.LogWarning((object)("Enemy health numbers: error while " + what + ": " + e));
		}
		if (_errors < 10)
		{
			return;
		}
		_failed = true;
		EnemyHealthNumbersPlugin.Log.LogError((object)"Enemy health numbers disabled for this session after repeated errors.");
		for (int i = 0; i < Live.Count; i++)
		{
			try
			{
				Blank(Live[i]);
			}
			catch (Exception)
			{
			}
		}
		Live.Clear();
		Entries.Clear();
	}

	private static Entry Create(object hud, Character c, bool isMount)
	{
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		if (isMount)
		{
			return null;
		}
		bool flag = c.IsPlayer();
		bool flag2 = !flag && c.IsBoss();
		if (!(flag ? EnemyHealthNumbersPlugin.ShowOnPlayers.Value : (flag2 ? EnemyHealthNumbersPlugin.ShowOnBosses.Value : EnemyHealthNumbersPlugin.ShowOnEnemies.Value)))
		{
			return null;
		}
		object? value = _fName.GetValue(hud);
		TextMeshProUGUI val = (TextMeshProUGUI)((value is TextMeshProUGUI) ? value : null);
		object? value2 = _fGui.GetValue(hud);
		GameObject val2 = (GameObject)((value2 is GameObject) ? value2 : null);
		if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
		{
			return null;
		}
		TextMeshProUGUI val3 = Object.Instantiate<TextMeshProUGUI>(val, ((TMP_Text)val).transform.parent);
		((Object)val3).name = "EHN_HealthText";
		((TMP_Text)val3).enableAutoSizing = false;
		((TMP_Text)val3).richText = false;
		((TMP_Text)val3).textWrappingMode = (TextWrappingModes)0;
		((TMP_Text)val3).overflowMode = (TextOverflowModes)0;
		((TMP_Text)val3).alignment = (TextAlignmentOptions)514;
		((Graphic)val3).color = EnemyHealthNumbersPlugin.TextColor.Value;
		((TMP_Text)val3).text = "";
		RectTransform rectTransform = ((TMP_Text)val3).rectTransform;
		float num = (flag2 ? EnemyHealthNumbersPlugin.BossOffsetY.Value : (flag ? EnemyHealthNumbersPlugin.PlayerOffsetY.Value : EnemyHealthNumbersPlugin.EnemyOffsetY.Value));
		rectTransform.anchoredPosition = new Vector2(((TMP_Text)val).rectTransform.anchoredPosition.x + EnemyHealthNumbersPlugin.OffsetX.Value, num);
		((Transform)rectTransform).SetAsLastSibling();
		Entry entry = new Entry();
		entry.Text = val3;
		entry.Character = c;
		entry.IsBoss = flag2;
		return entry;
	}

	private static void Blank(Entry entry)
	{
		if (!entry.Blanked && (Object)(object)entry.Text != (Object)null)
		{
			((TMP_Text)entry.Text).text = "";
			entry.Blanked = true;
			entry.LastHealth = -1;
		}
	}

	private static void Refresh(Entry entry)
	{
		int num = Mathf.CeilToInt(entry.Character.GetHealth());
		int num2 = Mathf.CeilToInt(entry.Character.GetMaxHealth());
		EnemyHealthNumbersPlugin.HealthFormat value = EnemyHealthNumbersPlugin.Format.Value;
		int num3 = (entry.IsBoss ? EnemyHealthNumbersPlugin.BossFontSize.Value : EnemyHealthNumbersPlugin.EnemyFontSize.Value);
		if (num3 != entry.LastFontSize)
		{
			((TMP_Text)entry.Text).fontSize = num3;
			entry.LastFontSize = num3;
		}
		if (entry.Blanked || num != entry.LastHealth || num2 != entry.LastMax || value != entry.LastFormat)
		{
			entry.Blanked = false;
			entry.LastHealth = num;
			entry.LastMax = num2;
			entry.LastFormat = value;
			((TMP_Text)entry.Text).text = Compose(num, num2, value);
		}
	}

	private static string Compose(int health, int max, EnemyHealthNumbersPlugin.HealthFormat format)
	{
		int num = ((max > 0) ? Mathf.Clamp(Mathf.RoundToInt(100f * (float)health / (float)max), 0, 100) : 0);
		return format switch
		{
			EnemyHealthNumbersPlugin.HealthFormat.CurrentOnly => health.ToString(), 
			EnemyHealthNumbersPlugin.HealthFormat.Percent => num + "%", 
			EnemyHealthNumbersPlugin.HealthFormat.CurrentMaxAndPercent => health + "/" + max + " (" + num + "%)", 
			_ => health + "/" + max, 
		};
	}
}

plugins/MoreStars.dll

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

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

[BepInPlugin("danpe.MoreStars", "More Stars", "1.0.0")]
public class MoreStarsPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "danpe.MoreStars";

	public const string PluginName = "More Stars";

	public const string PluginVersion = "1.0.0";

	internal static ManualLogSource Log;

	internal static ConfigEntry<int> MaxStarsCfg;

	internal static ConfigEntry<float> ChanceMultiplierCfg;

	internal static ConfigEntry<int> LootCapCfg;

	internal static ConfigEntry<bool> ShowHudStars;

	internal static ConfigEntry<float> HudStarSpacing;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Expected O, but got Unknown
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Expected O, but got Unknown
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Expected O, but got Unknown
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Expected O, but got Unknown
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0137: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		MaxStarsCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Gameplay (host decides)", "Max stars", 4, new ConfigDescription("Highest star count a creature can naturally spawn with. Vanilla is 2. Only spawn sources whose cap is the vanilla 2 stars are raised; creatures that never get stars stay that way.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 9), new object[0]));
		ChanceMultiplierCfg = ((BaseUnityPlugin)this).Config.Bind<float>("Gameplay (host decides)", "Star chance multiplier", 1f, new ConfigDescription("Multiplies the chance of every extra-star roll, on top of the world's enemyleveluprate. Each star is a separate roll at 10% x enemyleveluprate/100 x this. With Very Hard (140) and 1.0: 14% one star or more, ~2% two, 0.3% three, 0.04% four. 1.43 on top of Very Hard equals a world rate of 200.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), new object[0]));
		LootCapCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Gameplay (host decides)", "Max loot multiplier", 0, new ConfigDescription("Vanilla multiplies level-scaled drops by 2 per star: x8 at 3 stars, x16 at 4. Set a ceiling here (for example 4 = the 2-star amount). 0 keeps the vanilla formula.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 512), new object[0]));
		ShowHudStars = ((BaseUnityPlugin)this).Config.Bind<bool>("Display (each player)", "Show extra stars on health bars", true, "The game only has icons for 1 and 2 stars; this adds a row for 3 or more.");
		HudStarSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("Display (each player)", "Star spacing override", 0f, new ConfigDescription("Horizontal distance between the extra stars in pixels. 0 = copy the game's own spacing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), new object[0]));
		((BaseUnityPlugin)this).Config.SettingChanged += OnSettingChanged;
		_harmony = new Harmony("danpe.MoreStars");
		try
		{
			Sync.Init();
			Hud.Init();
			_harmony.PatchAll(typeof(MoreStarsPlugin).Assembly);
			Log.LogInfo((object)("More Stars ready: max " + MaxStarsCfg.Value + " stars."));
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Setup failed - creatures keep the vanilla 2-star cap. " + ex));
			_harmony.UnpatchSelf();
		}
	}

	private void OnSettingChanged(object sender, SettingChangedEventArgs e)
	{
		Sync.BroadcastIfServer();
	}

	private void OnDestroy()
	{
		((BaseUnityPlugin)this).Config.SettingChanged -= OnSettingChanged;
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}
}
internal static class Sync
{
	private const string RpcRequest = "MoreStars_Request";

	private const string RpcConfig = "MoreStars_Config";

	private static MethodInfo _getServerPeerId;

	private static ZRoutedRpc _registeredOn;

	private static bool _haveRemote;

	private static int _remoteMaxStars;

	private static float _remoteMultiplier;

	private static int _remoteLootCap;

	private static bool UseRemote
	{
		get
		{
			if (_haveRemote && (Object)(object)ZNet.instance != (Object)null)
			{
				return !ZNet.instance.IsServer();
			}
			return false;
		}
	}

	internal static int MaxLevel => (UseRemote ? _remoteMaxStars : MoreStarsPlugin.MaxStarsCfg.Value) + 1;

	internal static float ChanceMultiplier
	{
		get
		{
			if (!UseRemote)
			{
				return MoreStarsPlugin.ChanceMultiplierCfg.Value;
			}
			return _remoteMultiplier;
		}
	}

	internal static int LootCap
	{
		get
		{
			if (!UseRemote)
			{
				return MoreStarsPlugin.LootCapCfg.Value;
			}
			return _remoteLootCap;
		}
	}

	internal static void Init()
	{
		_getServerPeerId = AccessTools.Method(typeof(ZRoutedRpc), "GetServerPeerID", (Type[])null, (Type[])null);
	}

	internal static void Register()
	{
		ZRoutedRpc instance = ZRoutedRpc.instance;
		if (instance != null && _registeredOn != instance)
		{
			_haveRemote = false;
			instance.Register("MoreStars_Request", (Action<long>)OnRequest);
			instance.Register<string>("MoreStars_Config", (Action<long, string>)OnConfig);
			_registeredOn = instance;
		}
	}

	private static string Payload()
	{
		return MoreStarsPlugin.MaxStarsCfg.Value.ToString(CultureInfo.InvariantCulture) + ";" + MoreStarsPlugin.ChanceMultiplierCfg.Value.ToString(CultureInfo.InvariantCulture) + ";" + MoreStarsPlugin.LootCapCfg.Value.ToString(CultureInfo.InvariantCulture);
	}

	internal static void RequestFromServer()
	{
		if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer() && ZRoutedRpc.instance != null)
		{
			ZRoutedRpc.instance.InvokeRoutedRPC("MoreStars_Request", new object[0]);
		}
	}

	internal static void BroadcastIfServer()
	{
		if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && ZRoutedRpc.instance != null)
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, "MoreStars_Config", new object[1] { Payload() });
		}
	}

	private static void OnRequest(long sender)
	{
		if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && ZRoutedRpc.instance != null)
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(sender, "MoreStars_Config", new object[1] { Payload() });
		}
	}

	private static void OnConfig(long sender, string payload)
	{
		try
		{
			if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer() || _getServerPeerId == null || ZRoutedRpc.instance == null)
			{
				return;
			}
			object obj = _getServerPeerId.Invoke(ZRoutedRpc.instance, null);
			if (obj is long && (long)obj == sender)
			{
				string[] array = (payload ?? "").Split(new char[1] { ';' });
				if (array.Length >= 3 && int.TryParse(array[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && int.TryParse(array[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result3))
				{
					_remoteMaxStars = Mathf.Clamp(result, 2, 9);
					_remoteMultiplier = Mathf.Clamp(result2, 0.1f, 10f);
					_remoteLootCap = Mathf.Clamp(result3, 0, 512);
					_haveRemote = true;
					MoreStarsPlugin.Log.LogInfo((object)("Using the host's settings: max " + _remoteMaxStars + " stars, chance x" + _remoteMultiplier + ", loot cap " + ((_remoteLootCap == 0) ? "vanilla" : ("x" + _remoteLootCap)) + "."));
				}
			}
		}
		catch (Exception ex)
		{
			MoreStarsPlugin.Log.LogWarning((object)("Could not read the host's settings: " + ex.Message));
		}
	}
}
[HarmonyPatch]
public static class SpawnPatches
{
	private const int VanillaCap = 3;

	private static bool Lift(ref int maxLevel)
	{
		int maxLevel2 = Sync.MaxLevel;
		if (maxLevel == 3 && maxLevel2 > 3)
		{
			maxLevel = maxLevel2;
			return true;
		}
		return false;
	}

	[HarmonyPatch(typeof(SpawnSystem), "Spawn")]
	[HarmonyPrefix]
	public static void SpawnSystemPrefix(SpawnData critter, out bool __state)
	{
		__state = critter != null && Lift(ref critter.m_maxLevel);
	}

	[HarmonyFinalizer]
	[HarmonyPatch(typeof(SpawnSystem), "Spawn")]
	public static void SpawnSystemFinalizer(SpawnData critter, bool __state)
	{
		if (__state && critter != null)
		{
			critter.m_maxLevel = 3;
		}
	}

	[HarmonyPatch(typeof(SpawnArea), "SpawnOne")]
	[HarmonyPrefix]
	public static void SpawnAreaPrefix(SpawnArea __instance, out List<SpawnData> __state)
	{
		__state = null;
		if ((Object)(object)__instance == (Object)null || __instance.m_prefabs == null)
		{
			return;
		}
		foreach (SpawnData prefab in __instance.m_prefabs)
		{
			if (prefab != null && Lift(ref prefab.m_maxLevel))
			{
				if (__state == null)
				{
					__state = new List<SpawnData>();
				}
				__state.Add(prefab);
			}
		}
	}

	[HarmonyFinalizer]
	[HarmonyPatch(typeof(SpawnArea), "SpawnOne")]
	public static void SpawnAreaFinalizer(List<SpawnData> __state)
	{
		if (__state == null)
		{
			return;
		}
		foreach (SpawnData item in __state)
		{
			item.m_maxLevel = 3;
		}
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(CreatureSpawner), "Spawn")]
	public static void CreatureSpawnerPrefix(CreatureSpawner __instance, out bool __state)
	{
		__state = (Object)(object)__instance != (Object)null && Lift(ref __instance.m_maxLevel);
	}

	[HarmonyPatch(typeof(CreatureSpawner), "Spawn")]
	[HarmonyFinalizer]
	public static void CreatureSpawnerFinalizer(CreatureSpawner __instance, bool __state)
	{
		if (__state && (Object)(object)__instance != (Object)null)
		{
			__instance.m_maxLevel = 3;
		}
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(TriggerSpawner), "Spawn")]
	public static void TriggerSpawnerPrefix(TriggerSpawner __instance, out float __state)
	{
		__state = float.NaN;
		if (!((Object)(object)__instance == (Object)null) && Lift(ref __instance.m_maxLevel))
		{
			__state = __instance.m_levelupChance;
			__instance.m_levelupChance *= Sync.ChanceMultiplier;
		}
	}

	[HarmonyFinalizer]
	[HarmonyPatch(typeof(TriggerSpawner), "Spawn")]
	public static void TriggerSpawnerFinalizer(TriggerSpawner __instance, float __state)
	{
		if (!float.IsNaN(__state) && (Object)(object)__instance != (Object)null)
		{
			__instance.m_maxLevel = 3;
			__instance.m_levelupChance = __state;
		}
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(SpawnSystem), "GetLevelUpChance", new Type[]
	{
		typeof(Vector3),
		typeof(float)
	})]
	public static void SpawnSystemChancePostfix(ref float __result)
	{
		__result *= Sync.ChanceMultiplier;
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(SpawnArea), "GetLevelUpChance")]
	public static void SpawnAreaChancePostfix(ref float __result)
	{
		__result *= Sync.ChanceMultiplier;
	}
}
[HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")]
public static class LootPatch
{
	public static int Cap(int multiplier)
	{
		int lootCap = Sync.LootCap;
		if (lootCap <= 0 || multiplier <= lootCap)
		{
			return multiplier;
		}
		return lootCap;
	}

	public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
	{
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Expected O, but got Unknown
		List<CodeInstruction> list = new List<CodeInstruction>(instructions);
		MethodInfo methodInfo = AccessTools.Method(typeof(Mathf), "Pow", new Type[2]
		{
			typeof(float),
			typeof(float)
		}, (Type[])null);
		MethodInfo methodInfo2 = AccessTools.Method(typeof(Mathf), "Max", new Type[2]
		{
			typeof(int),
			typeof(int)
		}, (Type[])null);
		MethodInfo methodInfo3 = AccessTools.Method(typeof(LootPatch), "Cap", (Type[])null, (Type[])null);
		int num = 0;
		int index = -1;
		for (int i = 0; i + 2 < list.Count; i++)
		{
			if (CodeInstructionExtensions.Calls(list[i], methodInfo) && list[i + 1].opcode == OpCodes.Conv_I4 && CodeInstructionExtensions.Calls(list[i + 2], methodInfo2))
			{
				num++;
				index = i + 3;
			}
		}
		if (num != 1)
		{
			MoreStarsPlugin.Log.LogWarning((object)("Loot multiplier pattern not found (" + num + " matches); the loot cap is inactive."));
			return list;
		}
		list.Insert(index, new CodeInstruction(OpCodes.Call, (object)methodInfo3));
		return list;
	}
}
[HarmonyPatch(typeof(LevelEffects), "SetupLevelVisualization")]
public static class LooksPatch
{
	public static void Prefix(ref int level, IList ___m_levelSetups)
	{
		if (___m_levelSetups != null && ___m_levelSetups.Count > 0 && level - 1 > ___m_levelSetups.Count)
		{
			level = ___m_levelSetups.Count + 1;
		}
	}
}
[HarmonyPatch]
public static class NetPatches
{
	[HarmonyPostfix]
	[HarmonyPatch(typeof(ZNet), "Awake")]
	public static void ZNetAwakePostfix()
	{
		try
		{
			Sync.Register();
		}
		catch (Exception ex)
		{
			MoreStarsPlugin.Log.LogError((object)("Could not register RPCs: " + ex));
		}
	}

	[HarmonyPatch(typeof(Player), "OnSpawned")]
	[HarmonyPostfix]
	public static void PlayerOnSpawnedPostfix(Player __instance)
	{
		try
		{
			if ((Object)(object)__instance != (Object)null && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				Sync.RequestFromServer();
			}
		}
		catch (Exception ex)
		{
			MoreStarsPlugin.Log.LogWarning((object)("Could not ask the host for its settings: " + ex.Message));
		}
	}
}
[HarmonyPatch(typeof(EnemyHud), "UpdateHuds")]
public static class Hud
{
	private const string RowPrefix = "MoreStars_row_";

	private static FieldInfo _fCharacter;

	private static FieldInfo _fLevel2;

	private static FieldInfo _fLevel3;

	private static bool _loggedLayout;

	private static bool _failed;

	internal static void Init()
	{
		Type type = AccessTools.Inner(typeof(EnemyHud), "HudData");
		if (type == null)
		{
			throw new InvalidOperationException("EnemyHud.HudData not found");
		}
		_fCharacter = AccessTools.Field(type, "m_character");
		_fLevel2 = AccessTools.Field(type, "m_level2");
		_fLevel3 = AccessTools.Field(type, "m_level3");
		if (_fCharacter == null || _fLevel2 == null || _fLevel3 == null)
		{
			throw new InvalidOperationException("EnemyHud.HudData fields not found");
		}
	}

	public static void Postfix(object ___m_huds)
	{
		if (_failed || !(___m_huds is IDictionary dictionary))
		{
			return;
		}
		try
		{
			foreach (object value4 in dictionary.Values)
			{
				if (value4 == null)
				{
					continue;
				}
				object? value = _fCharacter.GetValue(value4);
				Character val = (Character)((value is Character) ? value : null);
				object? value2 = _fLevel3.GetValue(value4);
				RectTransform val2 = (RectTransform)((value2 is RectTransform) ? value2 : null);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null))
				{
					int num = val.GetLevel() - 1;
					Transform parent = ((Transform)val2).parent;
					Transform val3 = FindRow(parent);
					bool flag = MoreStarsPlugin.ShowHudStars.Value && num > 2;
					if ((Object)(object)val3 != (Object)null && (!flag || ((Object)val3).name != "MoreStars_row_" + num))
					{
						Object.Destroy((Object)(object)((Component)val3).gameObject);
						val3 = null;
					}
					if (flag && (Object)(object)val3 == (Object)null)
					{
						object? value3 = _fLevel2.GetValue(value4);
						val3 = Build(val2, (RectTransform)((value3 is RectTransform) ? value3 : null), num);
					}
					if ((Object)(object)val3 != (Object)null && !((Component)val3).gameObject.activeSelf)
					{
						((Component)val3).gameObject.SetActive(true);
					}
				}
			}
		}
		catch (Exception ex)
		{
			_failed = true;
			MoreStarsPlugin.Log.LogError((object)("Extra HUD stars disabled for this session after an error: " + ex));
		}
	}

	private static Transform FindRow(Transform parent)
	{
		if ((Object)(object)parent == (Object)null)
		{
			return null;
		}
		for (int i = 0; i < parent.childCount; i++)
		{
			Transform child = parent.GetChild(i);
			if (((Object)child).name.StartsWith("MoreStars_row_"))
			{
				return child;
			}
		}
		return null;
	}

	private static Transform Build(RectTransform level3, RectTransform level2, int stars)
	{
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: 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_016e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Expected O, but got Unknown
		//IL_018f: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e9: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: 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_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0251: Unknown result type (might be due to invalid IL or missing references)
		//IL_0268: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Object.Instantiate<GameObject>(((Component)level3).gameObject, ((Transform)level3).parent);
		((Object)val).name = "MoreStars_row_" + stars;
		List<RectTransform> list = new List<RectTransform>();
		for (int i = 0; i < val.transform.childCount; i++)
		{
			Transform child = val.transform.GetChild(i);
			RectTransform val2 = (RectTransform)(object)((child is RectTransform) ? child : null);
			if ((Object)(object)val2 != (Object)null)
			{
				list.Add(val2);
			}
		}
		if (list.Count >= 2)
		{
			Vector2 val3 = list[1].anchoredPosition - list[0].anchoredPosition;
			if (MoreStarsPlugin.HudStarSpacing.Value > 0f)
			{
				((Vector2)(ref val3))..ctor(MoreStarsPlugin.HudStarSpacing.Value, 0f);
			}
			RectTransform val4 = list[list.Count - 1];
			for (int j = list.Count; j < stars; j++)
			{
				RectTransform component = Object.Instantiate<GameObject>(((Component)val4).gameObject, val.transform).GetComponent<RectTransform>();
				component.anchoredPosition = list[0].anchoredPosition + val3 * (float)j;
			}
			LogLayout("copied the 2-star row, step " + val3);
			return val.transform;
		}
		Object.Destroy((Object)(object)val);
		if ((Object)(object)level2 == (Object)null)
		{
			return null;
		}
		GameObject val5 = new GameObject("MoreStars_row_" + stars, new Type[1] { typeof(RectTransform) });
		RectTransform component2 = val5.GetComponent<RectTransform>();
		((Transform)component2).SetParent(((Transform)level2).parent, false);
		component2.anchorMin = level2.anchorMin;
		component2.anchorMax = level2.anchorMax;
		component2.pivot = level2.pivot;
		component2.anchoredPosition = level2.anchoredPosition;
		component2.sizeDelta = level2.sizeDelta;
		float num;
		if (!(MoreStarsPlugin.HudStarSpacing.Value > 0f))
		{
			Rect rect = level2.rect;
			num = Mathf.Max(8f, ((Rect)(ref rect)).width);
		}
		else
		{
			num = MoreStarsPlugin.HudStarSpacing.Value;
		}
		float num2 = num;
		for (int k = 0; k < stars; k++)
		{
			GameObject val6 = Object.Instantiate<GameObject>(((Component)level2).gameObject, val5.transform);
			val6.SetActive(true);
			RectTransform component3 = val6.GetComponent<RectTransform>();
			component3.anchorMin = new Vector2(0.5f, 0.5f);
			component3.anchorMax = new Vector2(0.5f, 0.5f);
			component3.anchoredPosition = new Vector2(num2 * (float)k, 0f);
		}
		LogLayout("built from the 1-star icon, step " + num2);
		return val5.transform;
	}

	private static void LogLayout(string how)
	{
		if (!_loggedLayout)
		{
			_loggedLayout = true;
			MoreStarsPlugin.Log.LogInfo((object)("Extra HUD stars: " + how + "."));
		}
	}
}