Decompiled source of Building Tweaks v1.0.2

DigiBuilding.dll

Decompiled 14 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using BuildRestrictions;
using DigiCore;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using LevelStrength;
using Microsoft.CodeAnalysis;
using NoWeatherDamage;
using RepairNearby;
using RoofSwap;
using RugLift;
using StationExtensionRange;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("DigiBuilding")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("DigiBuilding")]
[assembly: AssemblyTitle("DigiBuilding")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
internal static class SettingOrder
{
	internal sealed class ConfigurationManagerAttributes
	{
		public int? Order;
	}

	internal static void Apply(ConfigFile config)
	{
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Expected O, but got Unknown
		FieldInfo fieldInfo = AccessTools.Field(typeof(ConfigEntryBase), "<Description>k__BackingField");
		if (fieldInfo == null)
		{
			return;
		}
		int num = 1000;
		foreach (ConfigDefinition item in config.Keys.ToList())
		{
			ConfigEntryBase val = config[item];
			ConfigDescription description = val.Description;
			object[] array = ((description != null) ? description.Tags : null) ?? new object[0];
			object obj = array.FirstOrDefault((object t) => t != null && t.GetType().Name == "ConfigurationManagerAttributes");
			if (obj != null)
			{
				FieldInfo fieldInfo2 = AccessTools.Field(obj.GetType(), "Order");
				if (fieldInfo2 != null && fieldInfo2.GetValue(obj) == null)
				{
					fieldInfo2.SetValue(obj, num);
				}
			}
			else
			{
				fieldInfo.SetValue(val, (object?)new ConfigDescription(((description != null) ? description.Description : null) ?? "", (description != null) ? description.AcceptableValues : null, array.Concat(new object[1]
				{
					new ConfigurationManagerAttributes
					{
						Order = num
					}
				}).ToArray()));
			}
			num--;
		}
	}
}
namespace DigiCore
{
	public sealed class ModuleInfo
	{
		public readonly Type Type;

		public readonly string Title;

		public readonly string OldGuid;

		public readonly string Description;

		public readonly string[] Requires;

		public readonly bool DefaultOn;

		public ModuleInfo(Type type, string title, string oldGuid, string description, string[] requires = null, bool defaultOn = true)
		{
			Type = type;
			Title = title;
			OldGuid = oldGuid;
			Description = description;
			Requires = requires ?? new string[0];
			DefaultOn = defaultOn;
		}
	}
	public abstract class DigiPlugin : BaseUnityPlugin
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static Func<string, string> <>9__11_0;

			public static Func<string, bool> <>9__11_1;

			public static Func<string, bool> <>9__11_2;

			public static Func<string, string> <>9__11_3;

			public static Func<string, string[]> <>9__18_0;

			public static Func<string[], string> <>9__18_1;

			public static Func<string[], string> <>9__18_4;

			public static Func<IGrouping<string, string[]>, string> <>9__18_2;

			public static PopupButtonCallback <>9__18_3;

			public static Func<string, bool> <>9__22_0;

			internal string <Awake>b__11_0(string l)
			{
				return l.Trim();
			}

			internal bool <Awake>b__11_1(string l)
			{
				return l.Length > 0;
			}

			internal bool <Awake>b__11_2(string r)
			{
				return !Chainloader.PluginInfos.ContainsKey(r);
			}

			internal string <Awake>b__11_3(string r)
			{
				if (!RequirementNames.TryGetValue(r, out var value))
				{
					return r;
				}
				return value;
			}

			internal string[] <ShowDuplicates>b__18_0(string d)
			{
				return d.Split(new char[1] { '|' });
			}

			internal string <ShowDuplicates>b__18_1(string[] d)
			{
				return d[0];
			}

			internal string <ShowDuplicates>b__18_2(IGrouping<string, string[]> g)
			{
				return "<b>" + g.Key + ":</b> " + string.Join(", ", g.Select((string[] d) => d[1]));
			}

			internal string <ShowDuplicates>b__18_4(string[] d)
			{
				return d[1];
			}

			internal void <ShowDuplicates>b__18_3()
			{
				UnifiedPopup.Pop();
			}

			internal bool <Apply>b__22_0(string r)
			{
				return !Chainloader.PluginInfos.ContainsKey(r);
			}
		}

		public const string ModulesSection = "0 - Sub-mods";

		internal static DigiPlugin StartingHost;

		internal static ModuleInfo StartingModule;

		private static readonly Dictionary<string, string> RequirementNames = new Dictionary<string, string>
		{
			{ "randyknapp.mods.epicloot", "Epic Loot" },
			{ "com.jotunn.jotunn", "Jotunn" },
			{ "ValheimLegends", "Valheim Legends" },
			{ "vapok.mods.adventurebackpacks", "Adventure Backpacks" },
			{ "MidnightsFX.StarLevelSystem", "Star Level System" },
			{ "sosal.nordicrugs", "Nordic Rugs" },
			{ "LuminairPrime.valheim.localcraftfromstorageprime", "Local Craft From Storage Prime" }
		};

		private readonly Dictionary<ModuleInfo, DigiModule> _running = new Dictionary<ModuleInfo, DigiModule>();

		private readonly Dictionary<ModuleInfo, ConfigEntry<bool>> _switches = new Dictionary<ModuleInfo, ConfigEntry<bool>>();

		private HashSet<string> _migrated;

		private const string DuplicatesKey = "digi.valheim.duplicates";

		private const string DuplicatesShownKey = "digi.valheim.duplicates.shown";

		protected abstract ModuleInfo[] Modules { get; }

		private string MigratedFile => Path.Combine(Paths.ConfigPath, ((BaseUnityPlugin)this).Info.Metadata.GUID + ".migrated.txt");

		private static List<string> Duplicates
		{
			get
			{
				List<string> list = AppDomain.CurrentDomain.GetData("digi.valheim.duplicates") as List<string>;
				if (list == null)
				{
					list = new List<string>();
					AppDomain.CurrentDomain.SetData("digi.valheim.duplicates", list);
				}
				return list;
			}
		}

		protected virtual void Awake()
		{
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
			((BaseUnityPlugin)this).Config.Save();
			_migrated = (File.Exists(MigratedFile) ? new HashSet<string>(from l in File.ReadAllLines(MigratedFile)
				select l.Trim() into l
				where l.Length > 0
				select l) : new HashSet<string>());
			bool flag = !_migrated.Contains("#switches");
			ModuleInfo[] modules = Modules;
			foreach (ModuleInfo moduleInfo in modules)
			{
				List<string> list = moduleInfo.Requires.Where((string r) => !Chainloader.PluginInfos.ContainsKey(r)).ToList();
				string value;
				string text = ((moduleInfo.Requires.Length == 0) ? "" : (" Needs " + string.Join(" and ", moduleInfo.Requires.Select((string r) => (!RequirementNames.TryGetValue(r, out value)) ? r : value)) + "."));
				ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Sub-mods", moduleInfo.Title, moduleInfo.DefaultOn, moduleInfo.Description + text);
				if (flag && !moduleInfo.DefaultOn && File.Exists(OldConfigPath(moduleInfo)))
				{
					val.Value = true;
				}
				_switches[moduleInfo] = val;
				ModuleInfo captured = moduleInfo;
				val.SettingChanged += delegate
				{
					Apply(captured);
				};
				if (list.Count > 0)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)(moduleInfo.Title + ": off, needs " + string.Join(", ", list) + "."));
				}
			}
			if (flag)
			{
				Remember("#switches");
			}
			modules = Modules;
			foreach (ModuleInfo module in modules)
			{
				Apply(module);
			}
		}

		private void Start()
		{
			foreach (KeyValuePair<ModuleInfo, DigiModule> item in _running.ToList())
			{
				if (!((Object)(object)item.Value == (Object)null) && Chainloader.PluginInfos.ContainsKey(item.Key.OldGuid))
				{
					item.Value.Teardown();
					_running.Remove(item.Key);
					Forget(item.Key.OldGuid);
					ReportDuplicate(item.Key);
				}
			}
			SettingOrder.Apply(((BaseUnityPlugin)this).Config);
			if (Duplicates.Count > 0 && !Application.isBatchMode)
			{
				((MonoBehaviour)this).StartCoroutine(ShowDuplicates());
			}
		}

		private void ReportDuplicate(ModuleInfo module)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)(module.Title + ": not started, because the separate mod (" + module.OldGuid + ") is installed too. Remove that one."));
			string item = ((BaseUnityPlugin)this).Info.Metadata.Name.Replace("Digi's ", "") + "|" + module.Title;
			if (!Duplicates.Contains(item))
			{
				Duplicates.Add(item);
			}
		}

		private IEnumerator ShowDuplicates()
		{
			while ((Object)(object)FejdStartup.instance == (Object)null || !UnifiedPopup.IsAvailable())
			{
				yield return (object)new WaitForSeconds(0.5f);
			}
			yield return (object)new WaitForSeconds(1f);
			if (AppDomain.CurrentDomain.GetData("digi.valheim.duplicates.shown") != null)
			{
				yield break;
			}
			AppDomain.CurrentDomain.SetData("digi.valheim.duplicates.shown", true);
			IEnumerable<string> values = from d in Duplicates
				select d.Split(new char[1] { '|' }) into d
				group d by d[0] into g
				select "<b>" + g.Key + ":</b> " + string.Join(", ", g.Select((string[] d) => d[1]));
			string text = "These mods are installed twice: on their own and inside one of our combined mods.\n\n" + string.Join("\n", values) + "\n\nThe copy in the combined mod stays off until you remove the separate ones in your mod manager (or make a new profile with Digi Modpack). Your settings are copied over.";
			object obj = <>c.<>9__18_3;
			if (obj == null)
			{
				PopupButtonCallback val = delegate
				{
					UnifiedPopup.Pop();
				};
				<>c.<>9__18_3 = val;
				obj = (object)val;
			}
			UnifiedPopup.Push((PopupBase)new WarningPopup("DigiTeam mods installed twice", text, (PopupButtonCallback)obj, false));
		}

		private static string OldConfigPath(ModuleInfo module)
		{
			return Path.Combine(Paths.ConfigPath, module.OldGuid + ".cfg");
		}

		private void Remember(string key)
		{
			if (!_migrated.Add(key))
			{
				return;
			}
			try
			{
				File.AppendAllText(MigratedFile, key + Environment.NewLine);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not write " + MigratedFile + ": " + ex.Message));
			}
		}

		private void Forget(string key)
		{
			if (!_migrated.Remove(key))
			{
				return;
			}
			try
			{
				File.WriteAllLines(MigratedFile, _migrated.ToArray());
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not write " + MigratedFile + ": " + ex.Message));
			}
		}

		private void Apply(ModuleInfo module)
		{
			bool value = _switches[module].Value;
			_running.TryGetValue(module, out var value2);
			if (value && (Object)(object)value2 == (Object)null)
			{
				if (!module.Requires.Any((string r) => !Chainloader.PluginInfos.ContainsKey(r)))
				{
					if (Chainloader.PluginInfos.ContainsKey(module.OldGuid))
					{
						ReportDuplicate(module);
					}
					else
					{
						StartModule(module);
					}
				}
			}
			else if (!value && (Object)(object)value2 != (Object)null)
			{
				value2.Teardown();
				_running.Remove(module);
				((BaseUnityPlugin)this).Logger.LogInfo((object)(module.Title + ": switched off."));
			}
		}

		private void StartModule(ModuleInfo module)
		{
			StartingHost = this;
			StartingModule = module;
			try
			{
				DigiModule digiModule = (DigiModule)(object)((Component)this).gameObject.AddComponent(module.Type);
				digiModule.Host = this;
				digiModule.Info2 = module;
				_running[module] = digiModule;
				MigrateOldSettings(module, digiModule);
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"{module.Title} could not start: {arg}");
			}
			finally
			{
				StartingHost = null;
				StartingModule = null;
			}
			SettingOrder.Apply(((BaseUnityPlugin)this).Config);
		}

		private void MigrateOldSettings(ModuleInfo module, DigiModule component)
		{
			if (_migrated.Contains(module.OldGuid))
			{
				return;
			}
			string path = OldConfigPath(module);
			if (File.Exists(path) && component.ConfigOrNull != null)
			{
				Dictionary<string, string> dictionary = ReadCfg(path);
				int num = 0;
				foreach (ModuleConfig.Bound entry in component.ConfigOrNull.Entries)
				{
					if (dictionary.TryGetValue(entry.Section + "\n" + entry.Key, out var value))
					{
						try
						{
							entry.Entry.SetSerializedValue(value);
							num++;
						}
						catch (Exception ex)
						{
							((BaseUnityPlugin)this).Logger.LogWarning((object)(module.Title + ": could not copy '" + entry.Key + "': " + ex.Message));
						}
					}
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"{module.Title}: copied {num} setting(s) from {Path.GetFileName(path)}.");
			}
			Remember(module.OldGuid);
		}

		private static Dictionary<string, string> ReadCfg(string path)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			string text = "";
			string[] array = File.ReadAllLines(path);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length == 0 || text2.StartsWith("#"))
				{
					continue;
				}
				if (text2.StartsWith("[") && text2.EndsWith("]"))
				{
					text = text2.Substring(1, text2.Length - 2);
					continue;
				}
				int num = text2.IndexOf(" = ", StringComparison.Ordinal);
				if (num > 0)
				{
					dictionary[text + "\n" + text2.Substring(0, num).Trim()] = text2.Substring(num + 3);
				}
			}
			return dictionary;
		}

		protected virtual void OnDestroy()
		{
			foreach (DigiModule item in _running.Values.ToList())
			{
				item?.Teardown();
			}
			_running.Clear();
		}

		public bool IsRunning(Type moduleType)
		{
			return _running.Any((KeyValuePair<ModuleInfo, DigiModule> p) => p.Key.Type == moduleType && (Object)(object)p.Value != (Object)null);
		}
	}
	public abstract class DigiModule : MonoBehaviour
	{
		internal DigiPlugin Host;

		internal ModuleInfo Info2;

		private ModuleConfig _config;

		private ManualLogSource _logger;

		private Harmony _harmony;

		internal ModuleConfig ConfigOrNull => _config;

		protected ModuleConfig Config => _config ?? (_config = new ModuleConfig(((BaseUnityPlugin)(Host ?? DigiPlugin.StartingHost)).Config, (Info2 ?? DigiPlugin.StartingModule).Title));

		protected ManualLogSource Logger => _logger ?? (_logger = Logger.CreateLogSource("Digi's " + (Info2 ?? DigiPlugin.StartingModule)?.Title));

		protected Harmony ModuleHarmony
		{
			get
			{
				//IL_003e: 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_0045: Expected O, but got Unknown
				//IL_004a: Expected O, but got Unknown
				Harmony obj = _harmony;
				if (obj == null)
				{
					Harmony val = new Harmony(((object)this).GetType().Namespace?.ToLowerInvariant() + "." + Guid.NewGuid().ToString("N"));
					Harmony val2 = val;
					_harmony = val;
					obj = val2;
				}
				return obj;
			}
		}

		protected Harmony PatchModule(Type type)
		{
			ModuleHarmony.PatchAll(type);
			return ModuleHarmony;
		}

		protected Harmony PatchModuleNamespace()
		{
			string text = ((object)this).GetType().Namespace;
			Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(((object)this).GetType().Assembly);
			foreach (Type type in typesFromAssembly)
			{
				if (type.Namespace == text || (type.Namespace != null && text != null && type.Namespace.StartsWith(text + ".")))
				{
					ModuleHarmony.CreateClassProcessor(type).Patch();
				}
			}
			return ModuleHarmony;
		}

		internal void Teardown()
		{
			try
			{
				Harmony harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Unpatch: " + ex.Message));
			}
			Object.Destroy((Object)(object)this);
		}
	}
	public sealed class ModuleConfig
	{
		public sealed class Bound
		{
			public string Section;

			public string Key;

			public ConfigEntryBase Entry;
		}

		private readonly ConfigFile _file;

		private readonly string _prefix;

		internal readonly List<Bound> Entries = new List<Bound>();

		public ConfigFile File => _file;

		public string ConfigFilePath => _file.ConfigFilePath;

		internal ModuleConfig(ConfigFile file, string title)
		{
			_file = file;
			_prefix = title + " - ";
		}

		public void Reload()
		{
		}

		public void Save()
		{
			_file.Save();
		}

		public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, ConfigDescription configDescription = null)
		{
			ConfigEntry<T> val = _file.Bind<T>(_prefix + section, key, defaultValue, configDescription);
			if (!Entries.Any((Bound b) => b.Section == section && b.Key == key))
			{
				Entries.Add(new Bound
				{
					Section = section,
					Key = key,
					Entry = (ConfigEntryBase)(object)val
				});
			}
			return val;
		}

		public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, string description)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			return Bind(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()));
		}

		public ConfigEntry<T> Bind<T>(ConfigDefinition definition, T defaultValue, ConfigDescription configDescription = null)
		{
			return Bind(definition.Section, definition.Key, defaultValue, configDescription);
		}

		public bool TryGetEntry<T>(ConfigDefinition definition, out ConfigEntry<T> entry)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			return _file.TryGetEntry<T>(new ConfigDefinition(_prefix + definition.Section, definition.Key), ref entry);
		}
	}
}
namespace DigiBuilding
{
	[BepInPlugin("digi.valheim.building", "Digi's Building Tweaks", "1.0.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : DigiPlugin
	{
		public const string Guid = "digi.valheim.building";

		public const string Name = "Digi's Building Tweaks";

		public const string Version = "1.0.2";

		protected override ModuleInfo[] Modules { get; } = new ModuleInfo[7]
		{
			new ModuleInfo(typeof(BuildRestrictions.Plugin), "Build Restrictions", "digi.valheim.buildrestrictions", "Choose which building rules apply, set by the host for everyone.", new string[1] { "com.jotunn.jotunn" }),
			new ModuleInfo(typeof(StationExtensionRange.Plugin), "Station Extension Range", "digi.valheim.stationextensionrange", "Station upgrades connect from further away and can stand next to each other."),
			new ModuleInfo(typeof(NoWeatherDamage.Plugin), "No Weather Damage", "digi.valheim.noweatherdamage", "No rain damage on your buildings, and docks don't rot in water."),
			new ModuleInfo(typeof(RepairNearby.Plugin), "Repair Nearby", "digi.valheim.repairnearby", "Press Keypad + to repair every damaged building piece around you."),
			new ModuleInfo(typeof(RoofSwap.Plugin), "Roof Swap", "digi.valheim.roofswap", "Swap thatch roofs to darkwood shingles in one click.", new string[1] { "com.jotunn.jotunn" }),
			new ModuleInfo(typeof(RugLift.Plugin), "Rug Lift", "digi.valheim.ruglift", "Nordic Rugs stop clipping into stone floors, and can hang on walls.", new string[2] { "com.jotunn.jotunn", "sosal.nordicrugs" }),
			new ModuleInfo(typeof(LevelStrength.Plugin), "Level Strength", "digi.valheim.levelstrength", "Makes the hoe's Level ground actually flatten the whole area.", new string[1] { "com.jotunn.jotunn" })
		};
	}
}
namespace StationExtensionRange
{
	public class Plugin : DigiModule
	{
		public const string Guid = "digi.valheim.stationextensionrange";

		public const string Name = "Digi's Station Extension Range";

		public const string Version = "1.0.1";

		private const float VanillaDistance = 5f;

		private const string PerStation = "Per station";

		private static Plugin _instance;

		private static ConfigEntry<bool> _enabled;

		private static ConfigEntry<bool> _allowClose;

		private static ConfigEntry<float> _distance;

		private static readonly Dictionary<string, ConfigEntry<float>> StationDistance = new Dictionary<string, ConfigEntry<float>>();

		private static readonly FieldRef<List<StationExtension>> AllExtensions = AccessTools.StaticFieldRefAccess<List<StationExtension>>(AccessTools.Field(typeof(StationExtension), "m_allExtensions"));

		private void MigrateConfig()
		{
			string text = Path.Combine(Paths.ConfigPath, "digi.valheim.stationextensionrange".Replace("digi.valheim.", "pieter.valheim.") + ".cfg");
			if (!File.Exists(base.Config.ConfigFilePath) && File.Exists(text))
			{
				File.Copy(text, base.Config.ConfigFilePath);
				base.Config.Reload();
			}
		}

		private void Awake()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			_instance = this;
			MigrateConfig();
			_enabled = base.Config.Bind("General", "Enabled", defaultValue: true, "Turn the mod on or off.");
			_distance = base.Config.Bind("General", "Connection distance (m)", 30f, new ConfigDescription("How far a station upgrade (chopping block, tanning rack, forge bellows, ...) can be from its crafting station, in meters. Normal is 5. Stations with their own distance under \"Per station\" use that instead.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			_allowClose = base.Config.Bind("General", "Allow extensions next to each other", defaultValue: true, "Upgrades of the same kind can be built close together (normally blocked).");
			_enabled.SettingChanged += delegate
			{
				ApplyAll();
			};
			_distance.SettingChanged += delegate
			{
				ApplyAll();
			};
			PatchModule(typeof(Plugin));
		}

		private static float DistanceFor(StationExtension extension)
		{
			if (!_enabled.Value)
			{
				return 5f;
			}
			string text = (((Object)(object)extension.m_craftingStation != (Object)null) ? extension.m_craftingStation.m_name : null);
			if (text != null && StationDistance.TryGetValue(text, out var value) && value.Value > 0f)
			{
				return value.Value;
			}
			return _distance.Value;
		}

		private static void ApplyAll()
		{
			List<StationExtension> list = AllExtensions.Invoke();
			if (list == null)
			{
				return;
			}
			foreach (StationExtension item in list)
			{
				if ((Object)(object)item != (Object)null)
				{
					item.m_maxStationDistance = DistanceFor(item);
				}
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		[HarmonyPostfix]
		private static void SceneAwake(ZNetScene __instance)
		{
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Expected O, but got Unknown
			bool flag = false;
			foreach (GameObject prefab in __instance.m_prefabs)
			{
				StationExtension val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<StationExtension>() : null);
				CraftingStation val2 = (((Object)(object)val != (Object)null) ? val.m_craftingStation : null);
				if (!((Object)(object)val2 == (Object)null) && !string.IsNullOrEmpty(val2.m_name) && !StationDistance.ContainsKey(val2.m_name))
				{
					string text = ((Localization.instance != null) ? Localization.instance.Localize(val2.m_name) : val2.m_name);
					ConfigEntry<float> val3 = _instance.Config.Bind("Per station", text + " (m)", 0f, new ConfigDescription("Own connection distance for " + text + " upgrades, in meters. 0 = use the general distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
					val3.SettingChanged += delegate
					{
						ApplyAll();
					};
					StationDistance[val2.m_name] = val3;
					flag = true;
				}
			}
			if (flag)
			{
				SettingOrder.Apply(_instance.Config.File);
			}
		}

		[HarmonyPatch(typeof(StationExtension), "Awake")]
		[HarmonyPrefix]
		private static void ExtensionAwake(StationExtension __instance)
		{
			__instance.m_maxStationDistance = DistanceFor(__instance);
		}

		[HarmonyPatch(typeof(StationExtension), "OtherExtensionInRange")]
		[HarmonyPostfix]
		private static void OtherExtensionInRange(ref bool __result)
		{
			if (_enabled.Value && _allowClose.Value)
			{
				__result = false;
			}
		}
	}
}
namespace RugLift
{
	public class Plugin : DigiModule
	{
		public const string Guid = "digi.valheim.ruglift";

		public const string Name = "Digi's Rug Lift";

		public const string Version = "1.3.2";

		private const string NordicRugsGuid = "sosal.nordicrugs";

		private const string MeshName = "NordicRugMesh";

		private const string WallSuffix = "_wall";

		private const string SidewaysSuffix = "_wall_side";

		private static ConfigEntry<float> _lift;

		private static ConfigEntry<bool> _wallRugs;

		private static ConfigEntry<bool> _sidewaysRugs;

		private static ConfigEntry<float> _wallGap;

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

		private static readonly FieldRef<Player, GameObject> Ghost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost");

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

		private void MigrateConfig()
		{
			string text = Path.Combine(Paths.ConfigPath, "digi.valheim.ruglift".Replace("digi.valheim.", "pieter.valheim.") + ".cfg");
			if (!File.Exists(base.Config.ConfigFilePath) && File.Exists(text))
			{
				File.Copy(text, base.Config.ConfigFilePath);
				base.Config.Reload();
			}
		}

		private void Awake()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			MigrateConfig();
			_lift = base.Config.Bind("General", "Lift (m)", 0.03f, new ConfigDescription("How far Nordic Rugs float above the floor so stone floors do not poke through, in meters (0.03 = 3 cm, like normal rugs). 0 = off.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.1f), Array.Empty<object>()));
			_wallRugs = base.Config.Bind("Wall rugs", "Add wall versions", defaultValue: true, "Add a \"(wall)\" version of every Nordic rug to the hammer's Furniture tab, to hang on walls. Needs a restart.");
			_sidewaysRugs = base.Config.Bind("Wall rugs", "Add sideways wall versions", defaultValue: true, "Also add a \"(wall, sideways)\" version: the wall rug turned 90 degrees. Needs a restart.");
			_wallGap = base.Config.Bind("Wall rugs", "Gap from wall (m)", 0.03f, new ConfigDescription("How far wall rugs hang from the wall, in meters, so bumpy log walls do not poke through.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.2f), Array.Empty<object>()));
			_lift.SettingChanged += delegate
			{
				Piece[] array = Object.FindObjectsOfType<Piece>();
				for (int i = 0; i < array.Length; i++)
				{
					Apply(array[i]);
				}
			};
			PatchModule(typeof(Plugin));
			if (_wallRugs.Value)
			{
				PrefabManager.OnVanillaPrefabsAvailable += AddWallRugs;
				PieceManager.OnPiecesRegistered += SortRugs;
			}
		}

		[HarmonyPatch(typeof(Piece), "Awake")]
		[HarmonyPostfix]
		private static void PieceAwake(Piece __instance)
		{
			Apply(__instance);
		}

		private static void Apply(Piece piece)
		{
			//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_003f: 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: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)piece == (Object)null) && !((Object)piece).name.Contains("_wall"))
			{
				Transform val = ((Component)piece).transform.Find("NordicRugMesh");
				if (!((Object)(object)val == (Object)null))
				{
					Vector3 localPosition = val.localPosition;
					val.localPosition = new Vector3(localPosition.x, _lift.Value, localPosition.z);
				}
			}
		}

		private void AddWallRugs()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= AddWallRugs;
			if (!(AccessTools.Field(AccessTools.TypeByName("NordicRugs.RugCatalog"), "All")?.GetValue(null) is IEnumerable enumerable))
			{
				base.Logger.LogError((object)"Wall rugs disabled, the Nordic Rugs catalog was not found.");
				return;
			}
			int num = 0;
			foreach (object item in enumerable)
			{
				try
				{
					Traverse obj = Traverse.Create(item);
					string value = obj.Property("PrefabName", (object[])null).GetValue<string>();
					string value2 = obj.Property("NameEn", (object[])null).GetValue<string>();
					bool value3 = obj.Property("Fur", (object[])null).GetValue<bool>();
					IReadOnlyDictionary<string, int> value4 = obj.Property("Recipe", (object[])null).GetValue<IReadOnlyDictionary<string, int>>();
					CustomPiece piece = PieceManager.Instance.GetPiece(value);
					if (!((Object)(object)((piece != null) ? piece.PiecePrefab : null) == (Object)null))
					{
						RugNames[value] = value2;
						if (AddWall(piece.PiecePrefab, value + "_wall", value2 + " (wall)", value3, value4, sideways: false))
						{
							num++;
						}
						if (_sidewaysRugs.Value && AddWall(piece.PiecePrefab, value + "_wall_side", value2 + " (wall, sideways)", value3, value4, sideways: true))
						{
							num++;
						}
					}
				}
				catch (Exception ex)
				{
					base.Logger.LogWarning((object)("Could not add a wall rug: " + ex.Message));
				}
			}
			base.Logger.LogInfo((object)$"Added {num} wall rugs (Furniture).");
		}

		private static void SortRugs()
		{
			PieceTable pieceTable = PieceManager.Instance.GetPieceTable("Hammer");
			if ((Object)(object)pieceTable == (Object)null || RugNames.Count == 0)
			{
				return;
			}
			List<GameObject> pieces = pieceTable.m_pieces;
			int num = pieces.FindIndex(IsRug);
			if (num >= 0)
			{
				List<GameObject> source = pieces.Where(IsRug).ToList();
				pieces.RemoveAll(IsRug);
				source = source.OrderBy<GameObject, string>((GameObject go) => RugNames[BaseName(((Object)go).name)], StringComparer.OrdinalIgnoreCase).ThenBy((GameObject go) => (!((Object)go).name.EndsWith("_wall_side")) ? (((Object)go).name.EndsWith("_wall") ? 1 : 0) : 2).ToList();
				pieces.InsertRange(Math.Min(num, pieces.Count), source);
			}
		}

		private static bool IsRug(GameObject go)
		{
			if ((Object)(object)go != (Object)null)
			{
				return RugNames.ContainsKey(BaseName(((Object)go).name));
			}
			return false;
		}

		private static string BaseName(string name)
		{
			if (!name.EndsWith("_wall_side"))
			{
				if (!name.EndsWith("_wall"))
				{
					return name;
				}
				return name.Substring(0, name.Length - "_wall".Length);
			}
			return name.Substring(0, name.Length - "_wall_side".Length);
		}

		[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
		[HarmonyPostfix]
		private static void AlignToWall(Player __instance)
		{
			//IL_0058: 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_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_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_0085: 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_0090: 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_00a0: 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_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)
			//IL_00c7: 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)
			GameObject val = Ghost.Invoke(__instance);
			if ((Object)(object)val == (Object)null || !val.activeSelf || !((Object)val).name.Contains("_wall"))
			{
				return;
			}
			object[] array = new object[6] { null, null, null, null, null, false };
			if ((bool)PieceRayTest.Invoke(__instance, array))
			{
				Vector3 val2 = (Vector3)array[0];
				Vector3 val3 = (Vector3)array[1];
				if (!(Mathf.Abs(val3.y) > 0.5f))
				{
					Vector3 val4 = new Vector3(val3.x, 0f, val3.z);
					val3 = ((Vector3)(ref val4)).normalized;
					val.transform.rotation = Quaternion.LookRotation(-val3, Vector3.up);
					val.transform.position = val2 + val3 * _wallGap.Value;
				}
			}
		}

		private static bool AddWall(GameObject source, string prefabName, string name, bool fur, IReadOnlyDictionary<string, int> recipe, bool sideways)
		{
			//IL_0015: 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_0021: 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_0041: 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_0058: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			GameObject val = PrefabManager.Instance.CreateClonedPrefab(prefabName, source);
			MakeUpright(val, sideways);
			PieceConfig val2 = new PieceConfig
			{
				Name = name,
				Description = (fur ? "$nr_fur_description" : "$nr_description"),
				PieceTable = "Hammer",
				Category = "Furniture",
				CraftingStation = "piece_workbench"
			};
			foreach (KeyValuePair<string, int> item in recipe)
			{
				val2.AddRequirement(item.Key, item.Value, true);
			}
			return PieceManager.Instance.AddPiece(new CustomPiece(val, false, val2));
		}

		private static void MakeUpright(GameObject wall, bool sideways)
		{
			//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_0034: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_008c: 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_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_0048: 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_0067: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			Transform val = wall.transform.Find("NordicRugMesh");
			if ((Object)(object)val != (Object)null)
			{
				val.localRotation = (sideways ? Quaternion.Euler(0f, 0f, 90f) : Quaternion.identity) * Quaternion.Euler(-90f, 0f, 0f);
				val.localPosition = new Vector3(0f, 0f, -0.005f);
			}
			BoxCollider component = wall.GetComponent<BoxCollider>();
			if ((Object)(object)component != (Object)null)
			{
				Vector3 size = component.size;
				component.size = (sideways ? new Vector3(size.z, size.x, size.y) : new Vector3(size.x, size.z, size.y));
				component.center = new Vector3(0f, 0f, (0f - size.y) / 2f);
			}
		}
	}
}
namespace RoofSwap
{
	public class Plugin : DigiModule
	{
		public const string Guid = "digi.valheim.roofswap";

		public const string Name = "Digi's Roof Swap";

		public const string Version = "1.0.3";

		private const string ToolPrefab = "piece_roofswap";

		private const string ThatchPrefix = "wood_roof";

		private const string ShinglePrefix = "darkwood_roof";

		private static ConfigEntry<KeyboardShortcut> _wholeRoofKey;

		private static ConfigEntry<int> _maxPieces;

		private static ConfigEntry<float> _chestRange;

		private static ManualLogSource _log;

		private static readonly HashSet<Container> Containers = new HashSet<Container>();

		private static readonly MethodInfo CheckAccessMethod = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null);

		private static readonly MethodInfo BuildStamina = AccessTools.Method(typeof(Player), "GetBuildStamina", (Type[])null, (Type[])null);

		private static readonly FieldRef<Player, bool> NoPlacementCost = AccessTools.FieldRefAccess<Player, bool>("m_noPlacementCost");

		private void MigrateConfig()
		{
			string text = Path.Combine(Paths.ConfigPath, "digi.valheim.roofswap".Replace("digi.valheim.", "pieter.valheim.") + ".cfg");
			if (!File.Exists(base.Config.ConfigFilePath) && File.Exists(text))
			{
				File.Copy(text, base.Config.ConfigFilePath);
				base.Config.Reload();
			}
		}

		private void Awake()
		{
			//IL_002b: 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_0074: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			MigrateConfig();
			_log = base.Logger;
			_wholeRoofKey = base.Config.Bind<KeyboardShortcut>("Roof Swap", "Whole roof key", new KeyboardShortcut((KeyCode)304, Array.Empty<KeyCode>()), "Hold this key while clicking with Roof Swap to swap every connected thatch roof piece at once.");
			_maxPieces = base.Config.Bind("Roof Swap", "Max pieces per whole-roof swap", 300, new ConfigDescription("Most pieces one whole-roof swap may change (safety limit).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 2000), Array.Empty<object>()));
			_chestRange = base.Config.Bind("Roof Swap", "Chest range (m)", 50f, new ConfigDescription("Missing materials are taken from chests up to this many meters away.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			PrefabManager.OnVanillaPrefabsAvailable += AddTool;
			PatchModule(typeof(Plugin));
		}

		private void AddTool()
		{
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: 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_012d: 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)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: 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
			PrefabManager.OnVanillaPrefabsAvailable -= AddTool;
			try
			{
				GameObject prefab = PrefabManager.Instance.GetPrefab("Hammer");
				GameObject val = ((prefab != null) ? prefab.GetComponent<ItemDrop>() : null)?.m_itemData?.m_shared?.m_buildPieces?.m_pieces?.FirstOrDefault((Func<GameObject, bool>)((GameObject p) => (Object)(object)p != (Object)null && (p.GetComponent<Piece>()?.m_repairPiece ?? false)));
				GameObject prefab2 = PrefabManager.Instance.GetPrefab("darkwood_roof");
				Piece val2 = ((prefab2 != null) ? prefab2.GetComponent<Piece>() : null);
				if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
				{
					base.Logger.LogError((object)"Roof Swap disabled, the hammer's repair tool or the shingle roof was not found.");
					return;
				}
				GameObject val3 = PrefabManager.Instance.CreateClonedPrefab("piece_roofswap", val);
				Piece component = val3.GetComponent<Piece>();
				component.m_repairPiece = false;
				component.m_removePiece = false;
				PieceConfig val4 = new PieceConfig
				{
					Name = "Roof Swap",
					Description = "Click a thatch roof piece to replace it with shingles (same shape, same spot). " + $"Hold {_wholeRoofKey.Value} to swap the whole connected roof. Costs the shingle recipe; " + "the thatch drops its materials.",
					PieceTable = "Hammer",
					Category = "Building",
					Icon = val2.m_icon
				};
				PieceManager.Instance.AddPiece(new CustomPiece(val3, false, val4));
				base.Logger.LogInfo((object)"Roof Swap added to the hammer.");
			}
			catch (Exception ex)
			{
				base.Logger.LogError((object)("Adding Roof Swap failed: " + ex));
			}
		}

		[HarmonyPatch(typeof(Container), "Awake")]
		[HarmonyPostfix]
		private static void ContainerAwake(Container __instance)
		{
			Containers.Add(__instance);
		}

		[HarmonyPatch(typeof(Player), "TryPlacePiece")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool TryPlacePrefix(Player __instance, Piece piece, ref bool __result)
		{
			if ((Object)(object)piece == (Object)null || Utils.GetPrefabName(((Component)piece).gameObject) != "piece_roofswap")
			{
				return true;
			}
			__result = false;
			try
			{
				Swap(__instance, Traverse.Create((object)__instance).Method("GetRightItem", Array.Empty<object>()).GetValue<ItemData>());
			}
			catch (Exception ex)
			{
				_log.LogError((object)("Roof swap failed: " + ex));
			}
			return false;
		}

		private static void Swap(Player player, ItemData toolItem)
		{
			//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_015e: 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_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_031b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			Piece hoveringPiece = player.GetHoveringPiece();
			if ((Object)(object)hoveringPiece == (Object)null)
			{
				return;
			}
			if ((Object)(object)ShingleFor(hoveringPiece) == (Object)null)
			{
				((Character)player).Message((MessageType)2, "Roof Swap only works on thatch roof pieces", 0, (Sprite)null, false);
				return;
			}
			KeyboardShortcut value = _wholeRoofKey.Value;
			List<Piece> list = (((KeyboardShortcut)(ref value)).IsPressed() ? ConnectedThatch(hoveringPiece) : new List<Piece> { hoveringPiece });
			List<Piece> list2 = list.Where((Piece p) => CanReplace(player, p)).ToList();
			if (list2.Count == 0)
			{
				return;
			}
			Piece val = ShingleFor(list2[0]);
			if (!player.HaveRequirements(val, (RequirementMode)1))
			{
				((Character)player).Message((MessageType)2, "You have not unlocked shingle roofs yet", 0, (Sprite)null, false);
				return;
			}
			if (!NoPlacementCost.Invoke(player) && (Object)(object)val.m_craftingStation != (Object)null && !Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(val.m_craftingStation.m_name, ((Component)player).transform.position)) && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)27))
			{
				((Character)player).Message((MessageType)2, "$msg_missingstation", 0, (Sprite)null, false);
				return;
			}
			bool num = NoPlacementCost.Invoke(player) || ZoneSystem.instance.GetGlobalKey(val.FreeBuildKey());
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			if (!num)
			{
				foreach (Piece item in list2)
				{
					Requirement[] resources = ShingleFor(item).m_resources;
					foreach (Requirement val2 in resources)
					{
						if ((Object)(object)val2?.m_resItem != (Object)null && val2.m_amount > 0)
						{
							string name = val2.m_resItem.m_itemData.m_shared.m_name;
							dictionary.TryGetValue(name, out var value2);
							dictionary[name] = value2 + val2.m_amount;
						}
					}
				}
			}
			List<string> list3 = (from c in dictionary
				where Available(player, c.Key) < c.Value
				select $"{Localization.instance.Localize(c.Key)} {Available(player, c.Key)}/{c.Value}").ToList();
			if (list3.Count > 0)
			{
				((Character)player).Message((MessageType)2, string.Format("Not enough for {0} piece(s): {1}", list2.Count, string.Join(", ", list3)), 0, (Sprite)null, false);
				return;
			}
			foreach (KeyValuePair<string, int> item2 in dictionary)
			{
				Pay(player, item2.Key, item2.Value);
			}
			bool flag = true;
			foreach (Piece item3 in list2)
			{
				Piece val3 = ShingleFor(item3);
				Vector3 position = ((Component)item3).transform.position;
				Quaternion rotation = ((Component)item3).transform.rotation;
				((Component)item3).GetComponent<WearNTear>().Remove(false);
				player.PlacePiece(val3, position, rotation, flag, false);
				flag = false;
			}
			((Character)player).UseStamina((float)BuildStamina.Invoke(player, null));
			if (toolItem != null && toolItem.m_shared.m_useDurability)
			{
				toolItem.m_durability -= toolItem.m_shared.m_useDurabilityDrain * Game.m_durabilityRate;
			}
			int num3 = list.Count - list2.Count;
			((Character)player).Message((MessageType)1, $"Swapped {list2.Count} roof piece(s) to shingles" + ((num3 > 0) ? $" ({num3} skipped: no access)" : ""), 0, (Sprite)null, false);
		}

		private static Piece ShingleFor(Piece piece)
		{
			if ((Object)(object)piece == (Object)null)
			{
				return null;
			}
			string prefabName = Utils.GetPrefabName(((Component)piece).gameObject);
			if (!prefabName.StartsWith("wood_roof", StringComparison.Ordinal))
			{
				return null;
			}
			ZNetScene instance = ZNetScene.instance;
			GameObject val = ((instance != null) ? instance.GetPrefab("darkwood_roof" + prefabName.Substring("wood_roof".Length)) : null);
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val.GetComponent<Piece>();
		}

		private static bool CanReplace(Player player, Piece piece)
		{
			//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_004f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)piece == (Object)null || !piece.m_canBeRemoved || !piece.CanBeRemoved())
			{
				return false;
			}
			if ((Object)(object)((Component)piece).GetComponent<WearNTear>() == (Object)null || (Object)(object)((Component)piece).GetComponent<ZNetView>() == (Object)null)
			{
				return false;
			}
			Vector3 position = ((Component)piece).transform.position;
			if (Location.IsInsideNoBuildLocation(position))
			{
				return false;
			}
			return PrivateArea.CheckAccess(position, 0f, true, false);
		}

		private static List<Piece> ConnectedThatch(Piece start)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			List<Piece> list = new List<Piece> { start };
			HashSet<Piece> hashSet = new HashSet<Piece> { start };
			List<Piece> list2 = new List<Piece>();
			for (int i = 0; i < list.Count; i++)
			{
				if (list.Count >= _maxPieces.Value)
				{
					break;
				}
				list2.Clear();
				Piece.GetAllPiecesInRadius(((Component)list[i]).transform.position, 3f, list2);
				foreach (Piece item in list2)
				{
					if (!((Object)(object)item == (Object)null) && !hashSet.Contains(item) && !((Object)(object)ShingleFor(item) == (Object)null))
					{
						hashSet.Add(item);
						list.Add(item);
						if (list.Count >= _maxPieces.Value)
						{
							break;
						}
					}
				}
			}
			return list;
		}

		private static IEnumerable<Inventory> ChestInventories(Player player)
		{
			Vector3 origin = ((Component)player).transform.position;
			float maxSqr = _chestRange.Value * _chestRange.Value;
			Containers.RemoveWhere((Container c) => (Object)(object)c == (Object)null);
			foreach (Container item in Containers.OrderBy(delegate(Container c)
			{
				//IL_0006: 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_0016: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val2 = ((Component)c).transform.position - origin;
				return ((Vector3)(ref val2)).sqrMagnitude;
			}))
			{
				Vector3 val = ((Component)item).transform.position - origin;
				if (((Vector3)(ref val)).sqrMagnitude > maxSqr)
				{
					break;
				}
				if (((Behaviour)item).isActiveAndEnabled && item.GetInventory() != null)
				{
					Piece componentInParent = ((Component)item).GetComponentInParent<Piece>();
					if (!((Object)(object)componentInParent == (Object)null) && componentInParent.IsPlacedByPlayer() && !((Object)(object)item.m_wagon != (Object)null) && !((Object)(object)((Component)item).GetComponentInParent<Ship>() != (Object)null) && item.IsOwner() && !item.IsInUse() && (bool)CheckAccessMethod.Invoke(item, new object[1] { player.GetPlayerID() }))
					{
						yield return item.GetInventory();
					}
				}
			}
		}

		private static int Available(Player player, string name)
		{
			return ((Humanoid)player).GetInventory().CountItems(name, -1, true) + ChestInventories(player).Sum((Inventory inv) => inv.CountItems(name, -1, true));
		}

		private static void Pay(Player player, string name, int amount)
		{
			int num = Mathf.Min(amount, ((Humanoid)player).GetInventory().CountItems(name, -1, true));
			if (num > 0)
			{
				((Humanoid)player).GetInventory().RemoveItem(name, num, -1, true);
			}
			int num2 = amount - num;
			foreach (Inventory item in ChestInventories(player))
			{
				if (num2 <= 0)
				{
					break;
				}
				int num3 = Mathf.Min(num2, item.CountItems(name, -1, true));
				if (num3 > 0)
				{
					item.RemoveItem(name, num3, -1, true);
					num2 -= num3;
				}
			}
		}
	}
}
namespace RepairNearby
{
	public class Plugin : DigiModule
	{
		public const string Guid = "digi.valheim.repairnearby";

		public const string Name = "Digi's Repair Nearby";

		public const string Version = "1.0.2";

		private ConfigEntry<bool> _enabled;

		private ConfigEntry<float> _radius;

		private ConfigEntry<KeyCode> _key;

		private float _cooldown;

		private void MigrateConfig()
		{
			string text = Path.Combine(Paths.ConfigPath, "digi.valheim.repairnearby".Replace("digi.valheim.", "pieter.valheim.") + ".cfg");
			if (!File.Exists(base.Config.ConfigFilePath) && File.Exists(text))
			{
				File.Copy(text, base.Config.ConfigFilePath);
				base.Config.Reload();
			}
		}

		private void Awake()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			MigrateConfig();
			_enabled = base.Config.Bind("General", "Enabled", defaultValue: true, "Turn the repair key on or off.");
			_radius = base.Config.Bind("General", "Radius (m)", 100f, new ConfigDescription("Building pieces up to this many meters from you are repaired.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 200f), Array.Empty<object>()));
			_key = base.Config.Bind<KeyCode>("General", "Key", (KeyCode)270, "Key that repairs all damaged building pieces around you.");
		}

		private void Update()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if (!_enabled.Value)
			{
				return;
			}
			if (_cooldown > 0f)
			{
				_cooldown -= Time.unscaledDeltaTime;
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !Game.IsPaused() && !Typing() && UnityInput.Current.GetKeyDown(_key.Value))
			{
				_cooldown = 0.5f;
				Repair(localPlayer);
			}
		}

		private static bool Typing()
		{
			if ((!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible())
			{
				return Menu.IsVisible();
			}
			return true;
		}

		private void Repair(Player player)
		{
			//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_0048: 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_004e: 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)
			Vector3 position = ((Component)player).transform.position;
			float num = _radius.Value * _radius.Value;
			int num2 = 0;
			WearNTear[] array = Object.FindObjectsOfType<WearNTear>();
			foreach (WearNTear val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Vector3 val2 = ((Component)val).transform.position - position;
					if (!(((Vector3)(ref val2)).sqrMagnitude > num) && val.Repair())
					{
						num2++;
					}
				}
			}
			((Character)player).Message((MessageType)1, (num2 > 0) ? $"Repaired {num2} building pieces within {_radius.Value:0} m" : $"Nothing to repair within {_radius.Value:0} m", 0, (Sprite)null, false);
			base.Logger.LogInfo((object)$"Repaired {num2} pieces within {_radius.Value} m");
		}
	}
}
namespace NoWeatherDamage
{
	public class Plugin : DigiModule
	{
		public enum Filter
		{
			All,
			OnlyListed,
			AllExceptListed
		}

		public const string Guid = "digi.valheim.noweatherdamage";

		public const string Name = "Digi's No Weather Damage";

		public const string Version = "1.0.1";

		private static ConfigEntry<bool> _rain;

		private static ConfigEntry<bool> _water;

		private static ConfigEntry<int> _rainMaxDamage;

		private static ConfigEntry<Filter> _filter;

		private static ConfigEntry<string> _filterList;

		private static ConfigEntry<float> _waterline;

		private static string[] _filterWords = new string[0];

		private static readonly FieldRef<WearNTear, bool> RainWet = AccessTools.FieldRefAccess<WearNTear, bool>("m_rainWet");

		private static readonly Func<WearNTear, bool> UnderWater = AccessTools.MethodDelegate<Func<WearNTear, bool>>(AccessTools.Method(typeof(WearNTear), "IsUnderWater", (Type[])null, (Type[])null), (object)null, true);

		private void MigrateConfig()
		{
			string text = Path.Combine(Paths.ConfigPath, "digi.valheim.noweatherdamage".Replace("digi.valheim.", "pieter.valheim.") + ".cfg");
			if (!File.Exists(base.Config.ConfigFilePath) && File.Exists(text))
			{
				File.Copy(text, base.Config.ConfigFilePath);
				base.Config.Reload();
			}
		}

		private void Awake()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Expected O, but got Unknown
			MigrateConfig();
			_rain = base.Config.Bind("Rain", "Protect from rain", defaultValue: true, "Buildings without a roof do not lose health in the rain.");
			_rainMaxDamage = base.Config.Bind("Rain", "Max rain damage (%)", 0, new ConfigDescription("How much health rain may still take from a piece: 0 = none, 50 = normal (rain normally stops at half health).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50), Array.Empty<object>()));
			_filter = base.Config.Bind("Rain", "Which pieces", Filter.All, "All = protect every piece. OnlyListed = only pieces that match the list below. AllExceptListed = every piece except those.");
			_filterList = base.Config.Bind("Rain", "Piece list", "", "Words matched against piece names, comma-separated, e.g. \"wood_floor, roof\".");
			_water = base.Config.Bind("Water", "Protect from water", defaultValue: true, "Pieces standing in water or just above it (docks, piers, boathouses) do not rot. Ships are not affected.");
			_waterline = base.Config.Bind("Water", "Waterline height (m)", 2.5f, new ConfigDescription("How far above the water a piece still counts as \"at the water\", in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			_filterList.SettingChanged += delegate
			{
				ParseList();
			};
			ParseList();
			PatchModule(typeof(Plugin));
		}

		private static void ParseList()
		{
			_filterWords = (from w in (_filterList.Value ?? "").Split(new char[1] { ',' })
				select w.Trim().ToLowerInvariant() into w
				where w.Length > 0
				select w).ToArray();
		}

		[HarmonyPatch(typeof(WearNTear), "UpdateWear")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> UpdateWear(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo isWet = AccessTools.Method(typeof(WearNTear), "IsWet", (Type[])null, (Type[])null);
			MethodInfo replacement = AccessTools.Method(typeof(Plugin), "WetForWear", (Type[])null, (Type[])null);
			int replaced = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				if ((instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt) && instruction.operand as MethodInfo == isWet)
				{
					replaced++;
					yield return CodeInstructionExtensions.WithBlocks(CodeInstructionExtensions.WithLabels(new CodeInstruction(OpCodes.Call, (object)replacement), (IEnumerable<Label>)instruction.labels), (IEnumerable<ExceptionBlock>)instruction.blocks);
				}
				else
				{
					yield return instruction;
				}
			}
			if (replaced == 0)
			{
				Debug.LogWarning((object)"[No Weather Damage] Rain/water check not found in WearNTear.UpdateWear; the mod does nothing.");
			}
		}

		public static bool WetForWear(WearNTear piece)
		{
			bool num = RainWet.Invoke(piece);
			bool flag = UnderWater(piece);
			if (!num && !flag)
			{
				return false;
			}
			if ((Object)(object)((Component)piece).GetComponentInParent<Ship>() != (Object)null)
			{
				return true;
			}
			if (_water.Value && (flag || AtWaterline(piece)))
			{
				return false;
			}
			if (flag)
			{
				return true;
			}
			return !RainProtected(piece);
		}

		private static bool AtWaterline(WearNTear piece)
		{
			//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_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)piece).transform.position;
			WaterVolume val = null;
			float waterLevel = Floating.GetWaterLevel(position, ref val);
			if (waterLevel > -1000f)
			{
				return position.y <= waterLevel + _waterline.Value;
			}
			return false;
		}

		private static bool RainProtected(WearNTear piece)
		{
			if (!_rain.Value || !Matches(piece))
			{
				return false;
			}
			int value = _rainMaxDamage.Value;
			if (value > 0)
			{
				return piece.GetHealthPercentage() <= 1f - (float)value / 100f;
			}
			return true;
		}

		private static bool Matches(WearNTear piece)
		{
			if (_filter.Value == Filter.All)
			{
				return true;
			}
			string text = ((Object)((Component)piece).gameObject).name.ToLowerInvariant();
			bool flag = false;
			string[] filterWords = _filterWords;
			foreach (string value in filterWords)
			{
				if (text.Contains(value))
				{
					flag = true;
					break;
				}
			}
			if (_filter.Value != Filter.OnlyListed)
			{
				return !flag;
			}
			return flag;
		}
	}
}
namespace LevelStrength
{
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	public class Plugin : DigiModule
	{
		[HarmonyPatch(typeof(TerrainComp), "InternalDoOperation")]
		private static class DoOperationPatch
		{
			[HarmonyPriority(0)]
			private static void Prefix(TerrainComp __instance, Vector3 pos, Settings modifier, out int __state)
			{
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: Invalid comparison between Unknown and I4
				//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_0102: Unknown result type (might be due to invalid IL or missing references)
				//IL_0107: Unknown result type (might be due to invalid IL or missing references)
				__state = 0;
				if (modifier == null || modifier.m_square || (!modifier.m_level && !modifier.m_smooth) || (!_includeCultivator.Value && modifier.m_paintCleared && (int)modifier.m_paintType == 1))
				{
					return;
				}
				float num = Mathf.Clamp01((float)_strength.Value / 100f);
				float num2 = Mathf.Max(8f, _maxHeightChange.Value);
				if (!(num <= 0f) || !(num2 <= 8f))
				{
					float num3 = (modifier.m_level ? modifier.m_levelRadius : 0f);
					float num4 = (modifier.m_smooth ? modifier.m_smoothRadius : 0f);
					if (!float.IsNaN(num4) && !float.IsInfinity(num4))
					{
						_log.LogDebug((object)$"Levelling: level radius {num3:0.##}, smooth radius {num4:0.##}, strength {num:P0}, max change {num2:0.#} m");
						Level(__instance, pos + Vector3.up * modifier.m_levelOffset, num3, num4, modifier.m_smoothPower, num, num2);
						__state = (modifier.m_level ? 1 : 0) | (modifier.m_smooth ? 2 : 0);
						modifier.m_level = false;
						modifier.m_smooth = false;
					}
				}
			}

			[HarmonyPriority(800)]
			private static void Postfix(TerrainComp __instance, Settings modifier, int __state)
			{
				Restore(__instance, modifier, __state);
			}

			private static Exception Finalizer(Exception __exception, TerrainComp __instance, Settings modifier, int __state)
			{
				if (__exception != null)
				{
					Restore(__instance, modifier, __state);
				}
				return __exception;
			}

			private static void Restore(TerrainComp comp, Settings modifier, int state)
			{
				if (state != 0)
				{
					if ((state & 1) != 0)
					{
						modifier.m_level = true;
					}
					if ((state & 2) != 0)
					{
						modifier.m_smooth = true;
					}
					LastOpRadius.Invoke(comp) = modifier.GetRadius();
				}
			}
		}

		public const string Guid = "digi.valheim.levelstrength";

		public const string Name = "Digi's Level Strength";

		public const string Version = "1.1.2";

		private const string TerrainToolsGuid = "Searica.Valheim.TerrainTools";

		private const float VanillaMaxLevelDelta = 8f;

		private static ManualLogSource _log;

		private static ConfigEntry<int> _strength;

		private static ConfigEntry<float> _maxHeightChange;

		private static readonly FieldRef<TerrainComp, Heightmap> Hmap = AccessTools.FieldRefAccess<TerrainComp, Heightmap>("m_hmap");

		private static readonly FieldRef<TerrainComp, int> Width = AccessTools.FieldRefAccess<TerrainComp, int>("m_width");

		private static readonly FieldRef<TerrainComp, float[]> LevelDelta = AccessTools.FieldRefAccess<TerrainComp, float[]>("m_levelDelta");

		private static readonly FieldRef<TerrainComp, float[]> SmoothDelta = AccessTools.FieldRefAccess<TerrainComp, float[]>("m_smoothDelta");

		private static readonly FieldRef<TerrainComp, bool[]> Modified = AccessTools.FieldRefAccess<TerrainComp, bool[]>("m_modifiedHeight");

		private static readonly FieldRef<TerrainComp, float> LastOpRadius = AccessTools.FieldRefAccess<TerrainComp, float>("m_lastOpRadius");

		private static ConfigEntry<bool> _includeCultivator;

		private void MigrateConfig()
		{
			string text = Path.Combine(Paths.ConfigPath, "digi.valheim.levelstrength".Replace("digi.valheim.", "pieter.valheim.") + ".cfg");
			if (!File.Exists(base.Config.ConfigFilePath) && File.Exists(text))
			{
				File.Copy(text, base.Config.ConfigFilePath);
				base.Config.Reload();
			}
		}

		private void Awake()
		{
			//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_001e: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			MigrateConfig();
			_log = base.Logger;
			ConfigurationManagerAttributes val = new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			};
			_strength = base.Config.Bind("Level ground", "Level strength", 0, new ConfigDescription("How flat the hoe's Level ground makes things: 0 = normal (only the middle gets flat), 100 = the whole circle becomes exactly flat. Set by the host, the same for everyone.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), new object[1] { val }));
			_maxHeightChange = base.Config.Bind("Level ground", "Max height change (m)", 8f, new ConfigDescription("How far one spot of ground can be raised or lowered in total by levelling, in meters. Normal is 8 (and only 1 for the hoe's Level ground). Set by the host, the same for everyone.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 32f), new object[1] { val }));
			_includeCultivator = base.Config.Bind("Level ground", "Include cultivator", defaultValue: false, new ConfigDescription("Also use this strength for the cultivator, which smooths the ground the same way. Set by the host, the same for everyone.", (AcceptableValueBase)null, new object[1] { val }));
			base.ModuleHarmony.PatchAll(typeof(DoOperationPatch));
			base.Logger.LogInfo((object)"Level strength slider ready.");
		}

		private static void Level(TerrainComp comp, Vector3 worldPos, float levelRadius, float smoothRadius, float power, float strength, float maxChange)
		{
			//IL_0048: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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)
			Heightmap val = Hmap.Invoke(comp);
			float[] array = LevelDelta.Invoke(comp);
			float[] array2 = SmoothDelta.Invoke(comp);
			bool[] array3 = Modified.Invoke(comp);
			if ((Object)(object)val == (Object)null || array == null || array2 == null || array3 == null)
			{
				return;
			}
			int num = default(int);
			int num2 = default(int);
			val.WorldToVertex(worldPos, ref num, ref num2);
			float num3 = worldPos.y - ((Component)comp).transform.position.y;
			float num4 = levelRadius / val.m_scale;
			float num5 = Mathf.Max(num4, smoothRadius / val.m_scale);
			int num6 = Mathf.CeilToInt(num5);
			int num7 = Width.Invoke(comp) + 1;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor((float)num, (float)num2);
			for (int i = num2 - num6; i <= num2 + num6; i++)
			{
				for (int j = num - num6; j <= num + num6; j++)
				{
					if (j < 0 || i < 0 || j >= num7 || i >= num7)
					{
						continue;
					}
					float num8 = Vector2.Distance(val2, new Vector2((float)j, (float)i));
					if (!(num8 > num5))
					{
						float num9;
						if (num4 > 0f && num8 <= num4)
						{
							num9 = 1f;
						}
						else
						{
							float num10 = num8 / num5;
							num9 = Mathf.Lerp(1f - Mathf.Pow(num10, power), 1f, strength);
						}
						int num11 = i * num7 + j;
						float height = val.GetHeight(j, i);
						if ((num4 > 0f && num8 <= num4) || strength > 0f)
						{
							array[num11] += array2[num11] + (num3 - height) * num9;
							array2[num11] = 0f;
							array[num11] = Mathf.Clamp(array[num11], 0f - maxChange, maxChange);
						}
						else
						{
							array2[num11] = Mathf.Clamp(array2[num11] + (Mathf.Lerp(height, num3, num9) - height), -1f, 1f);
						}
						array3[num11] = true;
					}
				}
			}
		}
	}
}
namespace BuildRestrictions
{
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	public class Plugin : DigiModule
	{
		public const string Guid = "digi.valheim.buildrestrictions";

		public const string Name = "Digi's Build Restrictions";

		public const string Version = "1.0.1";

		private static ConfigEntry<bool> _all;

		private static ConfigEntry<bool> _invalid;

		private static ConfigEntry<bool> _blockedByPlayer;

		private static ConfigEntry<bool> _noBuildZone;

		private static ConfigEntry<bool> _space;

		private static ConfigEntry<bool> _teleport;

		private static ConfigEntry<bool> _missingExtensionStation;

		private static ConfigEntry<bool> _missingStation;

		private static ConfigEntry<bool> _biome;

		private static ConfigEntry<bool> _cultivated;

		private static ConfigEntry<bool> _dirt;

		private static ConfigEntry<bool> _dungeon;

		private static CraftingStation _anyStation;

		private static readonly FieldRef<Player, GameObject> Ghost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost");

		private static readonly FieldRef<Player, PlacementStatus> Status = AccessTools.FieldRefAccess<Player, PlacementStatus>("m_placementStatus");

		private static readonly Action<Player, bool> SetGhostValid = AccessTools.MethodDelegate<Action<Player, bool>>(AccessTools.Method(typeof(Player), "SetPlacementGhostValid", (Type[])null, (Type[])null), (object)null, true);

		private void MigrateConfig()
		{
			string text = Path.Combine(Paths.ConfigPath, "digi.valheim.buildrestrictions".Replace("digi.valheim.", "pieter.valheim.") + ".cfg");
			if (!File.Exists(base.Config.ConfigFilePath) && File.Exists(text))
			{
				File.Copy(text, base.Config.ConfigFilePath);
				base.Config.Reload();
			}
		}

		private void Awake()
		{
			MigrateConfig();
			_all = Rule("Ignore all restrictions", value: false, "Turns every rule below off at once.");
			_invalid = Rule("Ignore invalid placement", value: true, "Place pieces where the game says \"Invalid placement\", e.g. a campfire on a wooden floor, ground-only pieces on floors, or pieces on steep slopes.");
			_blockedByPlayer = Rule("Ignore player in the way", value: false, "Build even when a player is standing where the piece goes.");
			_noBuildZone = Rule("Ignore no-build zones", value: false, "Build in protected places like the trader's camp and boss altars.");
			_space = Rule("Ignore space needed", value: false, "Build pieces that need free space around them (like beds and portals) in tight spots.");
			_teleport = Rule("Ignore teleport areas", value: false, "Place pieces that are normally only allowed in special teleport areas anywhere (rarely matters).");
			_missingExtensionStation = Rule("Ignore extension without station", value: false, "Build station upgrades (chopping block, tanning rack, forge bellows, ...) without their crafting station nearby.");
			_missingStation = Rule("Ignore missing workbench", value: false, "Build without a workbench (or the other station a piece needs) nearby.");
			_biome = Rule("Ignore biome restrictions", value: false, "Build pieces that are limited to certain biomes anywhere.");
			_cultivated = Rule("Ignore cultivated ground", value: false, "Plant crops and saplings without cultivated ground.");
			_dirt = Rule("Ignore dirt requirement", value: false, "Place pieces that need dirt or grass on any ground.");
			_dungeon = Rule("Ignore dungeon restrictions", value: true, "Build inside dungeons, crypts and other places where building is normally blocked.");
			PatchModule(typeof(Plugin));
		}

		private ConfigEntry<bool> Rule(string name, bool value, string description)
		{
			//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)
			//IL_002e: Expected O, but got Unknown
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			return base.Config.Bind("Restrictions", name, value, new ConfigDescription(description + " Set by the host, the same for everyone.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
		}

		private static bool On(ConfigEntry<bool> rule)
		{
			if (!_all.Value)
			{
				return rule.Value;
			}
			return true;
		}

		private static bool Ignored(PlacementStatus status)
		{
			//IL_0000: 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_0034: Expected I4, but got Unknown
			return (status - 1) switch
			{
				0 => On(_invalid), 
				1 => On(_blockedByPlayer), 
				2 => On(_noBuildZone), 
				4 => On(_space), 
				5 => On(_teleport), 
				6 => On(_missingExtensionStation), 
				7 => On(_biome), 
				8 => On(_cultivated), 
				9 => On(_dirt), 
				10 => On(_dungeon), 
				_ => false, 
			};
		}

		[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
		[HarmonyPostfix]
		private static void UpdatePlacementGhost(Player __instance)
		{
			//IL_0021: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Ghost.Invoke(__instance) == (Object)null))
			{
				PlacementStatus val = Status.Invoke(__instance);
				if ((int)val != 0 && Ignored(val))
				{
					Status.Invoke(__instance) = (PlacementStatus)0;
					SetGhostValid(__instance, arg2: true);
				}
			}
		}

		[HarmonyPatch(typeof(Location), "IsInsideNoBuildLocation")]
		[HarmonyPostfix]
		private static void NoBuildLocation(ref bool __result)
		{
			if (__result && On(_noBuildZone))
			{
				__result = false;
			}
		}

		[HarmonyPatch(typeof(CraftingStation), "HaveBuildStationInRange")]
		[HarmonyPostfix]
		private static void HaveStation(ref CraftingStation __result)
		{
			//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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			if (!((Object)(object)__result != (Object)null) && On(_missingStation))
			{
				if ((Object)(object)_anyStation == (Object)null)
				{
					GameObject val = new GameObject("BuildRestrictions_AnyStation");
					val.SetActive(false);
					Object.DontDestroyOnLoad((Object)val);
					_anyStation = val.AddComponent<CraftingStation>();
				}
				__result = _anyStation;
			}
		}
	}
}