Decompiled source of Aurora Season 2 v2.1.0

BepInEx/plugins/AuroraQuickConnect.dll

Decompiled 17 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("AuroraQuickConnect")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AuroraQuickConnect")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("b320a5f6-47c1-4fb0-a279-c04835cbb413")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace AuroraQuickConnect
{
	[BepInPlugin("com.aurora.quickconnect", "AuroraQuickConnect", "1.0.0")]
	public sealed class Class1 : BaseUnityPlugin
	{
		private static class Joiner
		{
			public static bool TryJoin(FejdStartup fs, string host, int port, string password)
			{
				string text = $"{host}:{port}";
				Ui.TryFillJoinByIp(fs, text, password);
				if (SmartInvoke.TryInvokeFirstMatch(fs, new string[8] { "OnJoinIPConnect", "OnJoinIpConnect", "JoinServerIP", "JoinServerIp", "JoinServer", "ConnectToServer", "ConnectToIP", "ConnectToIp" }, SmartInvoke.Candidates(new object[0], new object[1] { text }, new object[2] { text, password }, new object[2] { host, port }, new object[3] { host, port, password })))
				{
					return true;
				}
				if (TryJoinViaMatchmaking(text))
				{
					return true;
				}
				if (TryJoinViaZNet(host, port, text))
				{
					return true;
				}
				return false;
			}

			private static bool TryJoinViaMatchmaking(string hostAndPort)
			{
				try
				{
					Type type = AccessTools.TypeByName("ZSteamMatchmaking");
					if (type == null)
					{
						return false;
					}
					object obj = AccessTools.Property(type, "instance")?.GetValue(null) ?? AccessTools.Field(type, "instance")?.GetValue(null);
					if (obj == null)
					{
						return false;
					}
					if (SmartInvoke.TryInvokeFirstMatch(obj, new string[6] { "QueueServerJoin", "JoinServer", "JoinServerByIp", "JoinServerByIP", "JoinIP", "JoinIp" }, SmartInvoke.Candidates(new object[1] { hostAndPort })))
					{
						Log.LogInfo((object)"Aurora QuickConnect: join triggered via ZSteamMatchmaking.");
						return true;
					}
				}
				catch (Exception ex)
				{
					Log.LogDebug((object)("TryJoinViaMatchmaking failed: " + ex.GetType().Name + ": " + ex.Message));
				}
				return false;
			}

			private static bool TryJoinViaZNet(string host, int port, string hostAndPort)
			{
				try
				{
					Type type = AccessTools.TypeByName("ZNet");
					if (type == null)
					{
						return false;
					}
					object obj = AccessTools.Property(type, "instance")?.GetValue(null) ?? AccessTools.Field(type, "instance")?.GetValue(null);
					if (obj == null)
					{
						return false;
					}
					IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse(host), port);
					if (SmartInvoke.TryInvokeFirstMatch(obj, new string[6] { "Connect", "StartClient", "StartClientConnect", "ConnectToServer", "ConnectToIP", "ConnectToIp" }, SmartInvoke.Candidates(new object[2] { host, port }, new object[1] { hostAndPort }, new object[1] { iPEndPoint })))
					{
						Log.LogInfo((object)"Aurora QuickConnect: join triggered via ZNet.");
						return true;
					}
				}
				catch (Exception ex)
				{
					Log.LogDebug((object)("TryJoinViaZNet failed: " + ex.GetType().Name + ": " + ex.Message));
				}
				return false;
			}

			public static void DumpJoinMethods(FejdStartup fs)
			{
				try
				{
					DumpTypeMethods("FejdStartup", ((object)fs).GetType(), "join");
					DumpTypeMethods("FejdStartup", ((object)fs).GetType(), "connect");
					Type type = AccessTools.TypeByName("ZSteamMatchmaking");
					if (type != null)
					{
						DumpTypeMethods("ZSteamMatchmaking", type, "join");
					}
					Type type2 = AccessTools.TypeByName("ZNet");
					if (type2 != null)
					{
						DumpTypeMethods("ZNet", type2, "connect");
					}
				}
				catch (Exception ex)
				{
					Log.LogWarning((object)("DumpJoinMethods failed: " + ex.GetType().Name + ": " + ex.Message));
				}
			}

			private static void DumpTypeMethods(string label, Type t, string filter)
			{
				string filter2 = filter;
				string[] array = (from m in (from m in t.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
						where m.Name.IndexOf(filter2, StringComparison.OrdinalIgnoreCase) >= 0
						orderby m.Name
						select m).Take(60)
					select m.Name + "(" + string.Join(", ", from p in m.GetParameters()
						select p.ParameterType.Name) + ")").ToArray();
				Log.LogInfo((object)("---- " + label + " methods matching '" + filter2 + "' (up to 60) ----"));
				string[] array2 = array;
				foreach (string text in array2)
				{
					Log.LogInfo((object)text);
				}
				Log.LogInfo((object)"--------------------------------------------------------");
			}
		}

		private static class SmartInvoke
		{
			public static object[][] Candidates(params object[][] candidates)
			{
				return candidates;
			}

			public static bool TryInvokeFirstMatch(object instance, string[] methodNames, object[][] candidates)
			{
				Type type = instance.GetType();
				MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (string name in methodNames)
				{
					foreach (MethodInfo item in methods.Where((MethodInfo x) => x.Name == name))
					{
						foreach (object[] candidate in candidates)
						{
							if (!TryBuildArgs(item, candidate, out object[] args))
							{
								continue;
							}
							try
							{
								item.Invoke(instance, args);
								Log.LogInfo((object)("Invoked " + type.Name + "." + item.Name + "(" + string.Join(", ", from p in item.GetParameters()
									select p.ParameterType.Name) + ")"));
								return true;
							}
							catch (Exception ex)
							{
								Log.LogDebug((object)("Invoke failed " + type.Name + "." + item.Name + ": " + ex.GetType().Name + ": " + ex.Message));
							}
						}
					}
				}
				return false;
			}

			private static bool TryBuildArgs(MethodInfo method, object[] candidate, out object[] args)
			{
				args = Array.Empty<object>();
				ParameterInfo[] parameters = method.GetParameters();
				if (parameters.Length != candidate.Length)
				{
					return false;
				}
				object[] array = new object[parameters.Length];
				for (int i = 0; i < parameters.Length; i++)
				{
					Type parameterType = parameters[i].ParameterType;
					object obj = candidate[i];
					if (obj == null)
					{
						if (parameterType.IsValueType)
						{
							return false;
						}
						array[i] = null;
						continue;
					}
					Type type = obj.GetType();
					if (parameterType.IsAssignableFrom(type))
					{
						array[i] = obj;
						continue;
					}
					if (parameterType == typeof(ushort) && obj is int num && num >= 0 && num <= 65535)
					{
						array[i] = (ushort)num;
						continue;
					}
					if (parameterType == typeof(int) && obj is ushort num2)
					{
						array[i] = (int)num2;
						continue;
					}
					if (parameterType == typeof(string))
					{
						array[i] = obj.ToString() ?? "";
						continue;
					}
					return false;
				}
				args = array;
				return true;
			}
		}

		private static class Ui
		{
			private const string AuroraButtonName = "AuroraQuickConnect__PlayAuroraButton";

			public static void TryInjectPlayAuroraButtonAboveStart(FejdStartup fs, Action onClick)
			{
				//IL_015f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0169: Expected O, but got Unknown
				//IL_0178: Unknown result type (might be due to invalid IL or missing references)
				//IL_0182: Expected O, but got Unknown
				if ((Object)(object)fs == (Object)null || ((Component)fs).GetComponentsInChildren<Transform>(true).Any((Transform t) => ((Object)t).name == "AuroraQuickConnect__PlayAuroraButton"))
				{
					return;
				}
				Button[] componentsInChildren = ((Component)fs).GetComponentsInChildren<Button>(true);
				if (componentsInChildren == null || componentsInChildren.Length == 0)
				{
					Log.LogWarning((object)"No UI Buttons found under FejdStartup. Can't inject Play Aurora.");
					return;
				}
				Button val = ((IEnumerable<Button>)componentsInChildren).FirstOrDefault((Func<Button, bool>)((Button b) => LabelContains(((Component)b).gameObject, "Start Game"))) ?? ((IEnumerable<Button>)componentsInChildren).FirstOrDefault((Func<Button, bool>)((Button b) => LabelContains(((Component)b).gameObject, "Start"))) ?? ((IEnumerable<Button>)componentsInChildren).FirstOrDefault((Func<Button, bool>)((Button b) => HasAnyLabel(((Component)b).gameObject))) ?? componentsInChildren[0];
				Transform parent = ((Component)val).transform.parent;
				GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, parent);
				((Object)val2).name = "AuroraQuickConnect__PlayAuroraButton";
				val2.SetActive(true);
				val2.transform.SetSiblingIndex(0);
				SetButtonLabel(val2, _buttonText);
				Button component = val2.GetComponent<Button>();
				if ((Object)(object)component == (Object)null)
				{
					Object.Destroy((Object)(object)val2);
					return;
				}
				component.onClick = new ButtonClickedEvent();
				((UnityEvent)component.onClick).AddListener(new UnityAction(onClick.Invoke));
				Log.LogInfo((object)("Injected '" + _buttonText + "' button (template='" + ((Object)val).name + "')."));
			}

			public static bool TryInvokeVoidBestEffort(object instance, string methodName)
			{
				string methodName2 = methodName;
				try
				{
					Type type = instance.GetType();
					MethodInfo[] array = (from m in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
						where m.Name == methodName2 && m.ReturnType == typeof(void)
						select m).ToArray();
					if (array.Length == 0)
					{
						return false;
					}
					MethodInfo methodInfo = array.FirstOrDefault((MethodInfo m) => m.GetParameters().Length == 0);
					if (methodInfo != null)
					{
						methodInfo.Invoke(instance, Array.Empty<object>());
						return true;
					}
					MethodInfo methodInfo2 = array.FirstOrDefault((MethodInfo m) => m.GetParameters().Length == 1);
					if (methodInfo2 != null)
					{
						Type parameterType = methodInfo2.GetParameters()[0].ParameterType;
						object obj = null;
						if (parameterType == typeof(bool))
						{
							obj = false;
						}
						else if (parameterType == typeof(int))
						{
							obj = 0;
						}
						else if (parameterType == typeof(float))
						{
							obj = 0f;
						}
						else
						{
							if (!(parameterType == typeof(string)))
							{
								return false;
							}
							obj = "";
						}
						methodInfo2.Invoke(instance, new object[1] { obj });
						return true;
					}
				}
				catch
				{
				}
				return false;
			}

			public static bool ClickButtonByLabel(FejdStartup fs, string[] include, string[] exclude)
			{
				Button val = FindButtonByLabel(fs, include, exclude);
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				ButtonClickedEvent onClick = val.onClick;
				if (onClick != null)
				{
					((UnityEvent)onClick).Invoke();
				}
				return true;
			}

			private static Button? FindButtonByLabel(FejdStartup fs, string[] include, string[] exclude)
			{
				if ((Object)(object)fs == (Object)null)
				{
					return null;
				}
				Button[] componentsInChildren = ((Component)fs).GetComponentsInChildren<Button>(true);
				if (componentsInChildren == null)
				{
					return null;
				}
				Button[] array = componentsInChildren;
				foreach (Button val in array)
				{
					if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy)
					{
						continue;
					}
					string anyLabelText = GetAnyLabelText(((Component)val).gameObject);
					if (!string.IsNullOrEmpty(anyLabelText))
					{
						string lower = anyLabelText.ToLowerInvariant();
						if (!exclude.Any((string e) => lower.Contains(e.ToLowerInvariant())) && include.All((string i) => lower.Contains(i.ToLowerInvariant())))
						{
							return val;
						}
					}
				}
				return null;
			}

			public static void TryFillJoinByIp(FejdStartup fs, string hostAndPort, string password)
			{
				TrySetInputByFieldName(fs, new string[7] { "m_joinIPAddress", "m_joinIpAddress", "m_joinIP", "m_joinIp", "m_serverIP", "m_serverAddress", "m_serverHost" }, hostAndPort);
				if (!string.IsNullOrEmpty(password))
				{
					TrySetInputByFieldName(fs, new string[4] { "m_joinPassword", "m_password", "m_serverPassword", "m_joinServerPassword" }, password);
				}
			}

			private static void TrySetInputByFieldName(object instance, string[] fieldNames, string value)
			{
				foreach (string text in fieldNames)
				{
					try
					{
						FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), text);
						if (fieldInfo == null)
						{
							continue;
						}
						object value2 = fieldInfo.GetValue(instance);
						if (value2 != null)
						{
							InputField val = (InputField)((value2 is InputField) ? value2 : null);
							if (val != null)
							{
								val.text = value;
								break;
							}
							Type type = value2.GetType();
							if (type.Name == "TMP_InputField")
							{
								type.GetProperty("text", BindingFlags.Instance | BindingFlags.Public)?.SetValue(value2, value);
								break;
							}
						}
					}
					catch
					{
					}
				}
			}

			private static bool LabelContains(GameObject go, string text)
			{
				string anyLabelText = GetAnyLabelText(go);
				return anyLabelText != null && anyLabelText.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0;
			}

			private static bool HasAnyLabel(GameObject go)
			{
				return !string.IsNullOrEmpty(GetAnyLabelText(go));
			}

			private static string? GetAnyLabelText(GameObject go)
			{
				if ((Object)(object)go == (Object)null)
				{
					return null;
				}
				try
				{
					Component val = ((IEnumerable<Component>)go.GetComponentsInChildren<Component>(true)).FirstOrDefault((Func<Component, bool>)((Component c) => (Object)(object)c != (Object)null && (((object)c).GetType().Name == "TMP_Text" || ((object)c).GetType().Name == "TextMeshProUGUI")));
					if ((Object)(object)val != (Object)null)
					{
						string text = ((object)val).GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public)?.GetValue(val) as string;
						if (!string.IsNullOrEmpty(text))
						{
							return text;
						}
					}
				}
				catch
				{
				}
				Text componentInChildren = go.GetComponentInChildren<Text>(true);
				if ((Object)(object)componentInChildren != (Object)null && !string.IsNullOrEmpty(componentInChildren.text))
				{
					return componentInChildren.text;
				}
				return null;
			}

			private static void SetButtonLabel(GameObject buttonGo, string label)
			{
				if ((Object)(object)buttonGo == (Object)null)
				{
					return;
				}
				try
				{
					Component val = ((IEnumerable<Component>)buttonGo.GetComponentsInChildren<Component>(true)).FirstOrDefault((Func<Component, bool>)((Component c) => (Object)(object)c != (Object)null && (((object)c).GetType().Name == "TMP_Text" || ((object)c).GetType().Name == "TextMeshProUGUI")));
					if ((Object)(object)val != (Object)null)
					{
						((object)val).GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public)?.SetValue(val, label);
						return;
					}
				}
				catch
				{
				}
				Text componentInChildren = buttonGo.GetComponentInChildren<Text>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.text = label;
				}
			}
		}

		[CompilerGenerated]
		private sealed class <ConnectToServerRoutine>d__32 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public FejdStartup fs;

			private string <hostAndPort>5__1;

			private int <attempt>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ConnectToServerRoutine>d__32(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<hostAndPort>5__1 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: Expected O, but got Unknown
				//IL_0151: Unknown result type (might be due to invalid IL or missing references)
				//IL_015b: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if (_uiSettleDelay > 0f)
					{
						<>2__current = (object)new WaitForSecondsRealtime(_uiSettleDelay);
						<>1__state = 2;
						return true;
					}
					goto IL_007b;
				case 2:
					<>1__state = -1;
					goto IL_007b;
				case 3:
					{
						<>1__state = -1;
						<attempt>5__2++;
						break;
					}
					IL_007b:
					<hostAndPort>5__1 = $"{_host}:{_port}";
					Log.LogInfo((object)("Aurora QuickConnect: attempting direct join to " + <hostAndPort>5__1));
					<attempt>5__2 = 1;
					break;
				}
				if (<attempt>5__2 <= _joinAttempts)
				{
					if (<attempt>5__2 == 1)
					{
						Log.LogInfo((object)$"Join attempt 1/{_joinAttempts}");
					}
					else
					{
						Log.LogInfo((object)$"Join attempt {<attempt>5__2}/{_joinAttempts}");
					}
					if (Joiner.TryJoin(fs, _host, _port, _password))
					{
						Log.LogInfo((object)"Aurora QuickConnect: join triggered successfully.");
						return false;
					}
					<>2__current = (object)new WaitForSecondsRealtime(_joinAttemptInterval);
					<>1__state = 3;
					return true;
				}
				Log.LogWarning((object)"Aurora QuickConnect: Failed to start connection (no compatible join method found).");
				if (_debugDumpOnFail)
				{
					Log.LogWarning((object)"Dumping join diagnostics (Debug.DumpJoinMethodsOnFail=true) ...");
					Joiner.DumpJoinMethods(fs);
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public const string PluginGuid = "com.aurora.quickconnect";

		public const string PluginName = "AuroraQuickConnect";

		public const string PluginVersion = "1.0.0";

		private static ManualLogSource Log = null;

		private static Harmony _harmony = null;

		private static bool _pending;

		private static Coroutine? _connectRoutine;

		private static string _host = "85.206.119.102";

		private static int _port = 2456;

		private static string _password = "";

		private static string _buttonText = "Play Aurora";

		private static int _joinAttempts = 10;

		private static float _joinAttemptInterval = 0.25f;

		private static float _uiSettleDelay = 0.15f;

		private static bool _debugDumpOnFail = true;

		private ConfigEntry<string> _cfgHost = null;

		private ConfigEntry<int> _cfgPort = null;

		private ConfigEntry<string> _cfgPassword = null;

		private ConfigEntry<string> _cfgButtonText = null;

		private ConfigEntry<int> _cfgJoinAttempts = null;

		private ConfigEntry<float> _cfgJoinAttemptInterval = null;

		private ConfigEntry<float> _cfgUiSettleDelay = null;

		private ConfigEntry<bool> _cfgDebugDumpOnFail = null;

		private void Awake()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				SetupConfig();
				_harmony = new Harmony("com.aurora.quickconnect");
				PatchIfExists(typeof(FejdStartup), "Start", null, "FejdStartup_Start_Postfix");
				PatchIfExists(typeof(FejdStartup), "OnCharacterStart", "FejdStartup_OnCharacterStart_Prefix");
				PatchIfExists(typeof(FejdStartup), "OnBack", null, "FejdStartup_Back_Postfix");
				PatchIfExists(typeof(FejdStartup), "OnBackButton", null, "FejdStartup_Back_Postfix");
				PatchIfExists(typeof(FejdStartup), "OnCancel", null, "FejdStartup_Back_Postfix");
				Log.LogInfo((object)string.Format("{0} {1} loaded. Target={2}:{3} (password={4}).", "AuroraQuickConnect", "1.0.0", _host, _port, string.IsNullOrEmpty(_password) ? "none" : "set"));
			}
			catch (Exception arg)
			{
				Log.LogError((object)string.Format("{0} failed to load: {1}", "AuroraQuickConnect", arg));
			}
		}

		private void OnDestroy()
		{
			try
			{
				Harmony harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch
			{
			}
		}

		private void SetupConfig()
		{
			_cfgHost = ((BaseUnityPlugin)this).Config.Bind<string>("Server", "Host", "85.206.119.102", "Server IP / hostname for Aurora.");
			_cfgPort = ((BaseUnityPlugin)this).Config.Bind<int>("Server", "Port", 2456, "Server port for Aurora.");
			_cfgPassword = ((BaseUnityPlugin)this).Config.Bind<string>("Server", "Password", "", "Server password (leave blank if none).");
			_cfgButtonText = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "ButtonText", "Play Aurora", "Text shown on the main-menu button.");
			_cfgJoinAttempts = ((BaseUnityPlugin)this).Config.Bind<int>("Connect", "JoinAttempts", 10, "How many times to try triggering a join (safe retries, no spam).");
			_cfgJoinAttemptInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Connect", "AttemptIntervalSeconds", 0.25f, "Seconds between join attempts.");
			_cfgUiSettleDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Connect", "UiSettleDelaySeconds", 0.15f, "Small delay after clicking Start, before we trigger the join.");
			_cfgDebugDumpOnFail = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DumpJoinMethodsOnFail", true, "If join cannot be triggered, print join/connect method info to the log.");
			ApplyConfigSnapshot();
			_cfgHost.SettingChanged += delegate
			{
				ApplyConfigSnapshot();
			};
			_cfgPort.SettingChanged += delegate
			{
				ApplyConfigSnapshot();
			};
			_cfgPassword.SettingChanged += delegate
			{
				ApplyConfigSnapshot();
			};
			_cfgButtonText.SettingChanged += delegate
			{
				ApplyConfigSnapshot();
			};
			_cfgJoinAttempts.SettingChanged += delegate
			{
				ApplyConfigSnapshot();
			};
			_cfgJoinAttemptInterval.SettingChanged += delegate
			{
				ApplyConfigSnapshot();
			};
			_cfgUiSettleDelay.SettingChanged += delegate
			{
				ApplyConfigSnapshot();
			};
			_cfgDebugDumpOnFail.SettingChanged += delegate
			{
				ApplyConfigSnapshot();
			};
			try
			{
				((BaseUnityPlugin)this).Config.Save();
				Log.LogInfo((object)("Config ready: " + ((BaseUnityPlugin)this).Config.ConfigFilePath));
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not save config file: " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private void ApplyConfigSnapshot()
		{
			_host = _cfgHost.Value?.Trim() ?? "85.206.119.102";
			_port = _cfgPort.Value;
			if (_port <= 0 || _port > 65535)
			{
				_port = 2456;
			}
			_password = _cfgPassword.Value ?? "";
			_buttonText = (string.IsNullOrWhiteSpace(_cfgButtonText.Value) ? "Play Aurora" : _cfgButtonText.Value);
			_joinAttempts = _cfgJoinAttempts.Value;
			if (_joinAttempts < 1)
			{
				_joinAttempts = 1;
			}
			if (_joinAttempts > 50)
			{
				_joinAttempts = 50;
			}
			_joinAttemptInterval = _cfgJoinAttemptInterval.Value;
			if (_joinAttemptInterval < 0.05f)
			{
				_joinAttemptInterval = 0.05f;
			}
			if (_joinAttemptInterval > 5f)
			{
				_joinAttemptInterval = 5f;
			}
			_uiSettleDelay = _cfgUiSettleDelay.Value;
			if (_uiSettleDelay < 0f)
			{
				_uiSettleDelay = 0f;
			}
			if (_uiSettleDelay > 5f)
			{
				_uiSettleDelay = 5f;
			}
			_debugDumpOnFail = _cfgDebugDumpOnFail.Value;
		}

		private static void PatchIfExists(Type type, string methodName, string? prefix = null, string? postfix = null)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)("[PatchIfExists] " + type.Name + "." + methodName + " not found on this client build. Skipping."));
					}
				}
				else
				{
					HarmonyMethod val = ((prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Class1), prefix, (Type[])null));
					HarmonyMethod val2 = ((postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Class1), postfix, (Type[])null));
					_harmony.Patch((MethodBase)methodInfo, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					ManualLogSource log2 = Log;
					if (log2 != null)
					{
						log2.LogInfo((object)("Patched " + type.Name + "." + methodName));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = Log;
				if (log3 != null)
				{
					log3.LogWarning((object)("[PatchIfExists] Failed patching " + type.Name + "." + methodName + ": " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}

		private static void FejdStartup_Start_Postfix(FejdStartup __instance)
		{
			FejdStartup __instance2 = __instance;
			try
			{
				Ui.TryInjectPlayAuroraButtonAboveStart(__instance2, delegate
				{
					OnPlayAuroraClicked(__instance2);
				});
			}
			catch (Exception arg)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogError((object)$"Button injection exception: {arg}");
				}
			}
		}

		private static bool FejdStartup_OnCharacterStart_Prefix(FejdStartup __instance)
		{
			if (!_pending)
			{
				return true;
			}
			_pending = false;
			Log.LogInfo((object)$"OnCharacterStart intercepted (Play Aurora) -> joining {_host}:{_port}");
			if (_connectRoutine != null)
			{
				try
				{
					((MonoBehaviour)__instance).StopCoroutine(_connectRoutine);
				}
				catch
				{
				}
				_connectRoutine = null;
			}
			_connectRoutine = ((MonoBehaviour)__instance).StartCoroutine(ConnectToServerRoutine(__instance));
			return false;
		}

		private static void FejdStartup_Back_Postfix()
		{
			_pending = false;
		}

		private static void OnPlayAuroraClicked(FejdStartup fs)
		{
			Log.LogInfo((object)"Play Aurora clicked.");
			_pending = true;
			if (!Ui.TryInvokeVoidBestEffort(fs, "OnStartGame") && !Ui.TryInvokeVoidBestEffort(fs, "OnStart") && !Ui.ClickButtonByLabel(fs, new string[2] { "start", "game" }, Array.Empty<string>()))
			{
				Log.LogWarning((object)"Couldn't open Character Select automatically. Click Valheim's Start Game once, then click Play Aurora again.");
				_pending = false;
			}
		}

		[IteratorStateMachine(typeof(<ConnectToServerRoutine>d__32))]
		private static IEnumerator ConnectToServerRoutine(FejdStartup fs)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ConnectToServerRoutine>d__32(0)
			{
				fs = fs
			};
		}
	}
}

BepInEx/plugins/AuroraWardDecay.dll

Decompiled 17 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("AuroraWardDecay")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AuroraWardDecay")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("91245976-b7c2-4fcd-88a9-505fe801b8e8")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace AuroraWardDecay
{
	public class Class1
	{
	}
}
namespace AuroraWardDecayMod
{
	[BepInPlugin("aurora.warddecay", "AuroraWardDecay", "1.0.5")]
	public class AuroraWardDecayPlugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private sealed class <ServerSweepLoop>d__12 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public AuroraWardDecayPlugin <>4__this;

			private PrivateArea[] <wards>5__1;

			private long <nowTicks>5__2;

			private long <maxAge>5__3;

			private PrivateArea[] <>s__4;

			private int <>s__5;

			private PrivateArea <pa>5__6;

			private ZNetView <nview>5__7;

			private ZDO <zdo>5__8;

			private long <lastTouched>5__9;

			private Exception <ex>5__10;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ServerSweepLoop>d__12(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<wards>5__1 = null;
				<>s__4 = null;
				<pa>5__6 = null;
				<nview>5__7 = null;
				<zdo>5__8 = null;
				<ex>5__10 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
					{
						break;
					}
					try
					{
						<wards>5__1 = Object.FindObjectsOfType<PrivateArea>();
						if (<wards>5__1 == null || <wards>5__1.Length == 0)
						{
							break;
						}
						<nowTicks>5__2 = NowTicks();
						<maxAge>5__3 = DaysToTicks(DecayDays.Value);
						<>s__4 = <wards>5__1;
						for (<>s__5 = 0; <>s__5 < <>s__4.Length; <>s__5++)
						{
							<pa>5__6 = <>s__4[<>s__5];
							if (Object.op_Implicit((Object)(object)<pa>5__6))
							{
								<nview>5__7 = ((Component)<pa>5__6).GetComponent<ZNetView>();
								if (Object.op_Implicit((Object)(object)<nview>5__7) && <nview>5__7.IsValid())
								{
									<zdo>5__8 = <nview>5__7.GetZDO();
									if (<zdo>5__8 != null)
									{
										<lastTouched>5__9 = <zdo>5__8.GetLong("aurora_lastTouched_ticks", 0L);
										if (<lastTouched>5__9 <= 0)
										{
											<zdo>5__8.Set("aurora_lastTouched_ticks", <nowTicks>5__2);
										}
										else
										{
											if (<nowTicks>5__2 - <lastTouched>5__9 >= <maxAge>5__3)
											{
												Object.Destroy((Object)(object)((Component)<pa>5__6).gameObject);
											}
											<nview>5__7 = null;
											<zdo>5__8 = null;
											<pa>5__6 = null;
										}
									}
								}
							}
						}
						<>s__4 = null;
						<wards>5__1 = null;
					}
					catch (Exception ex)
					{
						<ex>5__10 = ex;
						((BaseUnityPlugin)<>4__this).Logger.LogError((object)$"Ward decay sweep failed: {<ex>5__10}");
					}
					break;
				}
				<>2__current = (object)new WaitForSeconds(CheckIntervalSeconds.Value);
				<>1__state = 1;
				return true;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public const string PluginGuid = "aurora.warddecay";

		public const string PluginName = "AuroraWardDecay";

		public const string PluginVersion = "1.0.5";

		internal const string ZdoKeyLastTouchedTicks = "aurora_lastTouched_ticks";

		internal static ConfigEntry<float> CheckIntervalSeconds;

		internal static ConfigEntry<double> DecayDays;

		internal static ConfigEntry<bool> RefreshOnInteractOnly;

		internal static ConfigEntry<bool> EnableHoverText;

		internal static ConfigEntry<string> HoverFormat;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected O, but got Unknown
			CheckIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "CheckIntervalSeconds", 30f, "How often the server checks for expired wards.");
			DecayDays = ((BaseUnityPlugin)this).Config.Bind<double>("General", "DecayDays", 7.0, "Days without interaction before a ward expires.");
			RefreshOnInteractOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RefreshOnInteractOnly", true, "If true, only Interact() refreshes the timer (placement always seeds).");
			EnableHoverText = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableHoverText", true, "Show remaining time on ward hover.");
			HoverFormat = ((BaseUnityPlugin)this).Config.Bind<string>("General", "HoverFormat", "<color=yellow><b>Upkeep:</b></color> {0}", "Format for remaining time; {0}=time left.");
			_harmony = new Harmony("aurora.warddecay");
			_harmony.PatchAll();
			((MonoBehaviour)this).StartCoroutine(ServerSweepLoop());
			((BaseUnityPlugin)this).Logger.LogInfo((object)"AuroraWardDecay 1.0.5 loaded");
		}

		private void OnDestroy()
		{
			try
			{
				Harmony harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch
			{
			}
		}

		[IteratorStateMachine(typeof(<ServerSweepLoop>d__12))]
		private IEnumerator ServerSweepLoop()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ServerSweepLoop>d__12(0)
			{
				<>4__this = this
			};
		}

		internal static long NowTicks()
		{
			return (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTime() : DateTime.UtcNow).ToUniversalTime().Ticks;
		}

		internal static long DaysToTicks(double days)
		{
			return TimeSpan.FromDays(days).Ticks;
		}

		internal static string FormatRemaining(long nowTicks, long lastTouchedTicks, double days)
		{
			long num = DaysToTicks(days);
			long num2 = ((lastTouchedTicks > 0) ? Math.Max(0L, num - (nowTicks - lastTouchedTicks)) : num);
			if (num2 <= 0)
			{
				return "expired";
			}
			TimeSpan timeSpan = TimeSpan.FromTicks(num2);
			if (timeSpan.TotalDays >= 1.0)
			{
				return $"{(int)timeSpan.TotalDays}d {timeSpan.Hours}h";
			}
			if (timeSpan.TotalHours >= 1.0)
			{
				return $"{(int)timeSpan.TotalHours}h {timeSpan.Minutes}m";
			}
			return $"{timeSpan.Minutes}m {timeSpan.Seconds}s";
		}
	}
	internal static class SeedHelper
	{
		public static void Seed(PrivateArea pa)
		{
			if (!Object.op_Implicit((Object)(object)pa))
			{
				return;
			}
			ZNetView component = ((Component)pa).GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)component) && component.IsValid())
			{
				ZDO zDO = component.GetZDO();
				if (zDO != null && zDO.GetLong("aurora_lastTouched_ticks", 0L) == 0)
				{
					zDO.Set("aurora_lastTouched_ticks", AuroraWardDecayPlugin.NowTicks());
				}
			}
		}
	}
	[HarmonyPatch(typeof(PrivateArea), "Awake")]
	public static class Patch_PrivateArea_Awake_Seed
	{
		private static void Postfix(PrivateArea __instance)
		{
			SeedHelper.Seed(__instance);
		}
	}
	[HarmonyPatch(typeof(PrivateArea), "Interact")]
	public static class Patch_PrivateArea_Interact
	{
		private static void Postfix(PrivateArea __instance, bool __result, Humanoid human, bool hold, bool alt)
		{
			if (!__result || !AuroraWardDecayPlugin.RefreshOnInteractOnly.Value)
			{
				return;
			}
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)component) && component.IsValid())
			{
				ZDO zDO = component.GetZDO();
				if (zDO != null)
				{
					zDO.Set("aurora_lastTouched_ticks", AuroraWardDecayPlugin.NowTicks());
				}
			}
		}
	}
	[HarmonyPatch(typeof(PrivateArea), "GetHoverText")]
	public static class Patch_PrivateArea_GetHoverText
	{
		private static void Postfix(PrivateArea __instance, ref string __result)
		{
			if (!AuroraWardDecayPlugin.EnableHoverText.Value)
			{
				return;
			}
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)component) || !component.IsValid())
			{
				return;
			}
			ZDO zDO = component.GetZDO();
			if (zDO != null)
			{
				long @long = zDO.GetLong("aurora_lastTouched_ticks", 0L);
				long nowTicks = AuroraWardDecayPlugin.NowTicks();
				string arg = AuroraWardDecayPlugin.FormatRemaining(nowTicks, @long, AuroraWardDecayPlugin.DecayDays.Value);
				StringBuilder stringBuilder = new StringBuilder(__result ?? string.Empty);
				if (!stringBuilder.ToString().EndsWith("\n"))
				{
					stringBuilder.Append('\n');
				}
				stringBuilder.AppendFormat(AuroraWardDecayPlugin.HoverFormat.Value, arg);
				__result = stringBuilder.ToString();
			}
		}
	}
}

BepInEx/plugins/VikingMessages.dll

Decompiled 17 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("VikingMessages")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyDescription("Elden Ring-inspired message system for Valheim")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Viking Messages")]
[assembly: AssemblyTitle("Viking Messages")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace VikingMessages
{
	public class GhostPhantom : MonoBehaviour
	{
		private Animator _animator;

		private float _displayDuration;

		private float _timer;

		private bool _isActive;

		private static readonly Color GhostColor = new Color(0.6f, 0.8f, 1f, 0.4f);

		private Material _ghostMaterial;

		private void Awake()
		{
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			Shader val = Shader.Find("Standard");
			if ((Object)(object)val == (Object)null)
			{
				val = Shader.Find("Legacy Shaders/Transparent/Diffuse");
			}
			if ((Object)(object)val == (Object)null)
			{
				val = Shader.Find("Sprites/Default");
			}
			if ((Object)(object)val == (Object)null)
			{
				ManualLogSource log = VikingMessagesPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"Could not find any suitable shader for ghost phantom");
				}
				return;
			}
			_ghostMaterial = new Material(val);
			try
			{
				_ghostMaterial.SetFloat("_Mode", 3f);
				_ghostMaterial.SetInt("_SrcBlend", 5);
				_ghostMaterial.SetInt("_DstBlend", 10);
				_ghostMaterial.SetInt("_ZWrite", 0);
				_ghostMaterial.DisableKeyword("_ALPHATEST_ON");
				_ghostMaterial.EnableKeyword("_ALPHABLEND_ON");
				_ghostMaterial.DisableKeyword("_ALPHAPREMULTIPLY_ON");
				_ghostMaterial.renderQueue = 3000;
				_ghostMaterial.color = GhostColor;
				_ghostMaterial.EnableKeyword("_EMISSION");
				_ghostMaterial.SetColor("_EmissionColor", new Color(0.3f, 0.5f, 0.7f));
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = VikingMessagesPlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("Could not configure ghost material: " + ex.Message));
				}
				_ghostMaterial.color = GhostColor;
			}
		}

		private void Update()
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			if (!_isActive)
			{
				return;
			}
			_timer -= Time.deltaTime;
			float num = 1f;
			if (_timer < num)
			{
				float num2 = _timer / num;
				if ((Object)(object)_ghostMaterial != (Object)null)
				{
					Color color = _ghostMaterial.color;
					color.a = GhostColor.a * num2;
					_ghostMaterial.color = color;
				}
			}
			if (_timer <= 0f)
			{
				Hide();
			}
		}

		public void Show(Vector3 position, Quaternion rotation, int emoteIndex, float duration)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			((Component)this).transform.position = position + Vector3.up * 0.1f;
			((Component)this).transform.rotation = rotation;
			_displayDuration = duration;
			_timer = duration;
			_isActive = true;
			((Component)this).gameObject.SetActive(true);
			if ((Object)(object)_animator != (Object)null)
			{
				string emoteName = MessageTemplates.GetEmoteName(emoteIndex);
				_animator.SetTrigger("emote_" + emoteName);
			}
			if ((Object)(object)_ghostMaterial != (Object)null)
			{
				_ghostMaterial.color = GhostColor;
			}
		}

		public void Hide()
		{
			_isActive = false;
			((Component)this).gameObject.SetActive(false);
		}

		public void SetupVisuals(GameObject visualSource)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			SkinnedMeshRenderer[] componentsInChildren = visualSource.GetComponentsInChildren<SkinnedMeshRenderer>();
			SkinnedMeshRenderer[] array = componentsInChildren;
			foreach (SkinnedMeshRenderer val in array)
			{
				GameObject val2 = new GameObject(((Object)val).name);
				val2.transform.SetParent(((Component)this).transform);
				val2.transform.localPosition = ((Component)val).transform.localPosition;
				val2.transform.localRotation = ((Component)val).transform.localRotation;
				val2.transform.localScale = ((Component)val).transform.localScale;
				SkinnedMeshRenderer val3 = val2.AddComponent<SkinnedMeshRenderer>();
				val3.sharedMesh = val.sharedMesh;
				val3.bones = val.bones;
				val3.rootBone = val.rootBone;
				Material[] array2 = (Material[])(object)new Material[((Renderer)val).materials.Length];
				for (int j = 0; j < array2.Length; j++)
				{
					array2[j] = _ghostMaterial;
				}
				((Renderer)val3).materials = array2;
			}
			_animator = visualSource.GetComponent<Animator>();
			if ((Object)(object)_animator != (Object)null)
			{
				Animator val4 = ((Component)this).gameObject.AddComponent<Animator>();
				val4.runtimeAnimatorController = _animator.runtimeAnimatorController;
				val4.avatar = _animator.avatar;
				_animator = val4;
			}
		}
	}
	public static class GhostPhantomManager
	{
		private static GameObject _ghostInstance;

		private static GhostPhantom _ghostComponent;

		public static void ShowGhost(Vector3 position, Quaternion rotation, int emoteIndex)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_ghostInstance == (Object)null)
			{
				CreateGhost();
			}
			if ((Object)(object)_ghostComponent != (Object)null)
			{
				float value = VikingMessagesPlugin.GhostDisplayDuration.Value;
				_ghostComponent.Show(position, rotation, emoteIndex, value);
				PlayGhostEmote(emoteIndex);
			}
		}

		public static void HideGhost()
		{
			if ((Object)(object)_ghostComponent != (Object)null)
			{
				_ghostComponent.Hide();
			}
		}

		private static void CreateGhost()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			_ghostInstance = new GameObject("VikingGhostPhantom");
			_ghostComponent = _ghostInstance.AddComponent<GhostPhantom>();
			try
			{
				Transform val = ((Component)Player.m_localPlayer).transform.Find("Visual");
				if ((Object)(object)val != (Object)null)
				{
					GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, _ghostInstance.transform);
					((Object)val2).name = "GhostVisual";
					ApplyGhostMaterial(val2);
					Animator component = ((Component)val).GetComponent<Animator>();
					if ((Object)(object)component != (Object)null)
					{
						Animator val3 = _ghostInstance.AddComponent<Animator>();
						val3.runtimeAnimatorController = component.runtimeAnimatorController;
						val3.avatar = component.avatar;
					}
				}
				else
				{
					CreateSimpleGhostVisual(_ghostInstance);
				}
			}
			catch (Exception arg)
			{
				VikingMessagesPlugin.Log.LogError((object)$"Failed to create ghost visual: {arg}");
				CreateSimpleGhostVisual(_ghostInstance);
			}
			_ghostInstance.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)_ghostInstance);
		}

		private static void ApplyGhostMaterial(GameObject obj)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			Material val = new Material(Shader.Find("Standard"));
			val.SetFloat("_Mode", 3f);
			val.SetInt("_SrcBlend", 5);
			val.SetInt("_DstBlend", 10);
			val.SetInt("_ZWrite", 0);
			val.EnableKeyword("_ALPHABLEND_ON");
			val.renderQueue = 3000;
			val.color = new Color(0.6f, 0.8f, 1f, 0.4f);
			val.EnableKeyword("_EMISSION");
			val.SetColor("_EmissionColor", new Color(0.3f, 0.5f, 0.7f));
			Renderer[] componentsInChildren = obj.GetComponentsInChildren<Renderer>();
			foreach (Renderer val2 in componentsInChildren)
			{
				Material[] array = (Material[])(object)new Material[val2.materials.Length];
				for (int j = 0; j < array.Length; j++)
				{
					array[j] = val;
				}
				val2.materials = array;
			}
			Collider[] componentsInChildren2 = obj.GetComponentsInChildren<Collider>();
			foreach (Collider val3 in componentsInChildren2)
			{
				val3.enabled = false;
			}
		}

		private static void CreateSimpleGhostVisual(GameObject parent)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.CreatePrimitive((PrimitiveType)1);
			val.transform.SetParent(parent.transform);
			val.transform.localPosition = new Vector3(0f, 1f, 0f);
			val.transform.localScale = new Vector3(0.5f, 0.8f, 0.3f);
			Object.Destroy((Object)(object)val.GetComponent<Collider>());
			ApplyGhostMaterial(val);
			GameObject val2 = GameObject.CreatePrimitive((PrimitiveType)0);
			val2.transform.SetParent(parent.transform);
			val2.transform.localPosition = new Vector3(0f, 1.8f, 0f);
			val2.transform.localScale = new Vector3(0.3f, 0.3f, 0.3f);
			Object.Destroy((Object)(object)val2.GetComponent<Collider>());
			ApplyGhostMaterial(val2);
		}

		private static void PlayGhostEmote(int emoteIndex)
		{
			if (!((Object)(object)_ghostInstance == (Object)null))
			{
				Animator component = _ghostInstance.GetComponent<Animator>();
				if ((Object)(object)component != (Object)null)
				{
					string emoteName = MessageTemplates.GetEmoteName(emoteIndex);
					component.SetTrigger("emote_" + emoteName);
					component.SetTrigger(emoteName);
					component.SetBool("emote_" + emoteName, true);
				}
			}
		}

		public static void Cleanup()
		{
			if ((Object)(object)_ghostInstance != (Object)null)
			{
				Object.Destroy((Object)(object)_ghostInstance);
				_ghostInstance = null;
				_ghostComponent = null;
			}
		}
	}
	public class MessageGlyphItem : MonoBehaviour, Hoverable
	{
		private ItemDrop _itemDrop;

		private void Awake()
		{
			_itemDrop = ((Component)this).GetComponent<ItemDrop>();
		}

		public string GetHoverText()
		{
			return "Message Glyph\n[<color=yellow><b>E</b></color>] Place Message";
		}

		public string GetHoverName()
		{
			return "Message Glyph";
		}
	}
	public class MessagePlacementHandler : MonoBehaviour
	{
		private static MessagePlacementHandler _instance;

		private bool _isPlacing;

		private float _placementTimer;

		private const float PlacementDuration = 2f;

		private Vector3 _placementPosition;

		private Quaternion _placementRotation;

		public static MessagePlacementHandler Instance
		{
			get
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Expected O, but got Unknown
				if ((Object)(object)_instance == (Object)null)
				{
					GameObject val = new GameObject("MessagePlacementHandler");
					_instance = val.AddComponent<MessagePlacementHandler>();
					Object.DontDestroyOnLoad((Object)(object)val);
				}
				return _instance;
			}
		}

		public bool IsPlacing => _isPlacing;

		private void Update()
		{
			if (_isPlacing)
			{
				_placementTimer -= Time.deltaTime;
				if (_placementTimer <= 0f)
				{
					FinishPlacement();
				}
				if ((Object)(object)Player.m_localPlayer != (Object)null && !((Character)Player.m_localPlayer).IsEncumbered() && !((Character)Player.m_localPlayer).InAttack() && !(((Character)Player.m_localPlayer).GetHealth() < ((Character)Player.m_localPlayer).GetMaxHealth() * 0.9f))
				{
				}
			}
		}

		public void StartPlacement(Player player)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			if (!_isPlacing)
			{
				_isPlacing = true;
				_placementTimer = 2f;
				_placementPosition = ((Component)player).transform.position + ((Component)player).transform.forward * 1.5f;
				_placementRotation = Quaternion.Euler(0f, ((Component)player).transform.eulerAngles.y, 0f);
				RaycastHit val = default(RaycastHit);
				if (Physics.Raycast(_placementPosition + Vector3.up * 5f, Vector3.down, ref val, 10f, LayerMask.GetMask(new string[3] { "Default", "static_solid", "terrain" })))
				{
					_placementPosition = ((RaycastHit)(ref val)).point;
				}
				player.StartEmote("kneel", true);
				((Character)player).Message((MessageType)2, "Placing message...", 0, (Sprite)null);
				VikingMessagesPlugin.Log.LogInfo((object)"Started message placement");
			}
		}

		private void FinishPlacement()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			_isPlacing = false;
			MessageUIManager.UI.ShowCreateUI(_placementPosition, _placementRotation);
			VikingMessagesPlugin.Log.LogInfo((object)"Finished placement, opening UI");
		}

		public void CancelPlacement()
		{
			if (_isPlacing)
			{
				_isPlacing = false;
				if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					((Character)Player.m_localPlayer).Message((MessageType)1, "Placement cancelled", 0, (Sprite)null);
				}
			}
		}
	}
	[HarmonyPatch]
	public static class MessageGlyphPatches
	{
		[HarmonyPatch(typeof(Player), "ConsumeItem")]
		[HarmonyPrefix]
		public static bool ConsumeItem_Prefix(Player __instance, ItemData item, ref bool __result)
		{
			object obj;
			if (item == null)
			{
				obj = null;
			}
			else
			{
				GameObject dropPrefab = item.m_dropPrefab;
				obj = ((dropPrefab != null) ? ((Object)dropPrefab).name : null);
			}
			if ((string?)obj != "MessageGlyph")
			{
				return true;
			}
			if (!CanPlaceMessage(__instance))
			{
				((Character)__instance).Message((MessageType)2, "Cannot place message here!", 0, (Sprite)null);
				__result = false;
				return false;
			}
			MessagePlacementHandler.Instance.StartPlacement(__instance);
			((Humanoid)__instance).GetInventory().RemoveItem(item, 1);
			__result = true;
			return false;
		}

		[HarmonyPatch(typeof(Humanoid), "UseItem")]
		[HarmonyPrefix]
		public static bool UseItem_Prefix(Humanoid __instance, ItemData item)
		{
			object obj;
			if (item == null)
			{
				obj = null;
			}
			else
			{
				GameObject dropPrefab = item.m_dropPrefab;
				obj = ((dropPrefab != null) ? ((Object)dropPrefab).name : null);
			}
			if ((string?)obj != "MessageGlyph")
			{
				return true;
			}
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null)
			{
				((Humanoid)val).ConsumeItem(((Humanoid)val).GetInventory(), item, false);
				return false;
			}
			return true;
		}

		private static bool CanPlaceMessage(Player player)
		{
			if (((Character)player).InInterior())
			{
				return false;
			}
			if (((Character)player).IsSwimming())
			{
				return false;
			}
			if (((Character)player).IsAttached())
			{
				return false;
			}
			if (((Character)player).IsDead())
			{
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(Character), "Damage")]
		[HarmonyPostfix]
		public static void Character_Damage_Postfix(Character __instance, HitData hit)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && MessagePlacementHandler.Instance.IsPlacing)
			{
				MessagePlacementHandler.Instance.CancelPlacement();
			}
		}
	}
	[Serializable]
	public class VikingMessage
	{
		public string Id;

		public Vector3 Position;

		public Quaternion Rotation;

		public string Template;

		public string Words;

		public int EmoteIndex;

		public long AuthorId;

		public int Reputation;

		public DateTime CreatedTime;

		public List<long> VotedPlayers = new List<long>();

		public string GetFormattedMessage()
		{
			return MessageTemplates.FormatMessage(Template, Words);
		}
	}
	public static class MessageManagerAlt
	{
		private static Dictionary<string, VikingMessage> _messages = new Dictionary<string, VikingMessage>();

		private static string _saveFilePath;

		private static bool _rpcRegistered = false;

		public const string RPC_PlaceMessage = "VikingMessages_PlaceMessage";

		public const string RPC_VoteMessage = "VikingMessages_VoteMessage";

		public const string RPC_RequestMessages = "VikingMessages_RequestMessages";

		public const string RPC_SyncMessages = "VikingMessages_SyncMessages";

		public const string RPC_RemoveMessage = "VikingMessages_RemoveMessage";

		public static void Initialize()
		{
			_saveFilePath = Path.Combine(Paths.ConfigPath, "VikingMessages_Data.json");
		}

		public static void RegisterRPCs()
		{
			if (_rpcRegistered || ZRoutedRpc.instance == null)
			{
				return;
			}
			try
			{
				ZRoutedRpc.instance.Register<ZPackage>("VikingMessages_PlaceMessage", (Action<long, ZPackage>)RPC_OnPlaceMessage);
				ZRoutedRpc.instance.Register<ZPackage>("VikingMessages_VoteMessage", (Action<long, ZPackage>)RPC_OnVoteMessage);
				ZRoutedRpc.instance.Register("VikingMessages_RequestMessages", (Action<long>)RPC_OnRequestMessages);
				ZRoutedRpc.instance.Register<ZPackage>("VikingMessages_SyncMessages", (Action<long, ZPackage>)RPC_OnSyncMessages);
				ZRoutedRpc.instance.Register<string>("VikingMessages_RemoveMessage", (Action<long, string>)RPC_OnRemoveMessage);
				_rpcRegistered = true;
				VikingMessagesPlugin.Log.LogInfo((object)"RPCs registered successfully");
			}
			catch (Exception arg)
			{
				VikingMessagesPlugin.Log.LogError((object)$"Failed to register RPCs: {arg}");
			}
		}

		private static void RPC_OnPlaceMessage(long sender, ZPackage pkg)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if (!ZNet.instance.IsServer())
			{
				return;
			}
			try
			{
				string text = pkg.ReadString();
				Vector3 position = pkg.ReadVector3();
				Quaternion rotation = pkg.ReadQuaternion();
				string template = pkg.ReadString();
				string words = pkg.ReadString();
				int emoteIndex = pkg.ReadInt();
				VikingMessage value = new VikingMessage
				{
					Id = text,
					Position = position,
					Rotation = rotation,
					Template = template,
					Words = words,
					EmoteIndex = emoteIndex,
					AuthorId = sender,
					Reputation = 0,
					CreatedTime = DateTime.UtcNow,
					VotedPlayers = new List<long>()
				};
				_messages[text] = value;
				SaveMessages();
				BroadcastMessageSync();
				VikingMessagesPlugin.Log.LogInfo((object)("Message placed: " + text));
			}
			catch (Exception arg)
			{
				VikingMessagesPlugin.Log.LogError((object)$"Error processing PlaceMessage: {arg}");
			}
		}

		private static void RPC_OnVoteMessage(long sender, ZPackage pkg)
		{
			if (!ZNet.instance.IsServer())
			{
				return;
			}
			try
			{
				string text = pkg.ReadString();
				bool flag = pkg.ReadBool();
				if (!_messages.TryGetValue(text, out var value))
				{
					return;
				}
				if (value.VotedPlayers.Contains(sender))
				{
					VikingMessagesPlugin.Log.LogInfo((object)$"Player {sender} already voted on message {text}");
					return;
				}
				value.VotedPlayers.Add(sender);
				value.Reputation += (flag ? 1 : (-1));
				VikingMessagesPlugin.Log.LogInfo((object)$"Message {text} reputation: {value.Reputation}");
				if (value.Reputation <= VikingMessagesPlugin.MinReputation.Value)
				{
					RemoveMessage(text);
					return;
				}
				SaveMessages();
				BroadcastMessageSync();
			}
			catch (Exception arg)
			{
				VikingMessagesPlugin.Log.LogError((object)$"Error processing VoteMessage: {arg}");
			}
		}

		private static void RPC_OnRequestMessages(long sender)
		{
			if (ZNet.instance.IsServer())
			{
				VikingMessagesPlugin.Log.LogInfo((object)$"Message sync requested by {sender}");
				SendMessagesToClient(sender);
			}
		}

		private static void RPC_OnSyncMessages(long sender, ZPackage pkg)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				int num = pkg.ReadInt();
				_messages.Clear();
				for (int i = 0; i < num; i++)
				{
					VikingMessage vikingMessage = new VikingMessage
					{
						Id = pkg.ReadString(),
						Position = pkg.ReadVector3(),
						Rotation = pkg.ReadQuaternion(),
						Template = pkg.ReadString(),
						Words = pkg.ReadString(),
						EmoteIndex = pkg.ReadInt(),
						AuthorId = pkg.ReadLong(),
						Reputation = pkg.ReadInt(),
						VotedPlayers = new List<long>()
					};
					int num2 = pkg.ReadInt();
					for (int j = 0; j < num2; j++)
					{
						vikingMessage.VotedPlayers.Add(pkg.ReadLong());
					}
					_messages[vikingMessage.Id] = vikingMessage;
				}
				RefreshAllMessageStones();
				VikingMessagesPlugin.Log.LogInfo((object)$"Synced {num} messages from server");
			}
			catch (Exception arg)
			{
				VikingMessagesPlugin.Log.LogError((object)$"Error processing SyncMessages: {arg}");
			}
		}

		private static void RPC_OnRemoveMessage(long sender, string messageId)
		{
			if (_messages.ContainsKey(messageId))
			{
				_messages.Remove(messageId);
			}
			MessageStone[] array = Object.FindObjectsOfType<MessageStone>();
			MessageStone[] array2 = array;
			foreach (MessageStone messageStone in array2)
			{
				if (messageStone.MessageId == messageId)
				{
					ZNetScene.instance.Destroy(((Component)messageStone).gameObject);
					break;
				}
			}
		}

		public static void PlaceMessage(Vector3 position, Quaternion rotation, string template, string words, int emoteIndex)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			string text = Guid.NewGuid().ToString();
			ZPackage val = new ZPackage();
			val.Write(text);
			val.Write(position);
			val.Write(rotation);
			val.Write(template);
			val.Write(words);
			val.Write(emoteIndex);
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "VikingMessages_PlaceMessage", new object[1] { val });
			SpawnMessageStone(text, position, rotation, template, words, emoteIndex, 0);
		}

		public static void VoteMessage(string messageId, bool isLike)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(messageId);
			val.Write(isLike);
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "VikingMessages_VoteMessage", new object[1] { val });
		}

		public static void RequestMessages()
		{
			if ((Object)(object)ZNet.instance != (Object)null && ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "VikingMessages_RequestMessages", Array.Empty<object>());
			}
		}

		public static VikingMessage GetMessage(string messageId)
		{
			VikingMessage value;
			return _messages.TryGetValue(messageId, out value) ? value : null;
		}

		public static IEnumerable<VikingMessage> GetAllMessages()
		{
			return _messages.Values;
		}

		private static void RemoveMessage(string messageId)
		{
			if (!_messages.ContainsKey(messageId))
			{
				return;
			}
			_messages.Remove(messageId);
			SaveMessages();
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(peer.m_uid, "VikingMessages_RemoveMessage", new object[1] { messageId });
			}
			RPC_OnRemoveMessage(0L, messageId);
		}

		private static void SendMessagesToClient(long targetId)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			ZPackage val = new ZPackage();
			val.Write(_messages.Count);
			foreach (VikingMessage value in _messages.Values)
			{
				val.Write(value.Id);
				val.Write(value.Position);
				val.Write(value.Rotation);
				val.Write(value.Template);
				val.Write(value.Words);
				val.Write(value.EmoteIndex);
				val.Write(value.AuthorId);
				val.Write(value.Reputation);
				val.Write(value.VotedPlayers.Count);
				foreach (long votedPlayer in value.VotedPlayers)
				{
					val.Write(votedPlayer);
				}
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(targetId, "VikingMessages_SyncMessages", new object[1] { val });
		}

		private static void BroadcastMessageSync()
		{
			if (!ZNet.instance.IsServer())
			{
				return;
			}
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				SendMessagesToClient(peer.m_uid);
			}
		}

		private static void SpawnMessageStone(string messageId, Vector3 position, Quaternion rotation, string template, string words, int emoteIndex, int reputation)
		{
			//IL_0028: 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)
			if ((Object)(object)VikingMessagesPlugin.MessageStonePrefab == (Object)null)
			{
				VikingMessagesPlugin.Log.LogError((object)"MessageStonePrefab is null!");
				return;
			}
			GameObject val = Object.Instantiate<GameObject>(VikingMessagesPlugin.MessageStonePrefab, position, rotation);
			MessageStone component = val.GetComponent<MessageStone>();
			if ((Object)(object)component != (Object)null)
			{
				component.Initialize(messageId, template, words, emoteIndex, reputation);
			}
		}

		private static void RefreshAllMessageStones()
		{
			//IL_0051: 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)
			MessageStone[] array = Object.FindObjectsOfType<MessageStone>();
			MessageStone[] array2 = array;
			foreach (MessageStone messageStone in array2)
			{
				Object.Destroy((Object)(object)((Component)messageStone).gameObject);
			}
			foreach (VikingMessage value in _messages.Values)
			{
				SpawnMessageStone(value.Id, value.Position, value.Rotation, value.Template, value.Words, value.EmoteIndex, value.Reputation);
			}
		}

		public static void SaveMessages()
		{
			if (!ZNet.instance.IsServer())
			{
				return;
			}
			try
			{
				List<SerializedMessage> list = new List<SerializedMessage>();
				foreach (VikingMessage value in _messages.Values)
				{
					list.Add(new SerializedMessage
					{
						Id = value.Id,
						PosX = value.Position.x,
						PosY = value.Position.y,
						PosZ = value.Position.z,
						RotX = value.Rotation.x,
						RotY = value.Rotation.y,
						RotZ = value.Rotation.z,
						RotW = value.Rotation.w,
						Template = value.Template,
						Words = value.Words,
						EmoteIndex = value.EmoteIndex,
						AuthorId = value.AuthorId,
						Reputation = value.Reputation,
						VotedPlayers = value.VotedPlayers.ToArray()
					});
				}
				SerializedMessageContainer serializedMessageContainer = new SerializedMessageContainer
				{
					Messages = list.ToArray()
				};
				string contents = JsonUtility.ToJson((object)serializedMessageContainer, true);
				File.WriteAllText(_saveFilePath, contents);
				VikingMessagesPlugin.Log.LogInfo((object)$"Saved {_messages.Count} messages");
			}
			catch (Exception arg)
			{
				VikingMessagesPlugin.Log.LogError((object)$"Failed to save messages: {arg}");
			}
		}

		public static void LoadMessages()
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			if (!ZNet.instance.IsServer())
			{
				return;
			}
			try
			{
				if (!File.Exists(_saveFilePath))
				{
					return;
				}
				string text = File.ReadAllText(_saveFilePath);
				SerializedMessageContainer serializedMessageContainer = JsonUtility.FromJson<SerializedMessageContainer>(text);
				_messages.Clear();
				if (serializedMessageContainer?.Messages != null)
				{
					SerializedMessage[] messages = serializedMessageContainer.Messages;
					foreach (SerializedMessage serializedMessage in messages)
					{
						VikingMessage vikingMessage = new VikingMessage
						{
							Id = serializedMessage.Id,
							Position = new Vector3(serializedMessage.PosX, serializedMessage.PosY, serializedMessage.PosZ),
							Rotation = new Quaternion(serializedMessage.RotX, serializedMessage.RotY, serializedMessage.RotZ, serializedMessage.RotW),
							Template = serializedMessage.Template,
							Words = serializedMessage.Words,
							EmoteIndex = serializedMessage.EmoteIndex,
							AuthorId = serializedMessage.AuthorId,
							Reputation = serializedMessage.Reputation,
							VotedPlayers = (serializedMessage.VotedPlayers?.ToList() ?? new List<long>())
						};
						_messages[vikingMessage.Id] = vikingMessage;
					}
				}
				VikingMessagesPlugin.Log.LogInfo((object)$"Loaded {_messages.Count} messages");
			}
			catch (Exception arg)
			{
				VikingMessagesPlugin.Log.LogError((object)$"Failed to load messages: {arg}");
			}
		}
	}
	[Serializable]
	public class SerializedMessage
	{
		public string Id;

		public float PosX;

		public float PosY;

		public float PosZ;

		public float RotX;

		public float RotY;

		public float RotZ;

		public float RotW;

		public string Template;

		public string Words;

		public int EmoteIndex;

		public long AuthorId;

		public int Reputation;

		public long[] VotedPlayers;
	}
	[Serializable]
	public class SerializedMessageContainer
	{
		public SerializedMessage[] Messages;
	}
	[HarmonyPatch]
	public static class NetworkingPatches
	{
		[CompilerGenerated]
		private sealed class <RequestMessagesDelayed>d__5 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RequestMessagesDelayed>d__5(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(3f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					MessageManagerAlt.RequestMessages();
					VikingMessagesPlugin.Log.LogInfo((object)"Requested message sync from server");
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[HarmonyPatch(typeof(ZRoutedRpc), "AddPeer")]
		[HarmonyPostfix]
		public static void ZRoutedRpc_AddPeer_Postfix(ZRoutedRpc __instance)
		{
			MessageManagerAlt.RegisterRPCs();
		}

		[HarmonyPatch(typeof(ZNet), "Awake")]
		[HarmonyPostfix]
		public static void ZNet_Awake_Postfix(ZNet __instance)
		{
		}

		[HarmonyPatch(typeof(ZNet), "Save")]
		[HarmonyPostfix]
		public static void ZNet_Save_Postfix(ZNet __instance)
		{
			if (__instance.IsServer())
			{
				MessageManagerAlt.SaveMessages();
			}
		}

		[HarmonyPatch(typeof(ZoneSystem), "Start")]
		[HarmonyPostfix]
		public static void ZoneSystem_Start_Postfix()
		{
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				MessageManagerAlt.LoadMessages();
			}
		}

		[HarmonyPatch(typeof(Player), "OnSpawned")]
		[HarmonyPostfix]
		public static void Player_OnSpawned_Postfix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				((MonoBehaviour)__instance).StartCoroutine(RequestMessagesDelayed());
			}
		}

		[IteratorStateMachine(typeof(<RequestMessagesDelayed>d__5))]
		private static IEnumerator RequestMessagesDelayed()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RequestMessagesDelayed>d__5(0);
		}
	}
	public class MessageStone : MonoBehaviour, Hoverable, Interactable
	{
		private ZNetView _netView;

		private bool _isInitialized;

		private Light _glowLight;

		private ParticleSystem _particles;

		private string _hoverText = "Message Stone";

		public string MessageId { get; private set; }

		public string Template { get; private set; }

		public string Words { get; private set; }

		public int EmoteIndex { get; private set; }

		public int Reputation { get; private set; }

		private void Awake()
		{
			_netView = ((Component)this).GetComponent<ZNetView>();
			_glowLight = ((Component)this).GetComponentInChildren<Light>();
			_particles = ((Component)this).GetComponentInChildren<ParticleSystem>();
		}

		private void Start()
		{
			if ((Object)(object)_netView != (Object)null && _netView.IsValid())
			{
				LoadFromZDO();
			}
		}

		public void Initialize(string messageId, string template, string words, int emoteIndex, int reputation)
		{
			MessageId = messageId;
			Template = template;
			Words = words;
			EmoteIndex = emoteIndex;
			Reputation = reputation;
			_isInitialized = true;
			string message = MessageTemplates.FormatMessage(template, words);
			_hoverText = "[E] Read Message\n\"" + TruncateMessage(message, 50) + "\"";
			SaveToZDO();
			UpdateVisuals();
		}

		private void SaveToZDO()
		{
			if (!((Object)(object)_netView == (Object)null) && _netView.IsValid())
			{
				_netView.GetZDO().Set("viking_msg_id", MessageId ?? "");
				_netView.GetZDO().Set("viking_msg_template", Template ?? "");
				_netView.GetZDO().Set("viking_msg_words", Words ?? "");
				_netView.GetZDO().Set("viking_msg_emote", EmoteIndex);
				_netView.GetZDO().Set("viking_msg_rep", Reputation);
			}
		}

		private void LoadFromZDO()
		{
			if (!((Object)(object)_netView == (Object)null) && _netView.IsValid())
			{
				MessageId = _netView.GetZDO().GetString("viking_msg_id", "");
				Template = _netView.GetZDO().GetString("viking_msg_template", "");
				Words = _netView.GetZDO().GetString("viking_msg_words", "");
				EmoteIndex = _netView.GetZDO().GetInt("viking_msg_emote", -1);
				Reputation = _netView.GetZDO().GetInt("viking_msg_rep", 0);
				if (!string.IsNullOrEmpty(MessageId))
				{
					_isInitialized = true;
					string message = MessageTemplates.FormatMessage(Template, Words);
					_hoverText = "[E] Read Message\n\"" + TruncateMessage(message, 50) + "\"";
					UpdateVisuals();
				}
			}
		}

		private string TruncateMessage(string message, int maxLength)
		{
			if (string.IsNullOrEmpty(message))
			{
				return "";
			}
			if (message.Length <= maxLength)
			{
				return message;
			}
			return message.Substring(0, maxLength - 3) + "...";
		}

		private void UpdateVisuals()
		{
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_glowLight != (Object)null)
			{
				if (Reputation > 5)
				{
					_glowLight.color = new Color(1f, 0.9f, 0.5f);
					_glowLight.intensity = 2f;
				}
				else if (Reputation > 0)
				{
					_glowLight.color = new Color(0.8f, 0.9f, 1f);
					_glowLight.intensity = 1.5f;
				}
				else if (Reputation < 0)
				{
					_glowLight.color = new Color(0.8f, 0.5f, 0.5f);
					_glowLight.intensity = 0.8f;
				}
				else
				{
					_glowLight.color = new Color(0.7f, 0.85f, 1f);
					_glowLight.intensity = 1.2f;
				}
			}
			if ((Object)(object)_particles != (Object)null)
			{
				MainModule main = _particles.main;
				((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit((Color)(((Object)(object)_glowLight != (Object)null) ? _glowLight.color : new Color(0.7f, 0.85f, 1f, 0.6f)));
			}
		}

		public string GetHoverText()
		{
			if (!_isInitialized)
			{
				return "Ancient Stone";
			}
			return _hoverText;
		}

		public string GetHoverName()
		{
			return "Message Stone";
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (hold)
			{
				return false;
			}
			ManualLogSource log = VikingMessagesPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"MessageStone Interact called - Initialized: {_isInitialized}, ID: {MessageId}");
			}
			if (!_isInitialized)
			{
				ManualLogSource log2 = VikingMessagesPlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"MessageStone not initialized");
				}
				return false;
			}
			VikingMessage message = MessageManagerAlt.GetMessage(MessageId);
			string template;
			string words;
			int emoteIndex;
			int reputation;
			if (message != null)
			{
				template = message.Template;
				words = message.Words;
				emoteIndex = message.EmoteIndex;
				reputation = message.Reputation;
				ManualLogSource log3 = VikingMessagesPlugin.Log;
				if (log3 != null)
				{
					log3.LogInfo((object)("Got message from manager: " + template + " / " + words));
				}
			}
			else
			{
				template = Template;
				words = Words;
				emoteIndex = EmoteIndex;
				reputation = Reputation;
				ManualLogSource log4 = VikingMessagesPlugin.Log;
				if (log4 != null)
				{
					log4.LogInfo((object)("Using local data: " + template + " / " + words));
				}
			}
			string text = MessageTemplates.FormatMessage(template, words);
			ManualLogSource log5 = VikingMessagesPlugin.Log;
			if (log5 != null)
			{
				log5.LogInfo((object)$"Showing read UI with: '{text}', rep={reputation}");
			}
			MessageUIManager.ShowReadUI(MessageId, text, reputation);
			if (emoteIndex >= 0 && emoteIndex < MessageTemplates.AvailableEmotes.Count)
			{
				string emoteName = MessageTemplates.AvailableEmotes[emoteIndex];
				TriggerEmote((Player)(object)((user is Player) ? user : null), emoteName);
			}
			return true;
		}

		private void TriggerEmote(Player player, string emoteName)
		{
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			try
			{
				player.StartEmote(emoteName, true);
				ManualLogSource log = VikingMessagesPlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("Triggered emote: " + emoteName));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = VikingMessagesPlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("Could not trigger emote '" + emoteName + "': " + ex.Message));
				}
			}
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			return false;
		}

		public void UpdateReputation(int newReputation)
		{
			Reputation = newReputation;
			if ((Object)(object)_netView != (Object)null && _netView.IsValid())
			{
				_netView.GetZDO().Set("viking_msg_rep", Reputation);
			}
			UpdateVisuals();
			string message = MessageTemplates.FormatMessage(Template, Words);
			_hoverText = "[E] Read Message\n\"" + TruncateMessage(message, 50) + "\"";
		}
	}
	public static class MessageTemplates
	{
		public static readonly Dictionary<string, List<string>> Categories = new Dictionary<string, List<string>>
		{
			["Battle"] = new List<string>
			{
				"Beware of {0}", "Be wary of {0}", "Watch out for {0}", "{0} ahead", "Weak foe ahead", "Strong foe ahead", "Likely {0}", "Time for {0}", "Didn't expect {0}", "First off, {0}",
				"Victory is near!", "Defeat is near...", "Prepare for battle", "Ready your {0}", "Ambush ahead!", "Retreat!", "Charge!", "Hold the line!", "{0} required ahead"
			},
			["Guidance"] = new List<string>
			{
				"Try {0}", "Don't give up!", "Keep going", "Turn back", "Go forward", "Go left", "Go right", "Look up", "Look down", "Hidden path ahead",
				"Treasure ahead", "Nothing here...", "Trap ahead!", "Safe zone", "Shortcut ahead", "Detour ahead", "Jump required", "Seek {0}", "Path of {0}"
			},
			["Location"] = new List<string>
			{
				"Biome ahead: {0}", "Boss ahead", "Dungeon ahead", "Village ahead", "Camp ahead", "Water ahead", "Mountain ahead", "Forest ahead", "Plains ahead", "Swamp ahead",
				"Ocean ahead", "Cave ahead", "Bridge ahead", "Shelter here", "Danger zone", "Sacred ground", "Cursed land"
			},
			["Resources"] = new List<string>
			{
				"Ore vein nearby", "Wood aplenty", "Rich in {0}", "Gather {0} here", "Mining spot", "Hunting ground", "Good fishing", "Berry bushes nearby", "Mushrooms ahead", "Crafting station needed",
				"Upgrade here", "Repair needed", "Food required", "Stamina low", "Health critical"
			},
			["Emotion"] = new List<string>
			{
				"Praise Odin!", "Valhalla awaits!", "By Thor's hammer!", "The gods smile upon you", "Despair...", "Hope ahead", "Fear not", "Courage required", "Patience needed", "Celebrate!",
				"Mourn...", "Rest here", "Think carefully", "Act quickly!", "Take your time", "Why always {0}?", "Ah, {0}...", "If only {0}...", "O, {0}!"
			},
			["Multiplayer"] = new List<string>
			{
				"Need ally", "Seek friend", "Beware of betrayal", "Cooperation required", "Share the load", "Follow me", "Wait here", "Protect this", "Rally point", "Meeting spot",
				"Trading post", "Help needed!", "Offering help", "Expert ahead", "Newbie zone"
			},
			["Strategy"] = new List<string>
			{
				"Stealth effective", "Brute force works", "Ranged attack recommended", "Melee required", "Use {0}", "Avoid {0}", "Weak to {0}", "Resistant to {0}", "Block and counter", "Dodge and strike",
				"Kite around", "Stand your ground", "Hit and run", "Divide and conquer", "Focus on {0}"
			},
			["Humor"] = new List<string>
			{
				"Liar ahead", "Message ahead", "Try fingers, but hole", "Could this be {0}?", "Didn't expect {0}!", "Why is it always {0}?", "Behold, {0}!", "Secret: {0}", "Legend says {0}", "Rumor has it {0}",
				"I did it!", "I can't take this...", "Let me solo this", "Don't you dare!", "Praise the {0}!", "Gorgeous view ahead", "Time for sleep", "Edge, Lord"
			}
		};

		public static readonly Dictionary<string, List<string>> WordCategories = new Dictionary<string, List<string>>
		{
			["Enemies"] = new List<string>
			{
				"Greylings", "Greydwarfs", "Trolls", "Skeletons", "Draugr", "Wraiths", "Blobs", "Leeches", "Deathsquitos", "Fulings",
				"Serpents", "Wolves", "Boars", "Necks", "Surtlings", "Golems", "Lox", "Drakes", "Abominations", "Seekers",
				"Gjall"
			},
			["Bosses"] = new List<string> { "Eikthyr", "The Elder", "Bonemass", "Moder", "Yagluth", "The Queen", "Boss", "Forsaken" },
			["Biomes"] = new List<string> { "Meadows", "Black Forest", "Swamp", "Mountains", "Plains", "Ocean", "Mistlands", "Ashlands", "Deep North" },
			["Materials"] = new List<string>
			{
				"Wood", "Stone", "Flint", "Copper", "Tin", "Bronze", "Iron", "Silver", "Black Metal", "Flametal",
				"Leather", "Bone", "Resin", "Greydwarf Eyes", "Trophies", "Core Wood", "Fine Wood", "Ancient Bark", "Yggdrasil Wood"
			},
			["Actions"] = new List<string>
			{
				"attacking", "blocking", "dodging", "jumping", "running", "sneaking", "swimming", "climbing", "building", "crafting",
				"mining", "chopping", "hunting", "fishing", "cooking", "sailing", "resting", "praying", "fighting", "fleeing"
			},
			["Equipment"] = new List<string>
			{
				"sword", "axe", "mace", "spear", "bow", "shield", "armor", "helmet", "cape", "pickaxe",
				"hammer", "hoe", "cultivator", "torch", "portal", "cart", "boat", "raft"
			},
			["Concepts"] = new List<string>
			{
				"death", "victory", "defeat", "glory", "honor", "wisdom", "courage", "strength", "speed", "stealth",
				"luck", "karma", "fate", "Valhalla", "Odin", "Thor", "Freya", "Loki", "Ragnarok", "adventure"
			},
			["Descriptors"] = new List<string>
			{
				"danger", "treasure", "secret", "trap", "ambush", "shortcut", "dead end", "safe spot", "spawn point", "portal hub",
				"base", "outpost", "farm", "graveyard", "dungeon", "crypt", "ruin"
			},
			["Directions"] = new List<string>
			{
				"north", "south", "east", "west", "up", "down", "left", "right", "forward", "behind",
				"inside", "outside", "above", "below"
			}
		};

		public static readonly List<string> AvailableEmotes = new List<string>
		{
			"wave", "sit", "challenge", "cheer", "nonono", "thumbsup", "point", "comehere", "bow", "cower",
			"cry", "despair", "flex", "headbang", "kneel", "laugh", "roar", "shrug", "dance", "blowkiss"
		};

		public static readonly List<string> Conjunctions = new List<string> { "and then", "or", "but", "therefore", "in short", "however", "also", "by the way", "all the more", "even so" };

		public static string GetEmoteName(int index)
		{
			if (index >= 0 && index < AvailableEmotes.Count)
			{
				return AvailableEmotes[index];
			}
			return "wave";
		}

		public static int GetEmoteIndex(string emoteName)
		{
			int num = AvailableEmotes.IndexOf(emoteName.ToLower());
			return (num >= 0) ? num : 0;
		}

		public static string FormatMessage(string template, string words)
		{
			if (string.IsNullOrEmpty(template))
			{
				return "...";
			}
			if (template.Contains("{0}") && !string.IsNullOrEmpty(words))
			{
				return string.Format(template, words);
			}
			return template;
		}

		public static List<string> GetAllTemplates()
		{
			return Categories.Values.SelectMany((List<string> x) => x).ToList();
		}

		public static List<string> GetTemplatesByCategory(string category)
		{
			List<string> value;
			return Categories.TryGetValue(category, out value) ? value : new List<string>();
		}

		public static List<string> GetAllWords()
		{
			return WordCategories.Values.SelectMany((List<string> x) => x).ToList();
		}

		public static List<string> GetWordsByCategory(string category)
		{
			List<string> value;
			return WordCategories.TryGetValue(category, out value) ? value : new List<string>();
		}

		public static bool TemplateRequiresWord(string template)
		{
			return template?.Contains("{0}") ?? false;
		}
	}
	public class MessageUI : MonoBehaviour
	{
		private static MessageUI _instance;

		private bool _isCreatingMessage;

		private bool _isReadingMessage;

		private Vector3 _pendingPosition;

		private Quaternion _pendingRotation;

		private string _currentMessageId;

		private GameObject _createPanel;

		private GameObject _readPanel;

		private GameObject _backgroundOverlay;

		private Canvas _canvas;

		private int _categoryIndex;

		private int _templateIndex;

		private int _wordCategoryIndex;

		private int _wordIndex;

		private int _emoteIndex;

		private int _currentRow;

		private List<string> _categories;

		private List<string> _templates;

		private List<string> _wordCategories;

		private List<string> _words;

		private List<string> _emotes;

		private Text _categoryText;

		private Text _templateText;

		private Text _wordCategoryText;

		private Text _wordText;

		private Text _emoteText;

		private Text _previewText;

		private Image[] _rowBackgrounds;

		private Text _messageText;

		private Text _reputationText;

		private static readonly Color PanelColor = new Color(0.15f, 0.12f, 0.08f, 0.95f);

		private static readonly Color BorderColor = new Color(0.55f, 0.45f, 0.3f, 1f);

		private static readonly Color TextColor = new Color(0.95f, 0.9f, 0.8f, 1f);

		private static readonly Color HighlightColor = new Color(0.8f, 0.65f, 0.35f, 1f);

		private static readonly Color SelectedBg = new Color(0.5f, 0.4f, 0.25f, 0.9f);

		private static readonly Color UnselectedBg = new Color(0.2f, 0.17f, 0.12f, 0.7f);

		public static MessageUI Instance => _instance;

		public bool IsUIOpen => _isCreatingMessage || _isReadingMessage;

		private void Awake()
		{
			_instance = this;
			_categories = MessageTemplates.Categories.Keys.ToList();
			_wordCategories = MessageTemplates.WordCategories.Keys.ToList();
			_emotes = MessageTemplates.AvailableEmotes.ToList();
			_templates = ((_categories.Count > 0) ? MessageTemplates.GetTemplatesByCategory(_categories[0]).ToList() : new List<string>());
			_words = ((_wordCategories.Count > 0) ? MessageTemplates.GetWordsByCategory(_wordCategories[0]).ToList() : new List<string>());
			CreateUIElements();
			HideAllUI();
			ManualLogSource log = VikingMessagesPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"MessageUI initialized - {_categories.Count} categories, {_templates.Count} templates");
			}
		}

		private void Update()
		{
			if (_isCreatingMessage)
			{
				HandleCreateInput();
			}
			else if (_isReadingMessage)
			{
				HandleReadInput();
			}
		}

		private void HandleCreateInput()
		{
			bool flag = false;
			if (Input.GetKeyDown((KeyCode)273) || Input.GetKeyDown((KeyCode)119))
			{
				ChangeRow(-1);
				flag = true;
			}
			else if (Input.GetKeyDown((KeyCode)274) || Input.GetKeyDown((KeyCode)115))
			{
				ChangeRow(1);
				flag = true;
			}
			else if (Input.GetKeyDown((KeyCode)276) || Input.GetKeyDown((KeyCode)97))
			{
				ChangeOption(-1);
				flag = true;
			}
			else if (Input.GetKeyDown((KeyCode)275) || Input.GetKeyDown((KeyCode)100))
			{
				ChangeOption(1);
				flag = true;
			}
			else if (Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)101))
			{
				ConfirmMessage();
				flag = true;
			}
			else if (Input.GetKeyDown((KeyCode)27) || Input.GetKeyDown((KeyCode)9))
			{
				CancelMessage();
				flag = true;
			}
			if (flag)
			{
				Input.ResetInputAxes();
			}
		}

		private void HandleReadInput()
		{
			if (Input.GetKeyDown((KeyCode)276) || Input.GetKeyDown((KeyCode)97))
			{
				VoteOnCurrentMessage(isPositive: true);
			}
			else if (Input.GetKeyDown((KeyCode)275) || Input.GetKeyDown((KeyCode)100))
			{
				VoteOnCurrentMessage(isPositive: false);
			}
			else if (Input.GetMouseButtonDown(0))
			{
				VoteOnCurrentMessage(isPositive: true);
			}
			else if (Input.GetMouseButtonDown(1))
			{
				VoteOnCurrentMessage(isPositive: false);
			}
			else if (Input.GetKeyDown((KeyCode)27) || Input.GetKeyDown((KeyCode)101) || Input.GetKeyDown((KeyCode)13))
			{
				CloseReadUI();
			}
		}

		private void ChangeRow(int direction)
		{
			int currentRow = _currentRow;
			_currentRow += direction;
			if (_currentRow < 0)
			{
				_currentRow = 4;
			}
			if (_currentRow > 4)
			{
				_currentRow = 0;
			}
			UpdateRowHighlights();
			ManualLogSource log = VikingMessagesPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"Row changed: {currentRow} -> {_currentRow}");
			}
		}

		private void ChangeOption(int direction)
		{
			switch (_currentRow)
			{
			case 0:
				_categoryIndex = WrapIndex(_categoryIndex + direction, _categories.Count);
				_templates = MessageTemplates.GetTemplatesByCategory(_categories[_categoryIndex]).ToList();
				_templateIndex = 0;
				UpdateCategoryDisplay();
				UpdateTemplateDisplay();
				break;
			case 1:
				_templateIndex = WrapIndex(_templateIndex + direction, _templates.Count);
				UpdateTemplateDisplay();
				break;
			case 2:
				_wordCategoryIndex = WrapIndex(_wordCategoryIndex + direction, _wordCategories.Count);
				_words = MessageTemplates.GetWordsByCategory(_wordCategories[_wordCategoryIndex]).ToList();
				_wordIndex = 0;
				UpdateWordCategoryDisplay();
				UpdateWordDisplay();
				break;
			case 3:
				_wordIndex = WrapIndex(_wordIndex + direction, _words.Count);
				UpdateWordDisplay();
				break;
			case 4:
				_emoteIndex = WrapIndex(_emoteIndex + direction, _emotes.Count);
				UpdateEmoteDisplay();
				break;
			}
			UpdatePreview();
		}

		private int WrapIndex(int index, int count)
		{
			if (count == 0)
			{
				return 0;
			}
			if (index < 0)
			{
				return count - 1;
			}
			if (index >= count)
			{
				return 0;
			}
			return index;
		}

		private void UpdateRowHighlights()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (_rowBackgrounds == null)
			{
				return;
			}
			for (int i = 0; i < _rowBackgrounds.Length; i++)
			{
				if ((Object)(object)_rowBackgrounds[i] != (Object)null)
				{
					((Graphic)_rowBackgrounds[i]).color = ((i == _currentRow) ? SelectedBg : UnselectedBg);
				}
			}
		}

		private void UpdateCategoryDisplay()
		{
			if ((Object)(object)_categoryText != (Object)null && _categories.Count > 0)
			{
				_categoryText.text = "◄ " + _categories[_categoryIndex] + " ►";
			}
		}

		private void UpdateTemplateDisplay()
		{
			if ((Object)(object)_templateText != (Object)null && _templates.Count > 0)
			{
				_templateText.text = "◄ " + _templates[_templateIndex] + " ►";
			}
		}

		private void UpdateWordCategoryDisplay()
		{
			if ((Object)(object)_wordCategoryText != (Object)null && _wordCategories.Count > 0)
			{
				_wordCategoryText.text = "◄ " + _wordCategories[_wordCategoryIndex] + " ►";
			}
		}

		private void UpdateWordDisplay()
		{
			if ((Object)(object)_wordText != (Object)null && _words.Count > 0)
			{
				_wordText.text = "◄ " + _words[_wordIndex] + " ►";
			}
		}

		private void UpdateEmoteDisplay()
		{
			if ((Object)(object)_emoteText != (Object)null && _emotes.Count > 0)
			{
				_emoteText.text = "◄ " + _emotes[_emoteIndex] + " ►";
			}
		}

		private void UpdatePreview()
		{
			if (!((Object)(object)_previewText == (Object)null))
			{
				string template = ((_templates.Count > _templateIndex) ? _templates[_templateIndex] : "");
				string words = ((_words.Count > _wordIndex) ? _words[_wordIndex] : "");
				string text = MessageTemplates.FormatMessage(template, words);
				_previewText.text = "\"" + text + "\"";
			}
		}

		private void UpdateAllDisplays()
		{
			UpdateCategoryDisplay();
			UpdateTemplateDisplay();
			UpdateWordCategoryDisplay();
			UpdateWordDisplay();
			UpdateEmoteDisplay();
			UpdatePreview();
			UpdateRowHighlights();
		}

		private void CreateUIElements()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_005f: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("VikingMessagesCanvas");
			val.transform.SetParent(((Component)this).transform);
			_canvas = val.AddComponent<Canvas>();
			_canvas.renderMode = (RenderMode)0;
			_canvas.sortingOrder = 100;
			CanvasScaler val2 = val.AddComponent<CanvasScaler>();
			val2.uiScaleMode = (ScaleMode)1;
			val2.referenceResolution = new Vector2(1920f, 1080f);
			val.AddComponent<GraphicRaycaster>();
			_backgroundOverlay = CreatePanel("BackgroundOverlay", val.transform, Vector2.zero, new Vector2(4000f, 4000f));
			((Graphic)_backgroundOverlay.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.5f);
			CreateMessageCreateUI(val.transform);
			CreateMessageReadUI(val.transform);
		}

		private void CreateMessageCreateUI(Transform parent)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0300: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0351: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_036d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0390: Unknown result type (might be due to invalid IL or missing references)
			//IL_039f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0423: Unknown result type (might be due to invalid IL or missing references)
			//IL_0432: Unknown result type (might be due to invalid IL or missing references)
			//IL_043f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0469: 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_0494: Unknown result type (might be due to invalid IL or missing references)
			_createPanel = CreatePanel("CreateMessagePanel", parent, Vector2.zero, new Vector2(520f, 440f));
			((Graphic)_createPanel.GetComponent<Image>()).color = PanelColor;
			AddBorder(_createPanel);
			CreateText("Title", _createPanel.transform, new Vector2(0f, 185f), new Vector2(480f, 40f), "═══ INSCRIBE MESSAGE ═══", 22, (TextAnchor)4, HighlightColor);
			_rowBackgrounds = (Image[])(object)new Image[5];
			float num = 125f;
			float num2 = 42f;
			_rowBackgrounds[0] = CreateRowBackground(_createPanel.transform, num);
			CreateText("CategoryLabel", _createPanel.transform, new Vector2(-160f, num), new Vector2(120f, 35f), "Category:", 15, (TextAnchor)5, TextColor);
			_categoryText = CreateText("CategoryValue", _createPanel.transform, new Vector2(60f, num), new Vector2(240f, 35f), "", 14, (TextAnchor)4, TextColor);
			num -= num2;
			_rowBackgrounds[1] = CreateRowBackground(_createPanel.transform, num);
			CreateText("TemplateLabel", _createPanel.transform, new Vector2(-160f, num), new Vector2(120f, 35f), "Template:", 15, (TextAnchor)5, TextColor);
			_templateText = CreateText("TemplateValue", _createPanel.transform, new Vector2(60f, num), new Vector2(240f, 35f), "", 14, (TextAnchor)4, TextColor);
			num -= num2;
			_rowBackgrounds[2] = CreateRowBackground(_createPanel.transform, num);
			CreateText("WordCatLabel", _createPanel.transform, new Vector2(-160f, num), new Vector2(120f, 35f), "Word Type:", 15, (TextAnchor)5, TextColor);
			_wordCategoryText = CreateText("WordCatValue", _createPanel.transform, new Vector2(60f, num), new Vector2(240f, 35f), "", 14, (TextAnchor)4, TextColor);
			num -= num2;
			_rowBackgrounds[3] = CreateRowBackground(_createPanel.transform, num);
			CreateText("WordLabel", _createPanel.transform, new Vector2(-160f, num), new Vector2(120f, 35f), "Word:", 15, (TextAnchor)5, TextColor);
			_wordText = CreateText("WordValue", _createPanel.transform, new Vector2(60f, num), new Vector2(240f, 35f), "", 14, (TextAnchor)4, TextColor);
			num -= num2;
			_rowBackgrounds[4] = CreateRowBackground(_createPanel.transform, num);
			CreateText("EmoteLabel", _createPanel.transform, new Vector2(-160f, num), new Vector2(120f, 35f), "Gesture:", 15, (TextAnchor)5, TextColor);
			_emoteText = CreateText("EmoteValue", _createPanel.transform, new Vector2(60f, num), new Vector2(240f, 35f), "", 14, (TextAnchor)4, TextColor);
			num -= num2 + 10f;
			CreateText("PreviewLabel", _createPanel.transform, new Vector2(0f, num), new Vector2(480f, 25f), "── Preview ──", 14, (TextAnchor)4, TextColor);
			num -= 35f;
			_previewText = CreateText("Preview", _createPanel.transform, new Vector2(0f, num), new Vector2(480f, 40f), "", 18, (TextAnchor)4, HighlightColor);
			CreateText("Controls", _createPanel.transform, new Vector2(0f, -190f), new Vector2(480f, 40f), "[↑↓] Row    [←→] Option    [E/Enter] Confirm    [Esc] Cancel", 12, (TextAnchor)4, new Color(0.6f, 0.55f, 0.45f));
		}

		private Image CreateRowBackground(Transform parent, float yPos)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("RowBg");
			val.transform.SetParent(parent, false);
			RectTransform val2 = val.AddComponent<RectTransform>();
			val2.anchorMin = new Vector2(0.5f, 0.5f);
			val2.anchorMax = new Vector2(0.5f, 0.5f);
			val2.anchoredPosition = new Vector2(0f, yPos);
			val2.sizeDelta = new Vector2(480f, 38f);
			Image val3 = val.AddComponent<Image>();
			((Graphic)val3).color = UnselectedBg;
			return val3;
		}

		private void CreateMessageReadUI(Transform parent)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			_readPanel = CreatePanel("ReadMessagePanel", parent, Vector2.zero, new Vector2(450f, 180f));
			((Graphic)_readPanel.GetComponent<Image>()).color = PanelColor;
			AddBorder(_readPanel);
			_messageText = CreateText("MessageText", _readPanel.transform, new Vector2(0f, 45f), new Vector2(420f, 50f), "", 18, (TextAnchor)4, TextColor);
			_reputationText = CreateText("ReputationText", _readPanel.transform, new Vector2(0f, 0f), new Vector2(420f, 30f), "Reputation: 0", 16, (TextAnchor)4, HighlightColor);
			CreateText("ControlsHint", _readPanel.transform, new Vector2(0f, -55f), new Vector2(420f, 45f), "[←/LClick] Appraise    [→/RClick] Disparage    [E/Esc] Close", 12, (TextAnchor)4, new Color(0.6f, 0.55f, 0.45f));
		}

		private GameObject CreatePanel(string name, Transform parent, Vector2 position, Vector2 size)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0028: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			RectTransform val2 = val.AddComponent<RectTransform>();
			val2.anchorMin = new Vector2(0.5f, 0.5f);
			val2.anchorMax = new Vector2(0.5f, 0.5f);
			val2.anchoredPosition = position;
			val2.sizeDelta = size;
			Image val3 = val.AddComponent<Image>();
			((Graphic)val3).color = PanelColor;
			return val;
		}

		private void AddBorder(GameObject panel)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			Outline val = panel.AddComponent<Outline>();
			((Shadow)val).effectColor = BorderColor;
			((Shadow)val).effectDistance = new Vector2(2f, 2f);
		}

		private Text CreateText(string name, Transform parent, Vector2 position, Vector2 size, string content, int fontSize, TextAnchor alignment, Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0028: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			RectTransform val2 = val.AddComponent<RectTransform>();
			val2.anchorMin = new Vector2(0.5f, 0.5f);
			val2.anchorMax = new Vector2(0.5f, 0.5f);
			val2.anchoredPosition = position;
			val2.sizeDelta = size;
			Text val3 = val.AddComponent<Text>();
			val3.text = content;
			val3.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			val3.fontSize = fontSize;
			((Graphic)val3).color = color;
			val3.alignment = alignment;
			return val3;
		}

		public void ShowCreateUI(Vector3 position, Quaternion rotation)
		{
			//IL_0018: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			ManualLogSource log = VikingMessagesPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"ShowCreateUI called");
			}
			_pendingPosition = position;
			_pendingRotation = rotation;
			_categoryIndex = 0;
			_templateIndex = 0;
			_wordCategoryIndex = 0;
			_wordIndex = 0;
			_emoteIndex = 0;
			_currentRow = 0;
			_categories = MessageTemplates.Categories.Keys.ToList();
			_wordCategories = MessageTemplates.WordCategories.Keys.ToList();
			_emotes = MessageTemplates.AvailableEmotes.ToList();
			if (_categories.Count > 0)
			{
				_templates = MessageTemplates.GetTemplatesByCategory(_categories[0]).ToList();
			}
			if (_wordCategories.Count > 0)
			{
				_words = MessageTemplates.GetWordsByCategory(_wordCategories[0]).ToList();
			}
			UpdateAllDisplays();
			GameObject backgroundOverlay = _backgroundOverlay;
			if (backgroundOverlay != null)
			{
				backgroundOverlay.SetActive(true);
			}
			GameObject createPanel = _createPanel;
			if (createPanel != null)
			{
				createPanel.SetActive(true);
			}
			_isCreatingMessage = true;
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
			ManualLogSource log2 = VikingMessagesPlugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)$"Create UI shown - templates: {_templates.Count}, words: {_words.Count}");
			}
		}

		public void ShowReadUI(string messageId, string messageText, int reputation)
		{
			ManualLogSource log = VikingMessagesPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"ShowReadUI called: id={messageId}, text={messageText}, rep={reputation}");
			}
			_currentMessageId = messageId;
			if ((Object)(object)_messageText != (Object)null)
			{
				_messageText.text = "\"" + messageText + "\"";
			}
			if ((Object)(object)_reputationText != (Object)null)
			{
				_reputationText.text = $"Reputation: {reputation}";
			}
			GameObject backgroundOverlay = _backgroundOverlay;
			if (backgroundOverlay != null)
			{
				backgroundOverlay.SetActive(true);
			}
			GameObject readPanel = _readPanel;
			if (readPanel != null)
			{
				readPanel.SetActive(true);
			}
			_isReadingMessage = true;
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
		}

		private void ConfirmMessage()
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			string text = ((_templates.Count > _templateIndex) ? _templates[_templateIndex] : "");
			string text2 = ((_words.Count > _wordIndex) ? _words[_wordIndex] : "");
			int emoteIndex = _emoteIndex;
			ManualLogSource log = VikingMessagesPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"ConfirmMessage: template='{text}', word='{text2}', emote={emoteIndex}");
			}
			if (string.IsNullOrEmpty(text))
			{
				ManualLogSource log2 = VikingMessagesPlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"No template selected!");
				}
			}
			else
			{
				MessageManagerAlt.PlaceMessage(_pendingPosition, _pendingRotation, text, text2, emoteIndex);
				HideAllUI();
				RelockCursor();
			}
		}

		private void CancelMessage()
		{
			HideAllUI();
			RelockCursor();
			try
			{
				if (!((Object)(object)Player.m_localPlayer != (Object)null))
				{
					return;
				}
				GameObject prefab = PrefabManager.Instance.GetPrefab("MessageGlyph");
				if ((Object)(object)prefab != (Object)null)
				{
					ItemDrop component = prefab.GetComponent<ItemDrop>();
					if ((Object)(object)component != (Object)null)
					{
						ItemData val = component.m_itemData.Clone();
						val.m_stack = 1;
						((Humanoid)Player.m_localPlayer).GetInventory().AddItem(val);
						((Character)Player.m_localPlayer).Message((MessageType)1, "Message cancelled, glyph returned", 0, (Sprite)null);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = VikingMessagesPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Could not refund glyph: " + ex.Message));
				}
			}
		}

		private void VoteOnCurrentMessage(bool isPositive)
		{
			if (string.IsNullOrEmpty(_currentMessageId))
			{
				ManualLogSource log = VikingMessagesPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"No message ID for voting");
				}
				return;
			}
			ManualLogSource log2 = VikingMessagesPlugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)("Voting on " + _currentMessageId + ": " + (isPositive ? "Appraise" : "Disparage")));
			}
			MessageManagerAlt.VoteMessage(_currentMessageId, isPositive);
			VikingMessage message = MessageManagerAlt.GetMessage(_currentMessageId);
			if (message != null && (Object)(object)_reputationText != (Object)null)
			{
				_reputationText.text = $"Reputation: {message.Reputation}";
			}
			string text = (isPositive ? "Appraised!" : "Disparaged!");
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null);
			}
		}

		private void CloseReadUI()
		{
			ManualLogSource log = VikingMessagesPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"CloseReadUI called");
			}
			_currentMessageId = null;
			HideAllUI();
			RelockCursor();
		}

		private void HideAllUI()
		{
			GameObject createPanel = _createPanel;
			if (createPanel != null)
			{
				createPanel.SetActive(false);
			}
			GameObject readPanel = _readPanel;
			if (readPanel != null)
			{
				readPanel.SetActive(false);
			}
			GameObject backgroundOverlay = _backgroundOverlay;
			if (backgroundOverlay != null)
			{
				backgroundOverlay.SetActive(false);
			}
			_isCreatingMessage = false;
			_isReadingMessage = false;
		}

		private void RelockCursor()
		{
			Cursor.lockState = (CursorLockMode)1;
			Cursor.visible = false;
		}
	}
	public static class MessageUIManager
	{
		private static MessageUI _ui;

		public static MessageUI UI
		{
			get
			{
				if ((Object)(object)_ui == (Object)null)
				{
					CreateUI();
				}
				return _ui;
			}
		}

		public static bool IsUIOpen => UI?.IsUIOpen ?? false;

		private static void CreateUI()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			GameObject val = new GameObject("VikingMessagesUI");
			Object.DontDestroyOnLoad((Object)(object)val);
			_ui = val.AddComponent<MessageUI>();
		}

		public static void ShowCreateUI(Vector3 position, Quaternion rotation)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			UI?.ShowCreateUI(position, rotation);
		}

		public static void ShowReadUI(string messageId, string messageText, int reputation)
		{
			UI?.ShowReadUI(messageId, messageText, reputation);
		}
	}
	[BepInPlugin("com.vikings.messages", "Viking Messages", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class VikingMessagesPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.vikings.messages";

		public const string PluginName = "Viking Messages";

		public const string PluginVersion = "1.0.0";

		private Harmony _harmony;

		public static GameObject MessageStonePrefab;

		public static GameObject GhostPhantomPrefab;

		public static ConfigEntry<int> MinReputation;

		public static ConfigEntry<float> MessageInteractDistance;

		public static ConfigEntry<float> GhostDisplayDuration;

		public static VikingMessagesPlugin Instance { get; private set; }

		public static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger;

		private void Awake()
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			Instance = this;
			MinReputation = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MinReputation", -5, "Minimum reputation before a message is removed");
			MessageInteractDistance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "InteractDistance", 3f, "Distance at which players can interact with messages");
			GhostDisplayDuration = ((BaseUnityPlugin)this).Config.Bind<float>("General", "GhostDuration", 5f, "Duration in seconds the ghost phantom is displayed");
			_harmony = new Harmony("com.vikings.messages");
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			PrefabManager.OnVanillaPrefabsAvailable += RegisterPrefabsAndItems;
			MessageManagerAlt.Initialize();
			Log.LogInfo((object)"Viking Messages v1.0.0 loaded!");
		}

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

		private void RegisterPrefabsAndItems()
		{
			try
			{
				CreateMessageStonePrefab();
				CreateGhostPhantomPrefab();
				Log.LogInfo((object)"Prefabs registered successfully");
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Failed to register prefabs: {arg}");
			}
			try
			{
				CreateMessageGlyphItem();
				Log.LogInfo((object)"Items registered successfully");
			}
			catch (Exception arg2)
			{
				Log.LogError((object)$"Failed to register items: {arg2}");
			}
		}

		private void CreateMessageStonePrefab()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			GameObject prefab = PrefabManager.Instance.GetPrefab("stone_wall_2x1");
			if ((Object)(object)prefab == (Object)null)
			{
				Log.LogError((object)"Could not find stone_wall_2x1 prefab!");
				return;
			}
			MessageStonePrefab = PrefabManager.Instance.CreateClonedPrefab("VikingMessageStone", prefab);
			MessageStonePrefab.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);
			Object.Destroy((Object)(object)MessageStonePrefab.GetComponent<WearNTear>());
			Object.Destroy((Object)(object)MessageStonePrefab.GetComponent<Piece>());
			MessageStonePrefab.AddComponent<MessageStone>();
			ZNetView val = MessageStonePrefab.GetComponent<ZNetView>();
			if ((Object)(object)val == (Object)null)
			{
				val = MessageStonePrefab.AddComponent<ZNetView>();
			}
			val.m_persistent = true;
			try
			{
				AddGlowEffect(MessageStonePrefab);
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not add glow effect to message stone: " + ex.Message));
			}
			PrefabManager.Instance.AddPrefab(MessageStonePrefab);
		}

		private void AddGlowEffect(GameObject obj)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("GlowLight");
			val.transform.SetParent(obj.transform);
			val.transform.localPosition = new Vector3(0f, 0.5f, 0f);
			Light val2 = val.AddComponent<Light>();
			val2.type = (LightType)2;
			val2.color = new Color(0.8f, 0.9f, 1f);
			val2.intensity = 1.5f;
			val2.range = 3f;
			val2.shadows = (LightShadows)0;
			val.AddComponent<GlowPulse>();
			try
			{
				GameObject prefab = PrefabManager.Instance.GetPrefab("vfx_Place_throne02");
				if ((Object)(object)prefab != (Object)null)
				{
					ParticleSystem[] componentsInChildren = prefab.GetComponentsInChildren<ParticleSystem>();
					ParticleSystem[] array = componentsInChildren;
					foreach (ParticleSystem val3 in array)
					{
						GameObject val4 = Object.Instantiate<GameObject>(((Component)val3).gameObject, obj.transform);
						val4.transform.localPosition = Vector3.zero;
						val4.transform.localScale = Vector3.one * 0.3f;
					}
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not add particle VFX: " + ex.Message));
			}
			try
			{
				CreateEtherealParticles(obj);
			}
			catch (Exception ex2)
			{
				Log.LogWarning((object)("Could not add ethereal particles: " + ex2.Message));
			}
		}

		private void CreateEtherealParticles(GameObject parent)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: 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_0114: Expected O, but got Unknown
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Expected O, but got Unknown
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject val = new GameObject("EtherealParticles");
				val.transform.SetParent(parent.transform);
				val.transform.localPosition = new Vector3(0f, 0.3f, 0f);
				ParticleSystem val2 = val.AddComponent<ParticleSystem>();
				MainModule main = val2.main;
				((MainModule)(ref main)).loop = true;
				((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(2f);
				((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(0.5f);
				((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.1f);
				((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.7f, 0.85f, 1f, 0.6f));
				((MainModule)(ref main)).maxParticles = 30;
				((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1;
				EmissionModule emission = val2.emission;
				((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(5f);
				ShapeModule shape = val2.shape;
				((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)0;
				((ShapeModule)(ref shape)).radius = 0.3f;
				ColorOverLifetimeModule colorOverLifetime = val2.colorOverLifetime;
				((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true;
				Gradient val3 = new Gradient();
				val3.SetKeys((GradientColorKey[])(object)new GradientColorKey[2]
				{
					new GradientColorKey(new Color(0.7f, 0.85f, 1f), 0f),
					new GradientColorKey(new Color(0.9f, 0.95f, 1f), 1f)
				}, (GradientAlphaKey[])(object)new GradientAlphaKey[3]
				{
					new GradientAlphaKey(0f, 0f),
					new GradientAlphaKey(0.6f, 0.3f),
					new GradientAlphaKey(0f, 1f)
				});
				((ColorOverLifetimeModule)(ref colorOverLifetime)).color = MinMaxGradient.op_Implicit(val3);
				ParticleSystemRenderer component = val.GetComponent<ParticleSystemRenderer>();
				if ((Object)(object)component != (Object)null)
				{
					Shader val4 = Shader.Find("Particles/Standard Unlit");
					if ((Object)(object)val4 == (Object)null)
					{
						val4 = Shader.Find("Legacy Shaders/Particles/Additive");
					}
					if ((Object)(object)val4 == (Object)null)
					{
						val4 = Shader.Find("Sprites/Default");
					}
					if ((Object)(object)val4 == (Object)null)
					{
						val4 = Shader.Find("Standard");
					}
					if ((Object)(object)val4 != (Object)null)
					{
						((Renderer)component).material = new Material(val4);
						((Renderer)component).material.color = new Color(0.7f, 0.85f, 1f, 0.6f);
					}
					else
					{
						Log.LogWarning((object)"Could not find any particle shader, particles may not render correctly");
					}
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not create ethereal particles: " + ex.Message));
			}
		}

		private void CreateGhostPhantomPrefab()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			GameObject prefab = PrefabManager.Instance.GetPrefab("Player");
			if ((Object)(object)prefab == (Object)null)
			{
				Log.LogWarning((object)"Could not find Player prefab for ghost phantom");
				return;
			}
			GhostPhantomPrefab = new GameObject("VikingGhostPhantom");
			GhostPhantomPrefab.AddComponent<GhostPhantom>();
			PrefabManager.Instance.AddPrefab(GhostPhantomPrefab);
		}

		private void CreateMessageGlyphItem()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			Log.LogInfo((object)"Creating Message Glyph item...");
			ItemConfig val = new ItemConfig();
			val.Name = "Message Glyph";
			val.Description = "Allows vikings to put a special message.\n\nPlace a mystical stone message for other travelers to discover.";
			val.CraftingStation = "";
			val.RepairStation = null;
			val.MinStationLevel = 0;
			val.Amount = 1;
			val.Requirements = (RequirementConfig[])(object)new RequirementConfig[1]
			{
				new RequirementConfig
				{
					Item = "Stone",
					Amount = 10,
					AmountPerLevel = 0,
					Recover = false
				}
			};
			ItemConfig val2 = val;
			Log.LogInfo((object)"Item config created, creating CustomItem...");
			CustomItem val3 = new CustomItem("MessageGlyph", "Stone", val2);
			ManualLogSource log = Log;
			object obj;
			if (val3 == null)
			{
				obj = null;
			}
			else
			{
				GameObject itemPrefab = val3.ItemPrefab;
				obj = ((itemPrefab != null) ? ((Object)itemPrefab).name : null);
			}
			if (obj == null)
			{
				obj = "null";
			}
			log.LogInfo((object)("CustomItem created: " + (string?)obj));
			ItemDrop itemDrop = val3.ItemDrop;
			if ((Object)(object)itemDrop != (Object)null)
			{
				Log.LogInfo((object)"Modifying ItemDrop...");
				SharedData shared = itemDrop.m_itemData.m_shared;
				shared.m_name = "Message Glyph";
				shared.m_description = "Allows vikings to put a special message.\n\nPlace a mystical stone message for other travelers to discover.";
				shared.m_weight = 0.1f;
				shared.m_teleportable = true;
				shared.m_itemType = (ItemType)2;
				shared.m_consumeStatusEffect = null;
				shared.m_maxStackSize = 50;
				Log.LogInfo((object)$"ItemDrop modified - Name: {shared.m_name}, Type: {shared.m_itemType}");
			}
			else
			{
				Log.LogWarning((object)"ItemDrop is null!");
			}
			if ((Object)(object)val3.ItemPrefab != (Object)null)
			{
				val3.ItemPrefab.AddComponent<MessageGlyphItem>();
				Log.LogInfo((object)"Added MessageGlyphItem component");
			}
			ItemManager.Instance.AddItem(val3);
			Log.LogInfo((object)"Item added to ItemManager: MessageGlyph");
		}
	}
	public class GlowPulse : MonoBehaviour
	{
		private Light _light;

		private float _baseIntensity;

		private float _pulseSpeed = 1.5f;

		private float _pulseAmount = 0.5f;

		private void Start()
		{
			_light = ((Component)this).GetComponent<Light>();
			if ((Object)(object)_light != (Object)null)
			{
				_baseIntensity = _light.intensity;
			}
		}

		private void Update()
		{
			if ((Object)(object)_light != (Object)null)
			{
				float num = Mathf.Sin(Time.time * _pulseSpeed) * _pulseAmount;
				_light.intensity = _baseIntensity + num;
			}
		}
	}
}