Decompiled source of ValheimFortress v0.20.5

plugins/ValheimFortress.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Versioning;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Extensions;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using ValheimFortress.Challenge;
using ValheimFortress.Defenses;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Callbacks;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ValheimFortress")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ValheimFortress")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("0.0.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.1.0")]
namespace ValheimFortress
{
	internal class ValheimFortressPieces
	{
		private class ValheimPiece
		{
			private string[] allowed_catagories = new string[4] { "Furniture", "Building", "Crafting", "Misc" };

			private string[] crafting_stations = new string[5] { "forge", "piece_workbench", "blackforge", "piece_artisanstation", "piece_stonecutter" };

			public ValheimPiece(AssetBundle EmbeddedResourceBundle, VFConfig cfg, Dictionary<string, string> metadata, Dictionary<string, bool> piecetoggle, Dictionary<string, Tuple<int, bool>> recipedata, bool shrinescript = false, bool turretscript = false, bool arenascript = false)
			{
				//IL_0364: Unknown result type (might be due to invalid IL or missing references)
				//IL_0369: Unknown result type (might be due to invalid IL or missing references)
				//IL_0377: Unknown result type (might be due to invalid IL or missing references)
				//IL_038a: Unknown result type (might be due to invalid IL or missing references)
				//IL_039e: Expected O, but got Unknown
				//IL_0473: Unknown result type (might be due to invalid IL or missing references)
				//IL_0478: Unknown result type (might be due to invalid IL or missing references)
				//IL_0493: Unknown result type (might be due to invalid IL or missing references)
				//IL_049f: Unknown result type (might be due to invalid IL or missing references)
				//IL_04b1: Unknown result type (might be due to invalid IL or missing references)
				//IL_04ba: Unknown result type (might be due to invalid IL or missing references)
				//IL_04c5: Expected O, but got Unknown
				//IL_04cf: Unknown result type (might be due to invalid IL or missing references)
				//IL_04d9: Expected O, but got Unknown
				if (!allowed_catagories.Contains(metadata["catagory"]))
				{
					throw new ArgumentException(string.Format("Catagory {0} must be an allowed catagory: {1}", metadata["catagory"], allowed_catagories));
				}
				if (!metadata.ContainsKey("name"))
				{
					throw new ArgumentException("Item must have a name");
				}
				if (!metadata.ContainsKey("prefab"))
				{
					throw new ArgumentException("Item must have a prefab");
				}
				if (!metadata.ContainsKey("sprite"))
				{
					throw new ArgumentException("Item must have a sprite");
				}
				if (!metadata.ContainsKey("requiredBench"))
				{
					throw new ArgumentException("Item must have a requiredBench");
				}
				if (!crafting_stations.Contains(metadata["requiredBench"]))
				{
					throw new ArgumentException(string.Format("Catagory {0} must be a valid crafting station: {1}", metadata["requiredBench"], crafting_stations));
				}
				if (recipedata.Count > 4)
				{
					throw new ArgumentException("Recipe data can't have more than 4 requirements");
				}
				if (!piecetoggle.ContainsKey("enabled"))
				{
					piecetoggle.Add("enabled", value: true);
				}
				metadata["short_item_name"] = string.Join("", metadata["name"].Split((string[]?)null, StringSplitOptions.RemoveEmptyEntries));
				if (VFConfig.EnableDebugMode.Value)
				{
					Logger.LogInfo((object)("Creating Configuration Values for " + metadata["name"]));
				}
				CreateAndLoadConfigValues(cfg, metadata, piecetoggle, recipedata);
				if (piecetoggle["enabled"])
				{
					if (VFConfig.EnableDebugMode.Value)
					{
						Logger.LogInfo((object)("Loading bundled assets for " + metadata["name"]));
					}
					GameObject val = EmbeddedResourceBundle.LoadAsset<GameObject>("Assets/Custom/Pieces/" + metadata["catagory"] + "/" + metadata["prefab"] + ".prefab");
					Sprite icon = EmbeddedResourceBundle.LoadAsset<Sprite>("Assets/Custom/Icons/piece_icons/" + metadata["sprite"] + ".png");
					if (shrinescript)
					{
						val.AddComponent<ChallengeShrine>();
						val.AddComponent<ChallengeShrineUI>();
						val.AddComponent<Spawner>();
					}
					if (arenascript)
					{
						val.AddComponent<ArenaShrine>();
						val.AddComponent<ArenaShrineUI>();
						val.AddComponent<Spawner>();
					}
					if (turretscript)
					{
						val.AddComponent<VFTurret>();
					}
					if (VFConfig.EnableDebugMode.Value)
					{
						Logger.LogInfo((object)("Loading " + metadata["name"] + " updated Recipe."));
					}
					RequirementConfig[] array = (RequirementConfig[])(object)new RequirementConfig[recipedata.Count];
					int num = 0;
					foreach (KeyValuePair<string, Tuple<int, bool>> recipedatum in recipedata)
					{
						array[num] = new RequirementConfig
						{
							Item = recipedatum.Key,
							Amount = recipedatum.Value.Item1,
							Recover = recipedatum.Value.Item2
						};
						num++;
					}
					if (VFConfig.EnableDebugMode.Value)
					{
						Logger.LogInfo((object)("Piece " + metadata["name"] + " Recipe:"));
						RequirementConfig[] array2 = array;
						foreach (RequirementConfig val2 in array2)
						{
							Logger.LogInfo((object)$"Requires: {val2.Amount} {val2.Item} Recover: {val2.Recover}");
						}
					}
					if (VFConfig.EnableDebugMode.Value)
					{
						Logger.LogInfo((object)("Building Piececonfig for " + metadata["name"] + "."));
					}
					PieceConfig val3 = new PieceConfig
					{
						CraftingStation = (metadata["requiredBench"] ?? ""),
						PieceTable = PieceTables.Hammer,
						Category = metadata["catagory"],
						Icon = icon,
						Requirements = array
					};
					PieceManager.Instance.AddPiece(new CustomPiece(val, true, val3));
					if (VFConfig.EnableDebugMode.Value)
					{
						Logger.LogInfo((object)("Piece " + metadata["name"] + " Added!"));
					}
				}
				else if (VFConfig.EnableDebugMode.Value)
				{
					Logger.LogInfo((object)(metadata["name"] + " is not enabled, and was not loaded."));
				}
			}

			private void CreateAndLoadConfigValues(VFConfig config, Dictionary<string, string> metadata, Dictionary<string, bool> piecetoggle, Dictionary<string, Tuple<int, bool>> recipedata)
			{
				piecetoggle["enabled"] = config.BindServerConfig(metadata["catagory"] + " - " + metadata["name"], metadata["short_item_name"] + "-Enable", piecetoggle["enabled"], "Enable/Disable the " + metadata["name"] + ".").Value;
				foreach (KeyValuePair<string, bool> item in piecetoggle)
				{
					if (!(item.Key == "enabled"))
					{
						piecetoggle[item.Key] = config.BindServerConfig(metadata["catagory"] + " - " + metadata["name"], metadata["short_item_name"] + "-" + item.Key, item.Value, item.Key + " enable(true)/disable(false).", advanced: true).Value;
					}
				}
				string text = "";
				foreach (KeyValuePair<string, Tuple<int, bool>> recipedatum in recipedata)
				{
					if (text.Length > 0)
					{
						text += "|";
					}
					text += $"{recipedatum.Key},{recipedatum.Value.Item1},{recipedatum.Value.Item2}";
				}
				string value = config.BindServerConfig(metadata["catagory"] + " - " + metadata["name"], metadata["short_item_name"] + "-recipe", text, "Recipe to craft, Find item ids: https://valheim.fandom.com/wiki/Item_IDs, at most 4 costs. Format: resouce_id,craft_cost-recover_flag eg: Wood,8,false|Iron,12,true", advanced: true).Value;
				if (VFConfig.EnableDebugMode.Value)
				{
					Logger.LogInfo((object)("recieved rawrecipe data: '" + value + "'"));
				}
				string[] array = value.Split(new char[1] { '|' });
				Dictionary<string, Tuple<int, bool>> dictionary = new Dictionary<string, Tuple<int, bool>>();
				if (VFConfig.EnableDebugMode.Value)
				{
					Logger.LogInfo((object)$"recipe entries: {array.Length} : {array}");
				}
				if (array.Length >= 1)
				{
					string[] array2 = array;
					foreach (string text2 in array2)
					{
						string[] array3 = text2.Split(new char[1] { ',' });
						if (VFConfig.EnableDebugMode.Value)
						{
							string text3 = "";
							string[] array4 = array3;
							foreach (string text4 in array4)
							{
								text3 = text3 + " " + text4;
							}
							Logger.LogInfo((object)("recipe segments: " + text3 + " from " + text2));
						}
						bool flag = true;
						if (array3.Length > 2)
						{
							flag = bool.Parse(array3[2]);
						}
						if (VFConfig.EnableDebugMode.Value)
						{
							Logger.LogInfo((object)$"Setting recipe requirement: {array3[0]}={array3[1]} recover={flag}");
						}
						dictionary.Add(array3[0], Tuple.Create(int.Parse(array3[1]), flag));
					}
					recipedata.Clear();
					{
						foreach (KeyValuePair<string, Tuple<int, bool>> item2 in dictionary)
						{
							if (VFConfig.EnableDebugMode.Value)
							{
								Logger.LogInfo((object)$"Updated recipe: resouce: {item2.Key} build: {item2.Value.Item1} recovery: {item2.Value.Item2}");
							}
							recipedata.Add(item2.Key, item2.Value);
						}
						return;
					}
				}
				Logger.LogWarning((object)("Configuration '" + metadata["catagory"] + " - " + metadata["name"] + " - " + metadata["short_item_name"] + "-recipe' was invalid and will be ignored, the default will be used."));
			}
		}

		public ValheimFortressPieces(AssetBundle EmbeddedResourceBundle, VFConfig config)
		{
			if (VFConfig.EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Loading Pieces.");
			}
			LoadRugs(EmbeddedResourceBundle, config);
			LoadGlassWalls(EmbeddedResourceBundle, config);
			LoadAlterOfChallenge(EmbeddedResourceBundle, config);
			LoadDefenses(EmbeddedResourceBundle, config);
		}

		private void LoadRugs(AssetBundle EmbeddedResourceBundle, VFConfig cfg)
		{
			new ValheimPiece(EmbeddedResourceBundle, cfg, new Dictionary<string, string>
			{
				{ "name", "Green Jute Carpet" },
				{ "catagory", "Furniture" },
				{ "prefab", "VFgreen_jute_carpet_circle" },
				{ "sprite", "cricle_rug_green" },
				{ "requiredBench", "piece_workbench" }
			}, new Dictionary<string, bool>(), new Dictionary<string, Tuple<int, bool>>
			{
				{
					"Guck",
					Tuple.Create(1, item2: true)
				},
				{
					"JuteRed",
					Tuple.Create(4, item2: true)
				}
			});
			new ValheimPiece(EmbeddedResourceBundle, cfg, new Dictionary<string, string>
			{
				{ "name", "Red Jute Carpet" },
				{ "catagory", "Furniture" },
				{ "prefab", "VFred_jute_carpet_circle" },
				{ "sprite", "cricle_rug_red" },
				{ "requiredBench", "piece_workbench" }
			}, new Dictionary<string, bool>(), new Dictionary<string, Tuple<int, bool>> { 
			{
				"JuteRed",
				Tuple.Create(4, item2: true)
			} });
			new ValheimPiece(EmbeddedResourceBundle, cfg, new Dictionary<string, string>
			{
				{ "name", "Yellow Jute Carpet" },
				{ "catagory", "Furniture" },
				{ "prefab", "VFyellow_jute_carpet_circle" },
				{ "sprite", "cricle_rug_yellow" },
				{ "requiredBench", "piece_workbench" }
			}, new Dictionary<string, bool>(), new Dictionary<string, Tuple<int, bool>>
			{
				{
					"Dandelion",
					Tuple.Create(4, item2: true)
				},
				{
					"JuteRed",
					Tuple.Create(4, item2: true)
				}
			});
		}

		private void LoadGlassWalls(AssetBundle EmbeddedResourceBundle, VFConfig cfg)
		{
			new ValheimPiece(EmbeddedResourceBundle, cfg, new Dictionary<string, string>
			{
				{ "name", "Blue Crystal Wall" },
				{ "catagory", "Building" },
				{ "prefab", "VFblue_crystal_wall" },
				{ "sprite", "blue_crystal_wall" },
				{ "requiredBench", "piece_workbench" }
			}, new Dictionary<string, bool>(), new Dictionary<string, Tuple<int, bool>>
			{
				{
					"Blueberries",
					Tuple.Create(4, item2: true)
				},
				{
					"Crystal",
					Tuple.Create(2, item2: true)
				}
			});
			new ValheimPiece(EmbeddedResourceBundle, cfg, new Dictionary<string, string>
			{
				{ "name", "Red Crystal Wall" },
				{ "catagory", "Building" },
				{ "prefab", "VFred_crystal_wall" },
				{ "sprite", "red_crystal_wall" },
				{ "requiredBench", "piece_workbench" }
			}, new Dictionary<string, bool>(), new Dictionary<string, Tuple<int, bool>>
			{
				{
					"Raspberry",
					Tuple.Create(2, item2: true)
				},
				{
					"Crystal",
					Tuple.Create(2, item2: true)
				}
			});
			new ValheimPiece(EmbeddedResourceBundle, cfg, new Dictionary<string, string>
			{
				{ "name", "Yellow Crystal Wall" },
				{ "catagory", "Building" },
				{ "prefab", "VFyellow_crystal_wall" },
				{ "sprite", "yellow_crystal_wall" },
				{ "requiredBench", "piece_workbench" }
			}, new Dictionary<string, bool>(), new Dictionary<string, Tuple<int, bool>>
			{
				{
					"Dandelion",
					Tuple.Create(2, item2: true)
				},
				{
					"Crystal",
					Tuple.Create(2, item2: true)
				}
			});
			new ValheimPiece(EmbeddedResourceBundle, cfg, new Dictionary<string, string>
			{
				{ "name", "Green Crystal Wall" },
				{ "catagory", "Building" },
				{ "prefab", "VFgreen_crystal_wall" },
				{ "sprite", "green_crystal_wall" },
				{ "requiredBench", "piece_workbench" }
			}, new Dictionary<string, bool>(), new Dictionary<string, Tuple<int, bool>>
			{
				{
					"Guck",
					Tuple.Create(2, item2: true)
				},
				{
					"Crystal",
					Tuple.Create(2, item2: true)
				}
			});
		}

		private void LoadAlterOfChallenge(AssetBundle EmbeddedResourceBundle, VFConfig cfg)
		{
			new ValheimPiece(EmbeddedResourceBundle, cfg, new Dictionary<string, string>
			{
				{ "name", "Alter of Challenge" },
				{ "catagory", "Misc" },
				{ "prefab", "VFshrine_of_challenge" },
				{ "sprite", "shrine_of_challenge" },
				{ "requiredBench", "piece_workbench" }
			}, new Dictionary<string, bool>(), new Dictionary<string, Tuple<int, bool>>
			{
				{
					"Stone",
					Tuple.Create(23, item2: true)
				},
				{
					"Ruby",
					Tuple.Create(4, item2: true)
				},
				{
					"Coins",
					Tuple.Create(100, item2: false)
				}
			}, shrinescript: true);
			new ValheimPiece(EmbeddedResourceBundle, cfg, new Dictionary<string, string>
			{
				{ "name", "Alter of the Arena" },
				{ "catagory", "Misc" },
				{ "prefab", "VFshine_of_gladiator" },
				{ "sprite", "alter_of_arena" },
				{ "requiredBench", "piece_workbench" }
			}, new Dictionary<string, bool>(), new Dictionary<string, Tuple<int, bool>>
			{
				{
					"Stone",
					Tuple.Create(23, item2: true)
				},
				{
					"Coins",
					Tuple.Create(100, item2: false)
				}
			}, shrinescript: false, turretscript: false, arenascript: true);
		}

		private void LoadDefenses(AssetBundle EmbeddedResourceBundle, VFConfig cfg)
		{
			new ValheimPiece(EmbeddedResourceBundle, cfg, new Dictionary<string, string>
			{
				{ "name", "Stone Spikes" },
				{ "catagory", "Misc" },
				{ "prefab", "VFstone_stakes" },
				{ "sprite", "stone_spikes" },
				{ "requiredBench", "piece_stonecutter" }
			}, new Dictionary<string, bool>(), new Dictionary<string, Tuple<int, bool>>
			{
				{
					"Stone",
					Tuple.Create(30, item2: false)
				},
				{
					"Silver",
					Tuple.Create(2, item2: true)
				}
			});
			new ValheimPiece(EmbeddedResourceBundle, cfg, new Dictionary<string, string>
			{
				{ "name", "Magic Turret" },
				{ "catagory", "Misc" },
				{ "prefab", "VFpiece_turret" },
				{ "sprite", "modified_turret" },
				{ "requiredBench", "piece_artisanstation" }
			}, new Dictionary<string, bool>(), new Dictionary<string, Tuple<int, bool>>
			{
				{
					"BlackMetal",
					Tuple.Create(20, item2: false)
				},
				{
					"YggdrasilWood",
					Tuple.Create(20, item2: false)
				},
				{
					"MechanicalSpring",
					Tuple.Create(5, item2: true)
				},
				{
					"DragonTear",
					Tuple.Create(2, item2: true)
				}
			}, shrinescript: false, turretscript: true);
		}
	}
	[BepInPlugin("MidnightsFX.ValheimFortress", "ValheimFortress", "0.20.5")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal class ValheimFortress : BaseUnityPlugin
	{
		public const string PluginGUID = "MidnightsFX.ValheimFortress";

		public const string PluginName = "ValheimFortress";

		public const string PluginVersion = "0.20.5";

		private AssetBundle EmbeddedResourceBundle;

		public VFConfig cfg;

		public static GameObject spawnPortal;

		public static GameObject creatureNotifier;

		public static GameObject portalDestroyVFX;

		private static readonly Regex sWhitespace = new Regex("\\s+");

		private void Awake()
		{
			cfg = new VFConfig(((BaseUnityPlugin)this).Config);
			cfg.SetupConfigRPCs();
			EmbeddedResourceBundle = AssetUtils.LoadAssetBundleFromResources("ValheimFortress.AssetsEmbedded.vfbundle", typeof(ValheimFortress).Assembly);
			AddLocalizations();
			new ValheimFortressPieces(EmbeddedResourceBundle, cfg);
			SetupVFXObjects(EmbeddedResourceBundle);
			new VFLocations(EmbeddedResourceBundle, cfg);
			VFConfig.GetYamlConfigFiles();
			Levels.UpdateLevelValues(cfg);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Valheim Fortress loaded.");
		}

		private void AddLocalizations()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Loading Localizations.");
			string[] manifestResourceNames = typeof(ValheimFortress).Assembly.GetManifestResourceNames();
			foreach (string text in manifestResourceNames)
			{
				if (text.Contains("Localizations"))
				{
					string input = ReadEmbeddedResourceFile(text);
					string text2 = Regex.Replace(input, "\\/\\/.*", "");
					string[] array = text.Split(new char[1] { '.' });
					if (VFConfig.EnableDebugMode.Value)
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)("Adding localization: " + array[2]));
					}
					localization.AddJsonFile(array[2], text2);
				}
			}
		}

		internal static GameObject getPortal()
		{
			return spawnPortal;
		}

		internal static GameObject getNotifier()
		{
			return creatureNotifier;
		}

		internal static GameObject getPortalDestroyVFX()
		{
			return portalDestroyVFX;
		}

		private static void SetupVFXObjects(AssetBundle EmbeddedResourceBundle)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			GameObject val = EmbeddedResourceBundle.LoadAsset<GameObject>("Assets/Custom/Pieces/VFortress/VF_portal.prefab");
			CustomPrefab val2 = new CustomPrefab(val, false);
			PrefabManager.Instance.AddPrefab(val2);
			spawnPortal = val2.Prefab;
			GameObject val3 = EmbeddedResourceBundle.LoadAsset<GameObject>("Assets/Custom/Pieces/VFortress/VF_portal_destroy.prefab");
			CustomPrefab val4 = new CustomPrefab(val3, false);
			PrefabManager.Instance.AddPrefab(val4);
			portalDestroyVFX = val4.Prefab;
			GameObject val5 = EmbeddedResourceBundle.LoadAsset<GameObject>("Assets/Custom/Pieces/VFortress/VF_creature_notify.prefab");
			CustomPrefab val6 = new CustomPrefab(val5, false);
			PrefabManager.Instance.AddPrefab(val6);
			creatureNotifier = val6.Prefab;
		}

		public static string LocalizeOrDefault(string str_to_localize, string default_string)
		{
			string text = Localization.instance.Localize(str_to_localize);
			if (text == "[" + str_to_localize.Replace("$", "") + "]")
			{
				Logger.LogInfo((object)(str_to_localize + " was not localized, returning the default: " + default_string));
				return default_string;
			}
			return text;
		}

		internal static string ReadEmbeddedResourceFile(string filename)
		{
			using Stream stream = typeof(ValheimFortress).Assembly.GetManifestResourceStream(filename);
			using StreamReader streamReader = new StreamReader(stream);
			return streamReader.ReadToEnd();
		}

		public static List<string> shuffleList(List<string> inputList)
		{
			int i = 0;
			int count = inputList.Count;
			int num = 0;
			string text = null;
			List<string> list = new List<string>();
			list.AddRange(inputList);
			for (; i < count; i++)
			{
				num = Random.Range(i, list.Count);
				text = list[i];
				list[i] = list[num];
				list[num] = text;
			}
			return list;
		}

		public static string FormatJson(string json, string indent = "  ")
		{
			int indentation = 0;
			int quoteCount = 0;
			int escapeCount = 0;
			IEnumerable<string> enumerable = from ch in json ?? string.Empty
				let escaped = ((ch == '\\') ? escapeCount++ : ((escapeCount > 0) ? escapeCount-- : escapeCount)) > 0
				let quotes = (ch == '"' && !escaped) ? quoteCount++ : quoteCount
				let unquoted = quotes % 2 == 0
				let colon = (ch == ':' && unquoted) ? ": " : null
				let nospace = (char.IsWhiteSpace(ch) && unquoted) ? string.Empty : null
				let lineBreak = (ch == ',' && unquoted) ? string.Concat(ch.ToString(), Environment.NewLine, string.Concat(Enumerable.Repeat(indent, indentation))) : null
				let openChar = ((ch == '{' || ch == '[') && unquoted) ? string.Concat(ch.ToString(), Environment.NewLine, string.Concat(Enumerable.Repeat(indent, ++indentation))) : ch.ToString()
				let closeChar = ((ch == '}' || ch == ']') && unquoted) ? string.Concat(Environment.NewLine, string.Concat(Enumerable.Repeat(indent, --indentation)), ch.ToString()) : ch.ToString()
				select colon ?? nospace ?? lineBreak ?? ((openChar.Length > 1) ? openChar : closeChar);
			return string.Concat(enumerable);
		}

		public static string ReplaceWhitespace(string input, string replacement)
		{
			return sWhitespace.Replace(input, replacement);
		}
	}
	internal class VFConfig
	{
		public static ConfigFile cfg;

		public static ConfigEntry<bool> EnableDebugMode;

		public static ConfigEntry<bool> EnableTurretDebugMode;

		public static ConfigEntry<short> MaxSpawnRange;

		public static ConfigEntry<float> rewardsMultiplier;

		public static ConfigEntry<float> rewardsDifficultyScalar;

		public static ConfigEntry<bool> EnableBossModifier;

		public static ConfigEntry<bool> EnableHardModifier;

		public static ConfigEntry<bool> EnableSiegeModifer;

		public static ConfigEntry<bool> EnableRewardsEstimate;

		public static ConfigEntry<bool> EnableMapPings;

		public static ConfigEntry<short> MaxRewardsPerSecond;

		public static ConfigEntry<short> NotifyCreatureThreshold;

		public static ConfigEntry<short> TeleportCreatureThreshold;

		public static ConfigEntry<float> ShrineAnnouncementRange;

		public static ConfigEntry<float> DistanceBetweenShrines;

		public static ConfigEntry<short> NumberOfEachWildShrine;

		public static ConfigEntry<short> ChallengeShrineMaxCreaturesPerWave;

		public static ConfigEntry<short> ArenaShrineMaxCreaturesPerWave;

		private static CustomRPC monsterSyncRPC;

		private static CustomRPC rewardSyncRPC;

		private static CustomRPC WavesSyncRPC;

		private static CustomRPC LevelsSyncRPC;

		private static CustomRPC WildShrineSyncRPC;

		private static string rewardFilePath = Path.Combine(Paths.ConfigPath, "VFortress", "Rewards.yaml");

		private static string creatureFilePath = Path.Combine(Paths.ConfigPath, "VFortress", "SpawnableCreatures.yaml");

		private static string waveStylesFilePath = Path.Combine(Paths.ConfigPath, "VFortress", "WaveStyles.yaml");

		private static string levelDefinitionsFilePath = Path.Combine(Paths.ConfigPath, "VFortress", "Levels.yaml");

		private static string wildShrineConfigurationFilePath = Path.Combine(Paths.ConfigPath, "VFortress", "WildShrines.yaml");

		public VFConfig(ConfigFile Config)
		{
			cfg = Config;
			cfg.SaveOnConfigSet = true;
			CreateConfigValues(Config);
			string configPath = Paths.ConfigPath;
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher();
			fileSystemWatcher.Path = configPath;
			fileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;
			fileSystemWatcher.Filter = "MidnightsFX.ValheimFortress.cfg";
			fileSystemWatcher.Changed += UpdateMainConfigFile;
			fileSystemWatcher.Created += UpdateMainConfigFile;
			fileSystemWatcher.Renamed += UpdateMainConfigFile;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
			Logger.LogInfo((object)"Main config filewatcher initialized.");
		}

		public void SetupConfigRPCs()
		{
			//IL_0012: 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_0028: Expected O, but got Unknown
			//IL_0028: Expected O, but got Unknown
			//IL_003e: 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_0054: Expected O, but got Unknown
			//IL_0054: Expected O, but got Unknown
			//IL_006a: 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_0080: Expected O, but got Unknown
			//IL_0080: Expected O, but got Unknown
			//IL_0096: 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_00ac: Expected O, but got Unknown
			//IL_00ac: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			//IL_00d8: Expected O, but got Unknown
			monsterSyncRPC = NetworkManager.Instance.AddRPC("monsteryaml_rpc", new CoroutineHandler(OnServerRecieveConfigs), new CoroutineHandler(OnClientReceiveCreatureConfigs));
			rewardSyncRPC = NetworkManager.Instance.AddRPC("rewardsyaml_rpc", new CoroutineHandler(OnServerRecieveConfigs), new CoroutineHandler(OnClientReceiveRewardsConfigs));
			WavesSyncRPC = NetworkManager.Instance.AddRPC("wavestyleyaml_rpc", new CoroutineHandler(OnServerRecieveConfigs), new CoroutineHandler(OnClientReceiveWaveConfigs));
			LevelsSyncRPC = NetworkManager.Instance.AddRPC("levelsyaml_rpc", new CoroutineHandler(OnServerRecieveConfigs), new CoroutineHandler(OnClientReceiveLevelConfigs));
			WildShrineSyncRPC = NetworkManager.Instance.AddRPC("wildshrineyaml_rpc", new CoroutineHandler(OnServerRecieveConfigs), new CoroutineHandler(OnClientReceiveWildShrineConfigs));
			SynchronizationManager.Instance.AddInitialSynchronization(monsterSyncRPC, (Func<ZPackage>)SendCreatureConfigs);
			SynchronizationManager.Instance.AddInitialSynchronization(rewardSyncRPC, (Func<ZPackage>)SendRewardsConfigs);
			SynchronizationManager.Instance.AddInitialSynchronization(WavesSyncRPC, (Func<ZPackage>)SendWavesConfigs);
			SynchronizationManager.Instance.AddInitialSynchronization(LevelsSyncRPC, (Func<ZPackage>)SendLevelsConfigs);
			SynchronizationManager.Instance.AddInitialSynchronization(WildShrineSyncRPC, (Func<ZPackage>)SendWildShrineConfigs);
		}

		public static string GetSecondaryConfigDirectoryPath()
		{
			string path = Path.Combine(Paths.ConfigPath, "VFortress");
			DirectoryInfo directoryInfo = Directory.CreateDirectory(path);
			return directoryInfo.FullName;
		}

		public static void GetYamlConfigFiles()
		{
			string secondaryConfigDirectoryPath = GetSecondaryConfigDirectoryPath();
			bool flag = false;
			bool flag2 = false;
			bool flag3 = false;
			bool flag4 = false;
			bool flag5 = false;
			string[] files = Directory.GetFiles(secondaryConfigDirectoryPath);
			string[] array = files;
			foreach (string text in array)
			{
				if (EnableDebugMode.Value)
				{
					Logger.LogInfo((object)("Config file found: " + text));
				}
				if (text.Contains("Rewards.yaml"))
				{
					if (EnableDebugMode.Value)
					{
						Logger.LogInfo((object)("Found rewards configuration: " + text));
					}
					rewardFilePath = text;
					flag = true;
				}
				if (text.Contains("SpawnableCreatures.yaml"))
				{
					if (EnableDebugMode.Value)
					{
						Logger.LogInfo((object)("Found Creature configuration: " + text));
					}
					creatureFilePath = text;
					flag2 = true;
				}
				if (text.Contains("WaveStyles.yaml"))
				{
					if (EnableDebugMode.Value)
					{
						Logger.LogInfo((object)("Found WaveStyles configuration: " + text));
					}
					waveStylesFilePath = text;
					flag3 = true;
				}
				if (text.Contains("Levels.yaml"))
				{
					if (EnableDebugMode.Value)
					{
						Logger.LogInfo((object)("Found Levels configuration: " + text));
					}
					levelDefinitionsFilePath = text;
					flag4 = true;
				}
				if (text.Contains("WildShrines.yaml"))
				{
					if (EnableDebugMode.Value)
					{
						Logger.LogInfo((object)("Found WildShrine configuration: " + text));
					}
					wildShrineConfigurationFilePath = text;
					flag5 = true;
				}
			}
			if (!flag)
			{
				Logger.LogInfo((object)"Rewards file missing, recreating.");
				using StreamWriter streamWriter = new StreamWriter(rewardFilePath);
				string value = "#################################################\n# Shrine of Challenge Rewards Configuration\n#################################################\n# Rewards configurations have a number of key values\n#  Coin:                                 |- The name of the reward, this will be the diplayed name if there is no localization for this reward, which is likely the case for any custom entries.\n#    enabled: true                       |- Whether or not the reward is enabled, you can use this to disable any vanilla rewards you do not want. At least 1 reward must be available at ALL times.\n#    resource_cost: 5                    |- This is the cost to gain 1 of the particular reward. Points are generated based on how many monsters are spawned.\n#    resource_prefab: \"Coins\"            |- This is the unity prefab name for a resource, you will often see mods list the prefabs they have added. Prefabs are also listed on the valheim wiki.\n#    required_boss: \"None\"               |- This must be one of the following values: \"None\" \"Eikythr\" \"TheElder\" \"BoneMass\" \"Moder\" \"Yagluth\" \"TheQueen\"";
				streamWriter.WriteLine(value);
				streamWriter.WriteLine(RewardsData.YamlRewardsDefinition());
			}
			if (!flag3)
			{
				Logger.LogInfo((object)"WaveStyles file missing, recreating.");
				using StreamWriter streamWriter2 = new StreamWriter(waveStylesFilePath);
				string value2 = "#################################################\n# Shrine of Challenge WaveStyles Configuration\n#################################################\n# WaveStyles configurations have a number of key values\n# Easy:                      |- This is the key used to lookup this wave definition\n#  WaveConfig                |- The wave configuration for each segment of the wave\n#   - type: COMMON           |- This is the catagory of creature that will be selected\n#     percent: 30            |- This is the percentage of the waves total point pool that will be used for this spawn";
				streamWriter2.WriteLine(value2);
				streamWriter2.WriteLine(Levels.YamlWaveDefinition());
			}
			if (!flag4)
			{
				Logger.LogInfo((object)"CreatureConfig file missing, recreating.");
				using StreamWriter streamWriter3 = new StreamWriter(levelDefinitionsFilePath);
				string value3 = "#################################################\n# Shrines of Challenge Levels Configuration\n#################################################\n# levels:\n# - levelIndex: 1                                                  |- LevelIndex is the difficulty this wave is set at, valid values are 1+\n#   levelForShrineTypes:                                           |- What shrines will host this level, multiple definitions can be applied\n#     challenge: true                                              |-   Shrine of challenge will host this level\n#     arena: true                                                  |-   Shrine of the arena will host this level\n#   levelMenuLocalization: $shrine_menu_meadow                     |- This is the localization that will be displayed when selecting the level, if no key matches the $lookup the literal string will be used\n#   requiredGlobalKey: NONE                                        |- This is the global key required to unlock this level more available here (https://valheim.fandom.com/wiki/Global_Keys)\n#   biome: Meadows                                                 |- This is the biome used for this level. This determines what creatures are considered\n#   waveFormat: Tutorial                                           |- This is the format of the wave, formates are defined in WaveStyles.yaml, it determines how many creatures, what catagory and percentage of total points they use\n#   bossWaveFormat: TutorialBoss                                   |- This is the format if the wave is modified to be a boss wave\n#   maxCreatureFromPreviousBiomes: 0                               |- This is the maximum number of creatures that can be selected from prior biomes\n#   levelWarningLocalization: $shrine_warning_meadows              |- This is the announcement text that plays when the challenge starts as a normal wave, uses literal value if the localization does not exist\n#   bossLevelWarningLocalization: $shrine_warning_meadows_boss     |- This is the announcement text that plays when the challenge starts as a boss wave, localizations are available here https://github.com/MidnightsFX/Valheim_Fortress/blob/master/JotunnModStub/Localizations/English.json\n#   onlySelectMonsters: []                                         |- This is an array of monsters that are the only valid targets for this wave\n#   excludeSelectMonsters: []                                      |- This is an array of monsters that are to be avoided for the wave\n#   commonSpawnModifiers:                                          |- Spawn modifiers are functions applied to each part of the wave, they can be different per catagory of monster\n#     linearIncreaseRandomWaveAdjustment: true                     |-   In general, it is best to only use one type of spawn modifier per creature type\n#     linearDecreaseRandomWaveAdjustment: false                    |- Linear Decrease/Increase will frontload or backload this creature in the various phase of the wave, meaning more of it will appear earlier or later depending on the modifier\n#     partialRandomWaveAdjustment: false                           |- Partial random adjustment will add more significant random variance to the number of creatures that will spawn\n#     onlyGenerateInSecondHalf: false                              |- Only generate in second half will prevent this type of creature from spawning in the earlier waves, this is useful for Elites/Rares when LinearDecrease is set for commons\n#   rareSpawnModifiers:                                            |-   The start of the wave will have many commons, and they will taper off till the end, while elites would come into play only on the second half of the wave\n#     linearIncreaseRandomWaveAdjustment: true\n#     linearDecreaseRandomWaveAdjustment: false\n#     partialRandomWaveAdjustment: false\n#     onlyGenerateInSecondHalf: false\n#   eliteSpawnModifiers:\n#     linearIncreaseRandomWaveAdjustment: true\n#     linearDecreaseRandomWaveAdjustment: false\n#     partialRandomWaveAdjustment: false\n#     onlyGenerateInSecondHalf: false\n#   uniqueSpawnModifiers: ";
				streamWriter3.WriteLine(value3);
				streamWriter3.WriteLine(Levels.YamlLevelsDefinition());
			}
			if (!flag2)
			{
				Logger.LogInfo((object)"CreatureConfig file missing, recreating.");
				using StreamWriter streamWriter4 = new StreamWriter(creatureFilePath);
				string value4 = "#################################################\n# Shrine of Challenge Creature Configuration\n#################################################\n# Creature configurations have a number of key values\n# Neck:                    |- This is the name of the creature being added, it is primarily used for display purposes and lookups\n#  spawnCost: 5            |- This is how many points from the wave pool it costs to spawn one creature, smaller values allow many more spawns.\n#  prefab: \"Neck\"          |- This is the creatures prefab, which will be used to spawn it.\n#  spawnType: \"common\"     |- This can either be: \"common\" or \"rare\" or \"elite\" or \"unique\", uniques are \"bosses\", most of the wave will be made up of more common enemies\n#  enabled: true           |- This controls if this creature will be included in wave-generation.\n#  dropsEnabled: false     |- This controls if this particular monster should drop loot. Disabled by default for everything.\n#  biome: \"Meadows\"        |- This must be one of the following values: \"Meadows\", \"BlackForest\", \"Swamp\", \"Mountain\", \"Plains\", \"Mistlands\". The biome determines the levels that will recieve this spawn, and how the spawn might be adjusted to\n#                             fit higher difficulty waves. eg: a greydwarf spawning into a swamp level wave will recieve 1 bonus star, since it is from the black forest, which is 1 biome behind the swamp.";
				streamWriter4.WriteLine(value4);
				streamWriter4.WriteLine(Levels.YamlCreatureDefinition());
			}
			if (!flag5)
			{
				Logger.LogInfo((object)"WildShrineConfig file missing, recreating.");
				using StreamWriter streamWriter5 = new StreamWriter(wildShrineConfigurationFilePath);
				string value5 = "###################################################################################################################################################\n# Wild Shrine Configuration\n###################################################################################################################################################\n# wildShrines:\n# - definitionForWildShrine: VF_wild_shrine_green1                    |- The prefab that this set of configuration will be applied to\n#   wildShrineNameLocalization: $wild_shrine_green                    |- The localization for the prefabs name (when hovered over) this uses a lookup value but defaults to its literal value\n#   wildShrineRequestLocalization: $wild_shrine_green_request         |- What the shrine says when you interact with it\n#   shrineUnacceptedTributeLocalization: $wild_shrine_not_interested  |- What the shrine says when you offer an incorrect tribute\n#   shrineLargerTributeRequiredLocalization: $wild_shrine_hungry      |- What the shrine says when you do not offer enough tribute\n#   wildShrineLevelsConfig:                                           |- Level configurations related to this shrine\n#   - tributeName: TrophyBoar                                         |- The prefab name of the tribute required to activate this level\n#     tributeAmount: 4                                                |- Amount of the tribute required to activate this level\n#     rewards:                                                        |- Rewards for this level in the format of Prefab: cost eg: RawMeat: 14.\n#       LeatherScraps: 14\n#       RawMeat: 12\n#     hardMode: false                                                 |- If hardmode should be enabled for this level (doubles the spawn point pool and gives 50% more rewards)\n#     siegeMode: false                                                |- If siege mode should be enabled for this level (double the number of waves 4->8 and gives 50% more rewards)\n#     wildshrineWaveStartLocalization: $wild_boars_attack             |- Localization text to display when this wave starts\n#     wildshrineWaveEndLocalization: $wild_boars_defeated             |- Localization text to display when this wave is finished\n#     wildLevelDefinition:\n#       levelIndex: 2                                                 |- The difficulty level for this wave, valid values are 1+ (Refer to the readme for a breakdown of this equation)\n#       biome: Meadows                                                |- The biome this wave is for, this impacts creature selection\n#       waveFormat: Tutorial                                          |- The wavestyle this uses (from wavestyles.yml), this governs which catagories and the percentage makeup of the wave\n#       levelWarningLocalization: $meadows_warning_wilderness         |- Localization for a between phase warning (often not used)\n#       maxCreaturesPerPhaseOverride: 15                              |- Overrides the max creatures per wave to be this value (overrides the global config)\n#       onlySelectMonsters:                                           |- Set of monsters that can be selected (From monsters.yml)\n#       - Boar\n#       - Greyling\n#       excludeSelectMonsters:                                        |- Set of monsters that can't be selected (from monsters.yml) best used when OnlySelected is not set.\n#       commonSpawnModifiers:                                         |- Spawn modifiers for common creatures\n#         linearIncreaseRandomWaveAdjustment: true\n#       rareSpawnModifiers:                                           |- Spawn modifiers for rare creatures\n#       eliteSpawnModifiers:                                          |- Spawn modifiers for elite creatures\n";
				streamWriter5.WriteLine(value5);
				streamWriter5.WriteLine(WildShrineData.YamlWildShrineDefinition());
			}
			string input = File.ReadAllText(creatureFilePath);
			string input2 = File.ReadAllText(rewardFilePath);
			string input3 = File.ReadAllText(waveStylesFilePath);
			string input4 = File.ReadAllText(levelDefinitionsFilePath);
			string input5 = File.ReadAllText(wildShrineConfigurationFilePath);
			try
			{
				WaveFormatCollection waveStyles = CONST.yamldeserializer.Deserialize<WaveFormatCollection>(input3);
				Levels.UpdateWaveDefinition(waveStyles);
			}
			catch (Exception arg)
			{
				Logger.LogWarning((object)$"There was an error updating the waveStyle values, defaults will be used. Exception: {arg}");
			}
			try
			{
				SpawnableCreatureCollection spawnables = CONST.yamldeserializer.Deserialize<SpawnableCreatureCollection>(input);
				Levels.UpdateSpawnableCreatures(spawnables);
			}
			catch (Exception arg2)
			{
				Logger.LogWarning((object)$"There was an error updating the creature values, defaults will be used. Exception: {arg2}");
			}
			try
			{
				RewardEntryCollection rewards = CONST.yamldeserializer.Deserialize<RewardEntryCollection>(input2);
				RewardsData.UpdateRewardsEntries(rewards);
			}
			catch (Exception arg3)
			{
				Logger.LogWarning((object)$"There was an error updating the rewards values, defaults will be used. Exception: {arg3}");
			}
			try
			{
				ChallengeLevelDefinitionCollection levelDefinitions = CONST.yamldeserializer.Deserialize<ChallengeLevelDefinitionCollection>(input4);
				Levels.UpdateLevelsDefinition(levelDefinitions);
			}
			catch (Exception arg4)
			{
				Logger.LogWarning((object)$"There was an error updating the levelDefinitions values, defaults will be used. Exception: {arg4}");
			}
			try
			{
				WildShrineConfigurationCollection wildShrineDefinitions = CONST.yamldeserializer.Deserialize<WildShrineConfigurationCollection>(input5);
				WildShrineData.UpdateWildShrineDefinition(wildShrineDefinitions);
			}
			catch (Exception arg5)
			{
				Logger.LogWarning((object)$"There was an error updating the WildShrine values, defaults will be used. Exception: {arg5}");
			}
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher();
			fileSystemWatcher.Path = secondaryConfigDirectoryPath;
			fileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;
			fileSystemWatcher.Filter = "Levels.yaml";
			fileSystemWatcher.Changed += UpdateLevelsConfigFileOnChange;
			fileSystemWatcher.Created += UpdateLevelsConfigFileOnChange;
			fileSystemWatcher.Renamed += UpdateLevelsConfigFileOnChange;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
			FileSystemWatcher fileSystemWatcher2 = new FileSystemWatcher();
			fileSystemWatcher2.Path = secondaryConfigDirectoryPath;
			fileSystemWatcher2.NotifyFilter = NotifyFilters.LastWrite;
			fileSystemWatcher2.Filter = "WaveStyles.yaml";
			fileSystemWatcher2.Changed += UpdateWavesConfigFileOnChange;
			fileSystemWatcher2.Created += UpdateWavesConfigFileOnChange;
			fileSystemWatcher2.Renamed += UpdateWavesConfigFileOnChange;
			fileSystemWatcher2.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher2.EnableRaisingEvents = true;
			FileSystemWatcher fileSystemWatcher3 = new FileSystemWatcher();
			fileSystemWatcher3.Path = secondaryConfigDirectoryPath;
			fileSystemWatcher3.NotifyFilter = NotifyFilters.LastWrite;
			fileSystemWatcher3.Filter = "SpawnableCreatures.yaml";
			fileSystemWatcher3.Changed += UpdateCreatureConfigFileOnChange;
			fileSystemWatcher3.Created += UpdateCreatureConfigFileOnChange;
			fileSystemWatcher3.Renamed += UpdateCreatureConfigFileOnChange;
			fileSystemWatcher3.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher3.EnableRaisingEvents = true;
			FileSystemWatcher fileSystemWatcher4 = new FileSystemWatcher();
			fileSystemWatcher4.Path = secondaryConfigDirectoryPath;
			fileSystemWatcher4.NotifyFilter = NotifyFilters.LastWrite;
			fileSystemWatcher4.Filter = "Rewards.yaml";
			fileSystemWatcher4.Changed += UpdateRewardsConfigFileOnChange;
			fileSystemWatcher4.Created += UpdateRewardsConfigFileOnChange;
			fileSystemWatcher4.Renamed += UpdateRewardsConfigFileOnChange;
			fileSystemWatcher4.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher4.EnableRaisingEvents = true;
			FileSystemWatcher fileSystemWatcher5 = new FileSystemWatcher();
			fileSystemWatcher5.Path = secondaryConfigDirectoryPath;
			fileSystemWatcher5.NotifyFilter = NotifyFilters.LastWrite;
			fileSystemWatcher5.Filter = "WildShrines.yaml";
			fileSystemWatcher5.Changed += UpdateWildShrineConfigFileOnChange;
			fileSystemWatcher5.Created += UpdateWildShrineConfigFileOnChange;
			fileSystemWatcher5.Renamed += UpdateWildShrineConfigFileOnChange;
			fileSystemWatcher5.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher5.EnableRaisingEvents = true;
		}

		public static IEnumerator OnServerRecieveConfigs(long sender, ZPackage package)
		{
			if (EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Server recieved config from client, rejecting due to being the server.");
			}
			yield return null;
		}

		private static ZPackage SendCreatureConfigs()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			string text = File.ReadAllText(creatureFilePath);
			ZPackage val = new ZPackage();
			val.Write(text);
			return val;
		}

		private static ZPackage SendWavesConfigs()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			string text = File.ReadAllText(waveStylesFilePath);
			ZPackage val = new ZPackage();
			val.Write(text);
			return val;
		}

		private static ZPackage SendRewardsConfigs()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			string text = File.ReadAllText(rewardFilePath);
			ZPackage val = new ZPackage();
			val.Write(text);
			return val;
		}

		private static ZPackage SendLevelsConfigs()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			string text = File.ReadAllText(levelDefinitionsFilePath);
			ZPackage val = new ZPackage();
			val.Write(text);
			return val;
		}

		private static ZPackage SendWildShrineConfigs()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			string text = File.ReadAllText(wildShrineConfigurationFilePath);
			ZPackage val = new ZPackage();
			val.Write(text);
			return val;
		}

		private static IEnumerator OnClientReceiveCreatureConfigs(long sender, ZPackage package)
		{
			string creatureyaml = package.ReadString();
			using (StreamWriter writetext = new StreamWriter(creatureFilePath))
			{
				writetext.WriteLine(creatureyaml);
			}
			yield return null;
		}

		private static IEnumerator OnClientReceiveRewardsConfigs(long sender, ZPackage package)
		{
			string rewardsyaml = package.ReadString();
			using (StreamWriter writetext = new StreamWriter(rewardFilePath))
			{
				writetext.WriteLine(rewardsyaml);
			}
			yield return null;
		}

		private static IEnumerator OnClientReceiveWaveConfigs(long sender, ZPackage package)
		{
			string wavesyaml = package.ReadString();
			using (StreamWriter writetext = new StreamWriter(waveStylesFilePath))
			{
				writetext.WriteLine(wavesyaml);
			}
			yield return null;
		}

		private static IEnumerator OnClientReceiveLevelConfigs(long sender, ZPackage package)
		{
			string levelsyaml = package.ReadString();
			using (StreamWriter writetext = new StreamWriter(levelDefinitionsFilePath))
			{
				writetext.WriteLine(levelsyaml);
			}
			yield return null;
		}

		private static IEnumerator OnClientReceiveWildShrineConfigs(long sender, ZPackage package)
		{
			string levelsyaml = package.ReadString();
			using (StreamWriter writetext = new StreamWriter(wildShrineConfigurationFilePath))
			{
				writetext.WriteLine(levelsyaml);
			}
			yield return null;
		}

		private static void UpdateLevelsConfigFileOnChange(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(levelDefinitionsFilePath))
			{
				return;
			}
			if (EnableDebugMode.Value)
			{
				Logger.LogInfo((object)$"{e} Creature filewatcher called, updating creature values.");
			}
			string input = File.ReadAllText(levelDefinitionsFilePath);
			ChallengeLevelDefinitionCollection levelDefinitions;
			try
			{
				levelDefinitions = CONST.yamldeserializer.Deserialize<ChallengeLevelDefinitionCollection>(input);
			}
			catch
			{
				if (EnableDebugMode.Value)
				{
					Logger.LogWarning((object)"Creatures failed deserializing, skipping update.");
				}
				return;
			}
			Levels.UpdateLevelsDefinition(levelDefinitions);
			if (EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Updated levels in-memory values.");
			}
			if (GUIManager.IsHeadless())
			{
				try
				{
					LevelsSyncRPC.SendPackage(ZNet.instance.m_peers, SendLevelsConfigs());
					if (EnableDebugMode.Value)
					{
						Logger.LogInfo((object)"Sent levels configs to clients.");
					}
					return;
				}
				catch
				{
					Logger.LogError((object)"Error while server syncing creature configs");
					return;
				}
			}
			if (EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Instance is not a server, and will not send znet creature updates.");
			}
		}

		private static void UpdateCreatureConfigFileOnChange(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(creatureFilePath))
			{
				return;
			}
			if (EnableDebugMode.Value)
			{
				Logger.LogInfo((object)$"{e} Creature filewatcher called, updating creature values.");
			}
			string input = File.ReadAllText(creatureFilePath);
			SpawnableCreatureCollection spawnables;
			try
			{
				spawnables = CONST.yamldeserializer.Deserialize<SpawnableCreatureCollection>(input);
			}
			catch
			{
				if (EnableDebugMode.Value)
				{
					Logger.LogWarning((object)"Creatures failed deserializing, skipping update.");
				}
				return;
			}
			Levels.UpdateSpawnableCreatures(spawnables);
			if (EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Updated creature in-memory values.");
			}
			if (GUIManager.IsHeadless())
			{
				try
				{
					monsterSyncRPC.SendPackage(ZNet.instance.m_peers, SendCreatureConfigs());
					if (EnableDebugMode.Value)
					{
						Logger.LogInfo((object)"Sent creature configs to clients.");
					}
					return;
				}
				catch
				{
					Logger.LogError((object)"Error while server syncing creature configs");
					return;
				}
			}
			if (EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Instance is not a server, and will not send znet creature updates.");
			}
		}

		private static void UpdateWavesConfigFileOnChange(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(waveStylesFilePath))
			{
				return;
			}
			if (EnableDebugMode.Value)
			{
				Logger.LogInfo((object)$"{e} Wavestyles filewatcher called, updating Wavestyles values.");
			}
			string input = File.ReadAllText(waveStylesFilePath);
			WaveFormatCollection waveStyles;
			try
			{
				waveStyles = CONST.yamldeserializer.Deserialize<WaveFormatCollection>(input);
			}
			catch
			{
				if (EnableDebugMode.Value)
				{
					Logger.LogWarning((object)"Wavestyles failed deserializing, skipping update.");
				}
				return;
			}
			Levels.UpdateWaveDefinition(waveStyles);
			if (EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Updated WaveDefinition in-memory values.");
			}
			if (GUIManager.IsHeadless())
			{
				try
				{
					WavesSyncRPC.SendPackage(ZNet.instance.m_peers, SendWavesConfigs());
					if (EnableDebugMode.Value)
					{
						Logger.LogInfo((object)"Sent WaveDefinition configs to clients.");
					}
					return;
				}
				catch
				{
					Logger.LogError((object)"Error while server syncing Wave configs");
					return;
				}
			}
			if (EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Instance is not a server, and will not send znet creature updates.");
			}
		}

		private static void UpdateRewardsConfigFileOnChange(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(rewardFilePath))
			{
				return;
			}
			if (EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Rewards filewatcher called, updating rewards values.");
			}
			string input = File.ReadAllText(rewardFilePath);
			RewardEntryCollection rewards;
			try
			{
				rewards = CONST.yamldeserializer.Deserialize<RewardEntryCollection>(input);
			}
			catch (Exception)
			{
				if (EnableDebugMode.Value)
				{
					Logger.LogWarning((object)"Rewards failed deserializing, skipping update.");
				}
				return;
			}
			RewardsData.UpdateRewardsEntries(rewards);
			if (EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Updated rewards in-memory values.");
			}
			if (GUIManager.IsHeadless())
			{
				try
				{
					rewardSyncRPC.SendPackage(ZNet.instance.m_peers, SendRewardsConfigs());
					if (EnableDebugMode.Value)
					{
						Logger.LogInfo((object)"Sent rewards configs to clients.");
					}
					return;
				}
				catch (Exception)
				{
					Logger.LogError((object)"Error while server syncing rewards configs");
					return;
				}
			}
			if (EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Instance is not a server, and will not send znet reward updates.");
			}
		}

		private static void UpdateWildShrineConfigFileOnChange(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(rewardFilePath))
			{
				return;
			}
			if (EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Rewards filewatcher called, updating Wildshrines values.");
			}
			string input = File.ReadAllText(wildShrineConfigurationFilePath);
			WildShrineConfigurationCollection wildShrineDefinitions;
			try
			{
				wildShrineDefinitions = CONST.yamldeserializer.Deserialize<WildShrineConfigurationCollection>(input);
			}
			catch (Exception)
			{
				if (EnableDebugMode.Value)
				{
					Logger.LogWarning((object)"WildShrineConfigs failed deserializing, skipping update.");
				}
				return;
			}
			WildShrineData.UpdateWildShrineDefinition(wildShrineDefinitions);
			if (EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Updated WildshrineConfigs in-memory values.");
			}
			if (GUIManager.IsHeadless())
			{
				try
				{
					WildShrineSyncRPC.SendPackage(ZNet.instance.m_peers, SendWildShrineConfigs());
					if (EnableDebugMode.Value)
					{
						Logger.LogInfo((object)"Sent Wildshrine configs to clients.");
					}
					return;
				}
				catch (Exception)
				{
					Logger.LogError((object)"Error while server syncing Wildshrine configs");
					return;
				}
			}
			if (EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Instance is not a server, and will not send znet reward updates.");
			}
		}

		private static void UpdateMainConfigFile(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(creatureFilePath))
			{
				return;
			}
			try
			{
				cfg.SaveOnConfigSet = false;
				cfg.Reload();
				cfg.SaveOnConfigSet = true;
			}
			catch
			{
				Logger.LogError((object)"There was an issue reloading MidnightsFX.ValheimFortress.cfg.");
			}
		}

		public ConfigEntry<bool> BindServerConfig(string catagory, string key, bool value, string description, bool advanced = false)
		{
			//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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			return cfg.Bind<bool>(catagory, key, value, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public ConfigEntry<string> BindServerConfig(string catagory, string key, string value, string description, bool advanced = false)
		{
			//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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			return cfg.Bind<string>(catagory, key, value, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public ConfigEntry<short> BindServerConfig(string catagory, string key, short value, string description, bool advanced = false, short valmin = 0, short valmax = 150)
		{
			//IL_001c: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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
			return cfg.Bind<short>(catagory, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<short>(valmin, valmax), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public ConfigEntry<float> BindServerConfig(string catagory, string key, float value, string description, bool advanced = false, float valmin = 0f, float valmax = 150f)
		{
			//IL_001c: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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
			return cfg.Bind<float>(catagory, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(valmin, valmax), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		private void CreateConfigValues(ConfigFile Config)
		{
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: 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_025b: Expected O, but got Unknown
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Expected O, but got Unknown
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: 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_029e: Expected O, but got Unknown
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Expected O, but got Unknown
			MaxSpawnRange = BindServerConfig("Shrine of Challenge", "MaxSpawnRange", 100, "The radius around the shrine that enemies can spawn in.", advanced: false, 10, 800);
			EnableHardModifier = BindServerConfig("Shrine of Challenge", "EnableHardModifier", value: true, "Whether or not the hard mode modifier is available (100% bigger wave size for 50% more rewards)", advanced: true);
			EnableBossModifier = BindServerConfig("Shrine of Challenge", "EnableBossModifier", value: true, "Whether or not boss mod is available as a level modifier (more rewards & spawns the biome specific boss)", advanced: true);
			EnableSiegeModifer = BindServerConfig("Shrine of Challenge", "EnableSiegeModifer", value: true, "Whether or not siege mode is available as a modifier. Siege mode gives much larger pauses between waves, and 100% larger waves for 50% more reward.", advanced: true);
			EnableMapPings = BindServerConfig("Shrine of Challenge", "EnableMapPings", value: false, "Whether or not waves spawning from the shrine of challenge should ping the map when they spawn.", advanced: true);
			EnableRewardsEstimate = BindServerConfig("Shrine of Challenge", "EnableRewardsEstimate", value: true, "Enables showing an estimate of how many rewards you will get for doing the selected level for the specified reward.", advanced: true);
			rewardsMultiplier = BindServerConfig("Shrine of Challenge", "rewardsMultiplier", 1.1f, "The base multiplier for rewards, higher values will make every wave more rewarding", advanced: true);
			rewardsDifficultyScalar = BindServerConfig("Shrine of Challenge", "rewardsDifficultyScalar", 0.02f, "Multiplier for rewards that scales with level, each level adds this to the value, making high level challenges much more rewarding.", advanced: true);
			MaxRewardsPerSecond = BindServerConfig("Shrine of Challenge", "MaxRewardsPerSecond", 120, "Sets how fast the shrine will spawn rewards. Reducing this will reduce the performance impact of spawning so many items at once.", advanced: true, 10, 400);
			NotifyCreatureThreshold = BindServerConfig("Shrine of Challenge", "NotifyCreatureThreshold", 10, "Sets the level at which interacting with the shrine will add notifier to remaining creatures.", advanced: true, 1, 50);
			TeleportCreatureThreshold = BindServerConfig("Shrine of Challenge", "TeleportCreatureThreshold", 3, "Sets the level at which interacting with the shrine teleport remaining creatures to the shrine.", advanced: true, 1, 50);
			ShrineAnnouncementRange = BindServerConfig("Shrine of Challenge", "ShrineAnnouncementRange", 150f, "Sets the range at which announcements will display for shrine of challenge related activities", advanced: true, 50f, 800f);
			DistanceBetweenShrines = BindServerConfig("Wild Shrines", "DistanceBetweenShrines", 1000f, "The mimum distance between shrines, setting this higher will result in fewer wild shrines, lower more.", advanced: true, 100f, 5000f);
			NumberOfEachWildShrine = BindServerConfig("Wild Shrines", "NumberOfEachWildShrine", 100, "Each wild shrine type will attempt to be placed this many times", advanced: true, 5, 200);
			ChallengeShrineMaxCreaturesPerWave = BindServerConfig("Shrine of Challenge", "max_creatures_per_wave", 60, "The max number of creatures that a wave can generate with, creatures will attempt to upgrade and reduce counts based on this.", advanced: true, 12, 200);
			ArenaShrineMaxCreaturesPerWave = BindServerConfig("Shrine of Arena", "max_creatures_per_wave", 25, "The max number of creatures that a wave can generate with, creatures will attempt to upgrade and reduce counts based on this.", advanced: true, 12, 200);
			EnableDebugMode = Config.Bind<bool>("Client config", "EnableDebugMode", false, new ConfigDescription("Enables Debug logging for Valheim Fortress.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = false,
				IsAdvanced = true
			} }));
			EnableTurretDebugMode = Config.Bind<bool>("Client config", "EnableTurretDebugMode", false, new ConfigDescription("Enables debug mode for turrets, this can be noisy.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = false,
				IsAdvanced = true
			} }));
		}
	}
	internal class VFLocations
	{
		public VFLocations(AssetBundle EmbeddedResourceBundle, VFConfig cfg)
		{
			AddWildShrineLocationWithWorldGen(cfg, EmbeddedResourceBundle.LoadAsset<GameObject>("Assets/Custom/Locations/VFortress/VF_wild_shrine_green1.prefab"), (Biome)1);
			AddWildShrineLocationWithWorldGen(cfg, EmbeddedResourceBundle.LoadAsset<GameObject>("Assets/Custom/Locations/VFortress/VF_wild_shrine_blue1.prefab"), (Biome)8);
			AddWildShrineLocationWithWorldGen(cfg, EmbeddedResourceBundle.LoadAsset<GameObject>("Assets/Custom/Locations/VFortress/VF_wild_shrine_green2.prefab"), (Biome)2);
			AddWildShrineLocationWithWorldGen(cfg, EmbeddedResourceBundle.LoadAsset<GameObject>("Assets/Custom/Locations/VFortress/VF_wild_shrine_blue2.prefab"), (Biome)4);
			AddWildShrineLocationWithWorldGen(cfg, EmbeddedResourceBundle.LoadAsset<GameObject>("Assets/Custom/Locations/VFortress/VF_wild_shrine_yellow1.prefab"), (Biome)16);
			AddWildShrineLocationWithWorldGen(cfg, EmbeddedResourceBundle.LoadAsset<GameObject>("Assets/Custom/Locations/VFortress/VF_wild_shrine_purple1.prefab"), (Biome)512);
		}

		public void AddWildShrineLocationWithWorldGen(VFConfig cfg, GameObject prefab, Biome biome)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_006e: 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_00e1: Expected O, but got Unknown
			if (!cfg.BindServerConfig("Wild Shrines", $"{prefab}-Enable", value: true, $"Enable/Disable the {prefab} wildshrine.").Value)
			{
				if (VFConfig.EnableDebugMode.Value)
				{
					Logger.LogInfo((object)$"Skipped loading location {prefab}");
				}
				return;
			}
			prefab.AddComponent<WildShrine>();
			prefab.AddComponent<Spawner>();
			LocationConfig val = new LocationConfig();
			val.Biome = biome;
			val.Quantity = VFConfig.NumberOfEachWildShrine.Value;
			val.Priotized = false;
			val.ExteriorRadius = 5f;
			val.SlopeRotation = true;
			val.MinAltitude = 1f;
			val.ClearArea = true;
			val.RandomRotation = false;
			val.MinDistanceFromSimilar = VFConfig.DistanceBetweenShrines.Value;
			ZoneManager.Instance.AddCustomLocation(new CustomLocation(prefab, true, val));
		}
	}
}
namespace ValheimFortress.Defenses
{
	public class VFTurret : MonoBehaviour, Hoverable, IPieceMarker
	{
		private static float m_turnRate = 80f;

		private static float m_horizontalAngle = 85f;

		private static float m_viewDistance = 25f;

		private static float m_noTargetScanRate = 12f;

		private static float m_attackCooldown = 2f;

		private static float m_hitNoise = 10f;

		private static float m_shootWhenAimDiff = 0.99f;

		private static float m_ammo_accuracy = 0.05f;

		private static float m_predictionModifier = 1f;

		private static float m_updateTargetIntervalNear = 2f;

		private static float m_updateTargetIntervalFar = 8f;

		public static float m_markerHideTime = 0.5f;

		private GameObject m_Projectile;

		private ItemData m_Ammo;

		private GameObject m_shootEffect;

		private GameObject m_reloadEffect;

		private GameObject m_newTargetEffect;

		private GameObject m_lostTargetEffect;

		private ZNetView m_nview;

		private Character m_target = null;

		private GameObject turretBodyArmed;

		private GameObject turretBodyUnarmed;

		private GameObject turretBodyArmedBolt;

		private GameObject turretBody;

		private GameObject turretNeck;

		private GameObject eye;

		private CircleProjector areaMarker;

		private Quaternion m_baseBodyRotation;

		private Quaternion m_baseNeckRotation;

		private static bool m_haveTarget = false;

		private static float m_aimDiffToTarget = -1f;

		private static float m_updateTargetTimer = 0f;

		private static float m_scan = 0f;

		protected void Awake()
		{
			//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_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)
			m_nview = ((Component)this).GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)m_nview))
			{
				m_nview.Register<ZDOID>("RPC_SetTarget", (Action<long, ZDOID>)RPC_SetTarget);
			}
			m_updateTargetTimer = Random.Range(0f, m_updateTargetIntervalNear);
			if (Object.op_Implicit((Object)(object)m_nview))
			{
				GameObject gameObject = ((Component)((Component)this).transform.Find("New")).gameObject;
				GameObject gameObject2 = ((Component)gameObject.transform.Find("Base")).gameObject;
				GameObject gameObject3 = ((Component)gameObject.transform.Find("NeckRotation")).gameObject;
				GameObject gameObject4 = ((Component)gameObject3.transform.GetChild(0)).gameObject;
				turretNeck = gameObject3;
				m_baseNeckRotation = turretNeck.transform.localRotation;
				GameObject val = (turretBody = ((Component)gameObject.transform.Find("BodyRotation")).gameObject);
				m_baseBodyRotation = turretBody.transform.localRotation;
				turretBodyArmed = ((Component)val.transform.Find("Body")).gameObject;
				turretBodyUnarmed = ((Component)val.transform.Find("Body_Unarmed")).gameObject;
				turretBodyArmedBolt = ((Component)val.transform.Find("Bolt Black Metal")).gameObject;
				eye = ((Component)val.transform.Find("Eye")).gameObject;
				m_Projectile = PrefabManager.Instance.GetPrefab("TurretBolt");
				m_Ammo = m_Projectile.GetComponent<ItemDrop>().m_itemData;
				areaMarker = ((Component)((Component)this).transform.Find("AreaMarker")).gameObject.GetComponent<CircleProjector>();
				m_shootEffect = PrefabManager.Instance.GetPrefab("fx_turret_fire");
				m_reloadEffect = PrefabManager.Instance.GetPrefab("fx_turret_reload");
				m_newTargetEffect = PrefabManager.Instance.GetPrefab("fx_turret_newtarget");
				m_lostTargetEffect = PrefabManager.Instance.GetPrefab("fx_turret_notarget");
			}
		}

		private void FixedUpdate()
		{
			//IL_006b: 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)
			float fixedDeltaTime = Time.fixedDeltaTime;
			UpdateMarker(fixedDeltaTime);
			if (!m_nview.IsValid())
			{
				return;
			}
			UpdateTurretRotation();
			if (m_nview.IsOwner() && !IsCoolingDown())
			{
				if (!turretBodyArmed.activeSelf)
				{
					Object.Instantiate<GameObject>(m_reloadEffect, turretBodyArmed.transform.position, turretBodyArmed.transform.rotation);
					turretBodyArmed.SetActive(true);
					turretBodyArmedBolt.SetActive(true);
					turretBodyUnarmed.SetActive(false);
				}
				UpdateTarget(fixedDeltaTime);
				ShootProjectile(fixedDeltaTime);
			}
		}

		private void UpdateTurretRotation()
		{
			//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_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_0071: 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_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_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_009b: 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_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_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: 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_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_017c: 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_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_0191: 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_0199: 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_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: 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_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fa: 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_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_031d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: 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_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			float fixedDeltaTime = Time.fixedDeltaTime;
			bool flag = Object.op_Implicit((Object)(object)m_target);
			Vector3 val2;
			Quaternion rotation;
			if (flag)
			{
				float num = Vector2.Distance(Vector2.op_Implicit(((Component)m_target).transform.position), Vector2.op_Implicit(eye.transform.position)) / (m_Ammo.m_shared.m_attack.m_projectileVel * 2f);
				Vector3 val = m_target.GetVelocity() * num * m_predictionModifier;
				val2 = ((Component)m_target).transform.position + val - turretBody.transform.position;
				ref float y = ref val2.y;
				float num2 = y;
				CapsuleCollider componentInChildren = ((Component)m_target).GetComponentInChildren<CapsuleCollider>();
				y = num2 + ((componentInChildren != null) ? (componentInChildren.height / 2f) : 1f);
			}
			else
			{
				m_scan += fixedDeltaTime;
				if (m_scan > m_noTargetScanRate * 2f)
				{
					m_scan = 0f;
				}
				rotation = ((Component)this).transform.rotation;
				val2 = Quaternion.Euler(0f, ((Quaternion)(ref rotation)).eulerAngles.y + (float)((m_scan - m_noTargetScanRate > 0f) ? 1 : (-1)) * (m_horizontalAngle / 2f), 0f) * Vector3.forward;
			}
			((Vector3)(ref val2)).Normalize();
			Quaternion val3 = Quaternion.LookRotation(val2, Vector3.up);
			Vector3 eulerAngles = ((Quaternion)(ref val3)).eulerAngles;
			rotation = ((Component)this).transform.rotation;
			float y2 = ((Quaternion)(ref rotation)).eulerAngles.y;
			eulerAngles.y -= y2;
			if (m_horizontalAngle >= 0f)
			{
				float num3 = eulerAngles.y;
				if (num3 > 180f)
				{
					num3 -= 360f;
				}
				else if (num3 < -180f)
				{
					num3 += 360f;
				}
				if (num3 > m_horizontalAngle)
				{
					((Vector3)(ref eulerAngles))..ctor(eulerAngles.x, m_horizontalAngle + y2, eulerAngles.z);
					((Quaternion)(ref val3)).eulerAngles = eulerAngles;
				}
				else if (num3 < 0f - m_horizontalAngle)
				{
					((Vector3)(ref eulerAngles))..ctor(eulerAngles.x, 0f - m_horizontalAngle + y2, eulerAngles.z);
					((Quaternion)(ref val3)).eulerAngles = eulerAngles;
				}
			}
			Quaternion val4 = Quaternion.RotateTowards(turretBody.transform.rotation, val3, m_turnRate * fixedDeltaTime);
			turretBody.transform.rotation = m_baseBodyRotation * val4;
			Transform transform = turretNeck.transform;
			Quaternion baseNeckRotation = m_baseNeckRotation;
			rotation = turretBody.transform.rotation;
			float y3 = ((Quaternion)(ref rotation)).eulerAngles.y;
			rotation = turretBody.transform.rotation;
			transform.rotation = baseNeckRotation * Quaternion.Euler(0f, y3, ((Quaternion)(ref rotation)).eulerAngles.z);
			m_aimDiffToTarget = (flag ? Math.Abs(Quaternion.Dot(val4, val3)) : (-1f));
		}

		private void UpdateTarget(float dt)
		{
			//IL_002a: 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_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: 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_00af: 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_0089: 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_00db: Unknown result type (might be due to invalid IL or missing references)
			m_updateTargetTimer -= dt;
			if (m_updateTargetTimer <= 0f)
			{
				m_updateTargetTimer = (Character.IsCharacterInRange(((Component)this).transform.position, 40f) ? m_updateTargetIntervalNear : m_updateTargetIntervalFar);
				Character val = selectTarget();
				if ((Object)(object)val != (Object)(object)m_target)
				{
					if (Object.op_Implicit((Object)(object)val))
					{
						Object.Instantiate<GameObject>(m_newTargetEffect, ((Component)this).transform.position, ((Component)this).transform.rotation);
					}
					else
					{
						Object.Instantiate<GameObject>(m_lostTargetEffect, ((Component)this).transform.position, ((Component)this).transform.rotation);
					}
					m_nview.InvokeRPC(ZNetView.Everybody, "RPC_SetTarget", new object[1] { Object.op_Implicit((Object)(object)val) ? val.GetZDOID() : ZDOID.None });
				}
			}
			if (m_haveTarget && (!Object.op_Implicit((Object)(object)m_target) || m_target.IsDead()))
			{
				m_nview.InvokeRPC(ZNetView.Everybody, "RPC_SetTarget", new object[1] { ZDOID.None });
				Object.Instantiate<GameObject>(m_lostTargetEffect, ((Component)this).transform.position, ((Component)this).transform.rotation);
			}
		}

		private bool IsValidTarget(Character ptarget)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (ptarget.IsDead() || ptarget.IsTamed() || ptarget.IsPlayer())
			{
				return false;
			}
			if ((int)ptarget.GetFaction() == 0 || ptarget is Player)
			{
				return false;
			}
			return true;
		}

		private Character selectTarget()
		{
			//IL_004d: 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)
			List<Character> allCharacters = Character.GetAllCharacters();
			Character val = null;
			foreach (Character item in allCharacters)
			{
				if (!IsValidTarget(item))
				{
					continue;
				}
				BaseAI baseAI = item.GetBaseAI();
				if (!baseAI.IsSleeping())
				{
					float num = Vector3.Distance(((Component)this).transform.position, ((Component)item).transform.position);
					if (num < m_viewDistance)
					{
						val = item;
						break;
					}
				}
			}
			if ((Object)(object)val != (Object)null && VFConfig.EnableTurretDebugMode.Value)
			{
				Logger.LogInfo((object)$"Selected target: {val}");
			}
			return val;
		}

		public void ShootProjectile(float dt)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: 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_0107: 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_0112: 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_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_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: 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_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_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_017a: 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_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Expected O, but got Unknown
			//IL_01f4: 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_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)m_target) && m_aimDiffToTarget > m_shootWhenAimDiff && !IsCoolingDown())
			{
				if (VFConfig.EnableTurretDebugMode.Value)
				{
					Logger.LogInfo((object)$"Turret target status:{!Object.op_Implicit((Object)(object)m_target)} aimdiff:{m_aimDiffToTarget} > {m_shootWhenAimDiff} ({!(m_aimDiffToTarget > m_shootWhenAimDiff)}) cooldown:{IsCoolingDown()}");
				}
				Object.Instantiate<GameObject>(m_shootEffect, turretBodyArmed.transform.position, eye.transform.rotation);
				m_nview.GetZDO().Set("lastAttack", (float)ZNet.instance.GetTimeSeconds());
				Vector3 forward = eye.transform.forward;
				Vector3 val = Vector3.Cross(forward, Vector3.up);
				float ammo_accuracy = m_ammo_accuracy;
				Quaternion val2 = Quaternion.AngleAxis(Random.Range(0f - ammo_accuracy, ammo_accuracy), Vector3.up);
				forward = Quaternion.AngleAxis(Random.Range(0f - ammo_accuracy, ammo_accuracy), val) * forward;
				forward = val2 * forward;
				GameObject val3 = Object.Instantiate<GameObject>(m_Ammo.m_shared.m_attack.m_attackProjectile, eye.transform.position, eye.transform.rotation);
				HitData val4 = new HitData();
				val4.m_pushForce = m_Ammo.m_shared.m_attackForce;
				val4.m_backstabBonus = m_Ammo.m_shared.m_backstabBonus;
				val4.m_staggerMultiplier = m_Ammo.m_shared.m_attack.m_staggerMultiplier;
				((DamageTypes)(ref val4.m_damage)).Add(m_Ammo.GetDamage(), 1);
				val4.m_blockable = m_Ammo.m_shared.m_blockable;
				val4.m_dodgeable = m_Ammo.m_shared.m_dodgeable;
				val4.m_skill = m_Ammo.m_shared.m_skillType;
				IProjectile component = val3.GetComponent<IProjectile>();
				if (component != null)
				{
					component.Setup((Character)null, forward * (m_Ammo.m_shared.m_attack.m_projectileVel * 2f), m_hitNoise, val4, (ItemData)null, m_Ammo);
				}
				turretBodyArmed.SetActive(false);
				turretBodyArmedBolt.SetActive(false);
				turretBodyUnarmed.SetActive(true);
			}
		}

		public bool IsCoolingDown()
		{
			if (!m_nview.IsValid())
			{
				return false;
			}
			return (double)(m_nview.GetZDO().GetFloat("lastAttack", 0f) + m_attackCooldown) > ZNet.instance.GetTimeSeconds();
		}

		public string GetHoverText()
		{
			if (!m_nview.IsValid())
			{
				return "";
			}
			return Localization.instance.Localize("$piece_vfturret");
		}

		public string GetHoverName()
		{
			return Localization.instance.Localize("$piece_vfturret");
		}

		private void RPC_SetTarget(long sender, ZDOID character)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = ZNetScene.instance.FindInstance(character);
			if (Object.op_Implicit((Object)(object)val))
			{
				Character component = val.GetComponent<Character>();
				if (component != null)
				{
					m_target = component;
					m_haveTarget = true;
					return;
				}
			}
			m_target = null;
			m_haveTarget = false;
			m_scan = 0f;
		}

		private void OnDestroyed()
		{
			((Component)this).GetComponent<WearNTear>().m_onDestroyed();
		}

		public void ShowHoverMarker()
		{
			ShowBuildMarker();
		}

		public void ShowBuildMarker()
		{
			if (!Object.op_Implicit((Object)(object)areaMarker))
			{
				areaMarker.m_radius = m_viewDistance;
				((Component)areaMarker).gameObject.SetActive(false);
			}
			if (Object.op_Implicit((Object)(object)areaMarker))
			{
				((Component)areaMarker).gameObject.SetActive(true);
				((MonoBehaviour)this).CancelInvoke("HideMarker");
				((MonoBehaviour)this).Invoke("HideMarker", m_markerHideTime);
			}
		}

		private void UpdateMarker(float dt)
		{
			//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_0035: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)areaMarker) && ((Behaviour)areaMarker).isActiveAndEnabled)
			{
				CircleProjector obj = areaMarker;
				Quaternion rotation = ((Component)this).transform.rotation;
				obj.m_start = ((Quaternion)(ref rotation)).eulerAngles.y - m_horizontalAngle;
				areaMarker.m_turns = m_horizontalAngle * 2f / 360f;
			}
		}

		private void HideMarker()
		{
			if (Object.op_Implicit((Object)(object)areaMarker))
			{
				((Component)areaMarker).gameObject.SetActive(false);
			}
		}
	}
}
namespace ValheimFortress.Challenge
{
	internal class ArenaShrine : GenericShrine
	{
		private static ArenaShrineUI ui_controller;

		private new static Vector3[] remote_spawn_locations = (Vector3[])(object)new Vector3[0];

		private static short fail_to_start = 0;

		public override string GetHoverName()
		{
			return Localization.instance.Localize("$piece_shrine_of_gladiator");
		}

		public override string GetHoverText()
		{
			string text = "[<color=yellow><b>$KEY_Use</b></color>] $piece_shrine_of_gladiator";
			return Localization.instance.Localize(text);
		}

		public override bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (hold)
			{
				return false;
			}
			if (base.challenge_active.Get())
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, $"Creatures remaining {base.spawned_creatures.Get()}", 0, (Sprite)null);
				ui_controller.DisplayCancelUI();
			}
			else
			{
				ui_controller.DisplayUI();
			}
			return true;
		}

		public override void StartChallengeMode()
		{
			if (!base.challenge_active.Get())
			{
				base.challenge_active.Set(value: true);
				base.currentPhase.Set(0);
				GenericShrine.spawn_controller.TrySpawningPhase(5f, send_message: false, GenericShrine.wave_phases_definitions.hordePhases[base.currentPhase.Get()], ((Component)this).gameObject, remote_spawn_locations);
				GenericShrine.phase_running = true;
				Logger.LogInfo((object)$"Challenge started. Level: {base.selected_level.Get()} Reward: {base.selected_reward.Get()}");
				base.start_challenge.Set(value: false);
				base.currentPhase.Set(base.currentPhase.Get() + 1);
				Logger.LogInfo((object)"Start challenge functions completed. Challenge started!");
			}
			else
			{
				if (VFConfig.EnableDebugMode.Value)
				{
					Logger.LogInfo((object)"Challenge mode is already active.");
				}
				fail_to_start++;
			}
			if (fail_to_start > 3)
			{
				if (VFConfig.EnableDebugMode.Value)
				{
					Logger.LogInfo((object)"Challenge mode failed to start, resetting.");
				}
				base.challenge_active.Set(value: false);
				base.wave_definition_ready.Set(value: false);
				base.spawn_locations_ready.Set(value: false);
				fail_to_start = 0;
				base.currentPhase.Set(0);
				base.start_challenge.Set(value: true);
			}
		}

		public override void Update()
		{
			//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_00aa: 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_00c1: 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_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			if (!zNetView.IsValid())
			{
				return;
			}
			if ((Object)(object)ui_controller == (Object)null || (Object)(object)GenericShrine.spawn_controller == (Object)null || (Object)(object)shrine_spawnpoint == (Object)null || remote_spawn_locations == null)
			{
				GenericShrine.spawn_controller = ((Component)this).gameObject.GetComponent<Spawner>();
				shrine_spawnpoint = ((Component)TransformExtensions.FindDeepChild(((Component)this).transform, "spawnpoint", (IterativeSearchType)1)).gameObject;
				remote_spawn_locations = (Vector3[])(object)new Vector3[3]
				{
					shrine_spawnpoint.transform.position,
					shrine_spawnpoint.transform.position,
					shrine_spawnpoint.transform.position
				};
				ui_controller = ((Component)this).gameObject.GetComponent<ArenaShrineUI>();
			}
			if (ui_controller.IsShrineOrCancelUIVisible() && Input.GetKeyDown((KeyCode)27))
			{
				Logger.LogInfo((object)"Shrine UI detected close commands.");
				ui_controller.HideUI();
				ui_controller.HideCancelUI();
			}
			if (base.challenge_active.Get())
			{
				if (!GenericShrine.shrine_portal_active)
				{
					EnablePortal();
				}
			}
			else if (base.end_of_challenge.Get())
			{
				Disableportal();
				base.end_of_challenge.ForceSet(value: false);
			}
			if (!zNetView.IsOwner())
			{
				return;
			}
			if (base.start_challenge.Get())
			{
				if (!base.wave_definition_ready.Get())
				{
					List<ChallengeLevelDefinition> challengeLevelDefinitions = Levels.GetChallengeLevelDefinitions();
					ChallengeLevelDefinition levelDefinition = challengeLevelDefinitions.ElementAt(base.selected_level.Get());
					GenericShrine.wave_phases_definitions = Levels.generateRandomWaveWithOptions(levelDefinition, base.hard_mode.Get(), base.boss_mode.Get(), base.siege_mode.Get(), VFConfig.ArenaShrineMaxCreaturesPerWave.Value);
					base.wave_definition_ready.Set(value: true);
				}
				if (base.wave_definition_ready.Get())
				{
					GenericShrine.SendUpdatedPhaseConfigs();
					StartChallengeMode();
				}
			}
			else
			{
				if (!base.challenge_active.Get() || GenericShrine.wave_phases_definitions.hordePhases.Count <= 0 || GenericShrine.enemies.Count <= 0 || base.spawned_creatures.Get() > 0 || GenericShrine.phase_running)
				{
					return;
				}
				if (RemainingPhases())
				{
					base.should_add_creature_beacons.Set(value: false);
					base.force_next_phase.Set(value: false);
					GenericShrine.spawn_controller.TrySpawningPhase(10f, send_message: true, GenericShrine.wave_phases_definitions.hordePhases[base.currentPhase.Get()], ((Component)this).gameObject, remote_spawn_locations);
					GenericShrine.phase_running = true;
					base.currentPhase.Set(base.currentPhase.Get() + 1);
					return;
				}
				Logger.LogInfo((object)"Challenge complete! Spawning reward.");
				List<Player> list = new List<Player>();
				Player.GetPlayersInRange(((Component)this).transform.position, VFConfig.ShrineAnnouncementRange.Value, list);
				foreach (Player item in list)
				{
					((Character)item).Message((MessageType)2, Localization.instance.Localize("$shrine_challenge_complete"), 0, (Sprite)null);
				}
				SpawnReward(base.selected_reward.Get(), Levels.GetChallengeLevelDefinitions().ElementAt(base.selected_level.Get()).levelIndex, shrine_spawnpoint.transform.position, base.hard_mode.Get(), base.boss_mode.Get(), base.siege_mode.Get());
				base.challenge_active.Set(value: false);
				base.boss_mode.Set(value: false);
				base.hard_mode.Set(value: false);
				base.siege_mode.Set(value: false);
				base.end_of_challenge.Set(value: true);
				Disableportal();
				GenericShrine.wave_phases_definitions = new PhasedWaveTemplate
				{
					hordePhases = new List<List<HoardConfig>>()
				};
				GenericShrine.SendUpdatedPhaseConfigs();
				base.wave_definition_ready.Set(value: false);
				base.spawn_locations_ready.Set(value: false);
			}
		}
	}
	internal class ArenaShrineUI : GenericShrineUI
	{
		private ArenaShrine Shrine;

		public override void AddCreatureFlares()
		{
			if (VFConfig.EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Adding creature flares.");
			}
			HideCancelUI();
			Shrine.NotifyRemainingCreatures();
		}

		public override void Awake()
		{
			cleanupPortals = false;
			CreateStaticUIObjects();
			createCancelUI();
			Shrine = ((Component)this).GetComponent<ArenaShrine>();
		}

		public override void CancelChallengeButtonClick()
		{
			if (VFConfig.EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Cancelling the active challenge.");
			}
			HideCancelUI();
			Shrine.CancelShrineRun();
		}

		public override void CleanupPortalsButtonClick()
		{
		}

		public override void StartChallenge()
		{
			HideUI();
			string text = availableRewards[rewardSelector.GetComponent<Dropdown>().value];
			string[] array = levelSelector.GetComponent<Dropdown>().options[levelSelector.GetComponent<Dropdown>().value].text.Split(new char[1] { '-' });
			string text2 = ValheimFortress.ReplaceWhitespace(array[0], "");
			short num = (short)(short.Parse(text2) - 1);
			if (VFConfig.EnableDebugMode.Value)
			{
				Logger.LogInfo((object)$"Looking up level definition with index of text-{text2} (1 based) int-{num} (zero based)");
			}
			List<ChallengeLevelDefinition> challengeLevelDefinitions = Levels.GetChallengeLevelDefinitions();
			bool flag = false;
			if (VFConfig.EnableHardModifier.Value)
			{
				flag = hardModeToggle.GetComponent<Toggle>().isOn;
			}
			bool flag2 = false;
			if (VFConfig.EnableBossModifier.Value)
			{
				flag2 = bossModeToggle.GetComponent<Toggle>().isOn;
			}
			bool flag3 = false;
			if (VFConfig.EnableSiegeModifer.Value)
			{
				flag3 = siegeModeToggle.GetComponent<Toggle>().isOn;
			}
			if (VFConfig.EnableDebugMode.Value)
			{
				Logger.LogInfo((object)$"Shrine challenge. Selected reward: {text}, selected level index: {num}");
			}
			UserInterfaceData.PreparePhase(challengeLevelDefinitions.ElementAt(num), flag2, ((Component)Shrine).gameObject);
			Shrine.SetLevel(num);
			Shrine.SetReward(text);
			if (flag)
			{
				Shrine.SetHardMode();
			}
			if (flag2)
			{
				Shrine.SetBossMode();
			}
			if (flag3)
			{
				Shrine.SetSiegeMode();
			}
			Shrine.SetStartChallenge();
		}

		public override void TeleportCreatures()
		{
			if (VFConfig.EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Teleporting creatures to the shrine.");
			}
			HideCancelUI();
			Shrine.TeleportRemainingCreatures();
		}

		public override void DisplayUI()
		{
			CreateChallengeUI("arena");
			ChallengePanel.SetActive(true);
			GUIManager.BlockInput(true);
			if (VFConfig.EnableDebugMode.Value)
			{
				Logger.LogInfo((object)"Enabled UI from Shrine object.");
			}
		}
	}
	internal class ChallengeShrine : GenericShrine
	{
		private static ChallengeShrineUI ui_controller;

		private new static GameObject shrine_spawnpoint;

		private static short fail_to_start;

		public override string GetHoverName()
		{
			return Localization.instance.Localize("$piece_shrine_of_challenge");
		}

		public override string GetHoverText()
		{
			string text = "[<color=yellow><b>$KEY_Use</b></color>] $piece_shrine_of_challenge";
			return Localization.instance.Localize(text);
		}

		public override bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (hold)
			{
				return false;
			}
			if (base.challenge_active.Get())
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, $"Creatures remaining {base.spawned_creatures.Get()}", 0, (Sprite)null);
				ui_controller.DisplayCancelUI();