Decompiled source of CrimsonEcho v1.0.0

CrimsonEcho.dll

Decompiled a month 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.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using CrimsonEcho.Structs;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Microsoft.CodeAnalysis;
using ProjectM;
using ProjectM.Network;
using Stunlock.Core;
using Stunlock.Network;
using Unity.Collections;
using Unity.Entities;
using UnityEngine;
using VAMP;
using VAMP.Attributes;
using VAMP.Data;
using VAMP.Models;
using VAMP.Services;
using VAMP.Systems;
using VAMP.Utilities;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("CrimsonEcho")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Automated Notifications")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+Branch.master.Sha.574e28bd13b4882f513b0ba312a7c8b7c0cec281.574e28bd13b4882f513b0ba312a7c8b7c0cec281")]
[assembly: AssemblyProduct("CrimsonEcho")]
[assembly: AssemblyTitle("CrimsonEcho")]
[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;
		}
	}
}
[HarmonyPatch(typeof(ServerBootstrapSystem), "OnUserConnected")]
public static class OnUserConnectedPatch
{
	public static List<ulong> welcomed = new List<ulong>();

	public static void Postfix(ServerBootstrapSystem __instance, NetConnectionId netConnectionId)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_021f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0224: Unknown result type (might be due to invalid IL or missing references)
		//IL_0228: Unknown result type (might be due to invalid IL or missing references)
		//IL_0200: Unknown result type (might be due to invalid IL or missing references)
		//IL_0425: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_03db: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_024c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0251: Unknown result type (might be due to invalid IL or missing references)
		//IL_0256: 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_0266: Unknown result type (might be due to invalid IL or missing references)
		//IL_026b: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bd: 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_02cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02da: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_035b: Unknown result type (might be due to invalid IL or missing references)
		if (Core.PlayerService == null || !Settings.ToggleMod.Value)
		{
			return;
		}
		try
		{
			EntityManager entityManager = ((ComponentSystemBase)__instance).EntityManager;
			int num = __instance._NetEndPointToApprovedUserIndex[netConnectionId];
			Entity userEntity = ((Il2CppArrayBase<ServerClient>)(object)__instance._ApprovedUsersLookup)[num].UserEntity;
			User componentData = ((EntityManager)(ref entityManager)).GetComponentData<User>(userEntity);
			bool isWhiteListed = true;
			ModTalk.Invoke("CrimsonKey.IsWhitelisted", new object[1] { componentData.PlatformId }, (Action<object>)delegate(object result)
			{
				isWhiteListed = (bool)result;
			});
			if (!isWhiteListed)
			{
				return;
			}
			Player val = PlayerService.PlayerFromUser(componentData);
			welcomed.Remove(componentData.PlatformId);
			if (((FixedString64Bytes)(ref componentData.CharacterName)).IsEmpty)
			{
				return;
			}
			string text = ((object)(FixedString64Bytes)(ref componentData.CharacterName)).ToString();
			if (Database.Messages.First((MessagePair x) => x.Key == "PlayerOnline").IsEnabled() && Settings.TogglePlayerOnline.Value && (!val.IsAdminCapable || !Settings.ShadowAdmin.Value))
			{
				ChatUtil.SystemSendAllExcept(componentData, Database.Messages.First((MessagePair x) => x.Key == "PlayerOnline").ToString(text));
			}
			if (Database.Messages.First((MessagePair x) => x.Key == "MOTD").IsEnabled() && Settings.ToggleMOTD.Value)
			{
				ChatUtil.SystemSendUser(componentData, Database.Messages.First((MessagePair x) => x.Key == "MOTD").ToString());
			}
			if (Database.RandomMessages.Count > 0 && Settings.ToggleRandom.Value)
			{
				string dailyRandom = Database.GetDailyRandom(Database.RandomMessages);
				ChatUtil.SystemSendUser(componentData, dailyRandom.ToString());
			}
			Entity val2;
			if (Settings.ClanPrintout.Value)
			{
				val2 = val.Clan;
				if (!((Entity)(ref val2)).Equals(Entity.Null))
				{
					List<string> list = new List<string>();
					IEnumerable<Player> clanMembersAsPlayers = ClanService.GetClanMembersAsPlayers(val.Clan);
					User clanLeader = GetClanLeader(val.Clan);
					string text2 = "";
					text2 = ((!(EntityUtil.Read<User>(val.User) == clanLeader)) ? (text + ",") : (text + " <color=" + Settings.ClanPrintoutLeaderColor.Value + ">[C]</color>,"));
					foreach (Player item in clanMembersAsPlayers)
					{
						val2 = item.User;
						if (((Entity)(ref val2)).Equals(Entity.Null))
						{
							continue;
						}
						val2 = item.User;
						if (!((Entity)(ref val2)).Equals(val.User))
						{
							if (EntityUtil.Read<User>(item.User) == clanLeader)
							{
								list.Add(((FixedString64Bytes)(ref clanLeader.CharacterName)).Value + " <color=" + Settings.ClanPrintoutLeaderColor.Value + ">[C]</color>");
							}
							else
							{
								list.Add(item.Name);
							}
						}
					}
					if (list.Count >= 1)
					{
						ChatUtil.SystemSendUser(componentData, $"<color={Settings.ClanPrintoutAccentColor.Value}>Clan:</color> {text2} {string.Join(", ", list)}");
					}
				}
			}
			if (Settings.ToggleClanless.Value)
			{
				val2 = val.Clan;
				if (((Entity)(ref val2)).Equals(Entity.Null))
				{
					ChatUtil.SystemSendUser(componentData, Database.Messages.First((MessagePair x) => x.Key == "Clanless").Value);
				}
			}
			welcomed.Add(componentData.PlatformId);
		}
		catch (Exception ex)
		{
			((BasePlugin)Plugin.Instance).Log.LogError((object)ex.Message);
		}
	}

	public static int GetClanLeaderIndex(DynamicBuffer<ClanMemberStatus> clanBuffer)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		for (int i = 0; i < clanBuffer.Length; i++)
		{
			ClanMemberStatus val = clanBuffer[i];
			if (((object)(ClanRoleEnum)(ref val.ClanRole)).Equals((object)(ClanRoleEnum)2))
			{
				return i;
			}
		}
		return -1;
	}

	public static User GetClanLeader(Entity clan)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		int clanLeaderIndex = GetClanLeaderIndex(EntityUtil.ReadBuffer<ClanMemberStatus>(clan));
		return EntityUtil.Read<User>(EntityUtil.ReadBuffer<SyncToUserBuffer>(clan)[clanLeaderIndex].UserEntity);
	}
}
[HarmonyPatch(typeof(ServerBootstrapSystem), "OnUserDisconnected")]
public static class OnUserDisconnectedPatch
{
	private static void Prefix(ServerBootstrapSystem __instance, NetConnectionId netConnectionId, ConnectionStatusChangeReason connectionStatusReason, string extraData)
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		if (Core.PlayerService == null)
		{
			Core.Initialize();
		}
		if (!Settings.ToggleMod.Value)
		{
			return;
		}
		try
		{
			int num = __instance._NetEndPointToApprovedUserIndex[netConnectionId];
			ServerClient val = ((Il2CppArrayBase<ServerClient>)(object)__instance._ApprovedUsersLookup)[num];
			EntityManager entityManager = ((ComponentSystemBase)__instance).EntityManager;
			User componentData = ((EntityManager)(ref entityManager)).GetComponentData<User>(val.UserEntity);
			Player val2 = PlayerService.PlayerFromUser(componentData);
			if (!((FixedString64Bytes)(ref componentData.CharacterName)).IsEmpty)
			{
				string text = ((object)(FixedString64Bytes)(ref componentData.CharacterName)).ToString();
				if (Database.Messages.First((MessagePair x) => x.Key == "PlayerOffline").IsEnabled() && Settings.TogglePlayerOffline.Value && (!val2.IsAdminCapable || !Settings.ShadowAdmin.Value))
				{
					ChatUtil.SystemSendAll(Database.Messages.First((MessagePair x) => x.Key == "PlayerOffline").ToString(text));
				}
			}
			OnUserConnectedPatch.welcomed.Remove(componentData.PlatformId);
		}
		catch
		{
		}
	}
}
[HarmonyPatch(typeof(Destroy_TravelBuffSystem), "OnUpdate")]
public class Destroy_TravelBuffSystem_Patch
{
	private static void Postfix(Destroy_TravelBuffSystem __instance)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: 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_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: 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_0063: 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_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: 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_029b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0224: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0288: Unknown result type (might be due to invalid IL or missing references)
		if (Core.PlayerService == null || !Settings.ToggleMod.Value)
		{
			return;
		}
		EntityQuery _query_615927226_ = __instance.__query_615927226_0;
		Enumerator<Entity> enumerator = ((EntityQuery)(ref _query_615927226_)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2)).GetEnumerator();
		while (enumerator.MoveNext())
		{
			Entity current = enumerator.Current;
			EntityManager entityManager = ((ComponentSystemBase)__instance).EntityManager;
			PrefabGUID componentData = ((EntityManager)(ref entityManager)).GetComponentData<PrefabGUID>(current);
			if (!((PrefabGUID)(ref componentData)).Equals(Prefabs.AB_Interact_TombCoffinSpawn_Travel))
			{
				continue;
			}
			entityManager = ((ComponentSystemBase)__instance).EntityManager;
			Entity owner = ((EntityManager)(ref entityManager)).GetComponentData<EntityOwner>(current).Owner;
			entityManager = ((ComponentSystemBase)__instance).EntityManager;
			if (!((EntityManager)(ref entityManager)).HasComponent<PlayerCharacter>(owner))
			{
				continue;
			}
			entityManager = ((ComponentSystemBase)__instance).EntityManager;
			Entity userEntity = ((EntityManager)(ref entityManager)).GetComponentData<PlayerCharacter>(owner).UserEntity;
			entityManager = ((ComponentSystemBase)__instance).EntityManager;
			User componentData2 = ((EntityManager)(ref entityManager)).GetComponentData<User>(userEntity);
			if (OnUserConnectedPatch.welcomed.Contains(componentData2.PlatformId))
			{
				continue;
			}
			Player val = PlayerService.PlayerFromUser(componentData2);
			if (Database.Messages.First((MessagePair x) => x.Key == "NewPlayerWelcome").IsEnabled() && Settings.ToggleNewPlayerWelcome.Value)
			{
				ChatUtil.SystemSendUser(componentData2, Database.Messages.First((MessagePair x) => x.Key == "NewPlayerWelcome").ToString(componentData2));
			}
			if (Database.Messages.First((MessagePair x) => x.Key == "NewPlayerAnnounce").IsEnabled() && Settings.ToggleNewPlayerAnnounce.Value && (!val.IsAdminCapable || !Settings.ShadowAdmin.Value))
			{
				ChatUtil.SystemSendAllExcept(componentData2, Database.Messages.First((MessagePair x) => x.Key == "NewPlayerAnnounce").ToString(componentData2));
			}
			if (Database.Messages.First((MessagePair x) => x.Key == "NewPlayerMOTD").IsEnabled() && Settings.ToggleNewPlayerMOTD.Value)
			{
				ChatUtil.SystemSendUser(componentData2, Database.Messages.First((MessagePair x) => x.Key == "NewPlayerMOTD").ToString());
			}
			if (Database.RandomMessages.Count > 0 && Settings.ToggleNewPlayerRandom.Value)
			{
				string dailyRandom = Database.GetDailyRandom(Database.RandomMessages);
				ChatUtil.SystemSendUser(componentData2, dailyRandom.ToString());
			}
			OnUserConnectedPatch.welcomed.Add(componentData2.PlatformId);
		}
	}
}
public struct MessagePair
{
	public string Key { get; set; }

	public string Value { get; set; }

	public MessagePair(string key, string value)
	{
		Key = key;
		Value = value;
	}

	public bool IsEnabled()
	{
		if (string.IsNullOrEmpty(Value))
		{
			return false;
		}
		return true;
	}

	public override string ToString()
	{
		return Value;
	}

	public string ToString(string userName)
	{
		return Value.Replace("{player}", userName);
	}

	public string ToString(User user)
	{
		return ToString(((FixedString64Bytes)(ref user.CharacterName)).Value);
	}

	public string ToString(Player player, PrefabGUID vblood)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		return Value.Replace("{vblood.long}", VBloods.ToString(vblood)).Replace("{vblood.short}", VBloods.ToShortString(vblood)).Replace("{vblood}", ((object)(PrefabGUID)(ref vblood)).ToString())
			.Replace("{player}", player.Name);
	}
}
namespace CrimsonEcho
{
	[BepInPlugin("CrimsonEcho", "CrimsonEcho", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BasePlugin
	{
		private Harmony _harmony;

		public static Plugin Instance { get; private set; }

		public static Harmony Harmony => Instance._harmony;

		public static ManualLogSource LogInstance => ((BasePlugin)Instance).Log;

		public static Settings Settings { get; private set; }

		public static string ConfigFiles => Path.Combine(Paths.ConfigPath, "CrimsonEcho");

		public Database Database { get; private set; }

		public override void Load()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			Instance = this;
			Settings = default(Settings);
			Settings.InitConfig();
			_harmony = new Harmony("CrimsonEcho");
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			Events.OnCoreLoaded = (Action)Delegate.Combine(Events.OnCoreLoaded, new Action(Loaded));
		}

		public void Loaded()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			Database = new Database();
			ManualLogSource log = ((BasePlugin)this).Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(27, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Plugin ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CrimsonEcho");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" version ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.0.0");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" is loaded!");
			}
			log.LogInfo(val);
			Core.StartCoroutine(AutoMessageLoop());
		}

		private IEnumerator AutoMessageLoop()
		{
			int loopsForAutoMessage = 0;
			while (true)
			{
				yield return (object)new WaitForSeconds(60f);
				loopsForAutoMessage++;
				if (loopsForAutoMessage % Settings.AutoMessageInterval.Value == 0 && Database.AutoMessages.Count > 0)
				{
					Database.SendAutoMessage();
					loopsForAutoMessage = 0;
				}
				if (Database.Announcements == null || Database.Announcements.Count <= 0)
				{
					continue;
				}
				DateTime dateTime = (Settings.TimesInUTC.Value ? DateTime.UtcNow : DateTime.Now);
				List<Announcement> list = new List<Announcement>();
				foreach (Announcement announcement in Database.Announcements)
				{
					if ((!announcement.DayOfWeek.HasValue || announcement.DayOfWeek == dateTime.DayOfWeek) && announcement.Time.Hour == dateTime.Hour && announcement.Time.Minute == dateTime.Minute)
					{
						ChatUtil.SystemSendAll(announcement.Message);
						if (announcement.OneTime)
						{
							list.Add(announcement);
						}
					}
				}
				if (list.Count <= 0)
				{
					continue;
				}
				foreach (Announcement item in list)
				{
					Database.Announcements.Remove(item);
				}
				Database.SaveAnnouncements();
			}
		}

		public override bool Unload()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			return true;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "CrimsonEcho";

		public const string PLUGIN_NAME = "CrimsonEcho";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace CrimsonEcho.Structs
{
	public struct Announcement
	{
		public string Message { get; set; }

		public DayOfWeek? DayOfWeek { get; set; }

		public TimeOnly Time { get; set; }

		public bool OneTime { get; set; }

		public Announcement(string message, DayOfWeek? day, TimeOnly time, bool oneTime)
		{
			Message = message;
			DayOfWeek = day;
			Time = time;
			OneTime = oneTime;
		}

		public override string ToString()
		{
			return Message;
		}
	}
	public class AnnouncementConverter : JsonConverter<Announcement>
	{
		private const string TimeFormat = "HH:mm";

		public override Announcement Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			if (reader.TokenType != JsonTokenType.StartObject)
			{
				throw new JsonException("Expected start of object");
			}
			string message = string.Empty;
			DayOfWeek? day = null;
			TimeOnly time = new TimeOnly(0, 0);
			bool oneTime = false;
			while (reader.Read())
			{
				if (reader.TokenType == JsonTokenType.EndObject)
				{
					return new Announcement(message, day, time, oneTime);
				}
				if (reader.TokenType != JsonTokenType.PropertyName)
				{
					throw new JsonException("Expected property name");
				}
				string @string = reader.GetString();
				reader.Read();
				switch (@string)
				{
				case "Message":
					message = reader.GetString();
					break;
				case "DayOfWeek":
				{
					if (reader.TokenType == JsonTokenType.Null)
					{
						day = null;
						break;
					}
					string string3 = reader.GetString();
					DayOfWeek result;
					if (string.IsNullOrEmpty(string3) || string3.Equals("Daily", StringComparison.OrdinalIgnoreCase))
					{
						day = null;
					}
					else if (Enum.TryParse<DayOfWeek>(string3, ignoreCase: true, out result))
					{
						day = result;
					}
					break;
				}
				case "Time":
				{
					string string2 = reader.GetString();
					try
					{
						time = TimeOnly.ParseExact(string2 ?? "00:00", "HH:mm");
					}
					catch
					{
						time = TimeOnly.Parse(string2 ?? "00:00");
					}
					break;
				}
				case "OneTime":
					oneTime = reader.GetBoolean();
					break;
				}
			}
			throw new JsonException("Expected end of object");
		}

		public override void Write(Utf8JsonWriter writer, Announcement value, JsonSerializerOptions options)
		{
			writer.WriteStartObject();
			writer.WritePropertyName("Message");
			writer.WriteStringValue(value.Message);
			writer.WritePropertyName("DayOfWeek");
			if (value.DayOfWeek.HasValue)
			{
				writer.WriteStringValue(value.DayOfWeek.Value.ToString());
			}
			else
			{
				writer.WriteStringValue("Daily");
			}
			writer.WritePropertyName("Time");
			writer.WriteStringValue(value.Time.ToString("HH:mm"));
			writer.WritePropertyName("OneTime");
			writer.WriteBooleanValue(value.OneTime);
			writer.WriteEndObject();
		}
	}
	public class AutoMessage
	{
		public string Content { get; set; }

		[JsonPropertyName("isFirst")]
		[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
		public bool IsFirst { get; set; }

		public AutoMessage()
		{
		}

		public AutoMessage(string content, bool isFirst = false)
		{
			Content = content;
			IsFirst = isFirst;
		}

		public override string ToString()
		{
			return Content;
		}
	}
	public class Database
	{
		public static readonly JsonSerializerOptions prettyJsonOptions = new JsonSerializerOptions
		{
			WriteIndented = true,
			IncludeFields = true,
			AllowTrailingCommas = true,
			ReadCommentHandling = JsonCommentHandling.Skip,
			Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
			Converters = { (JsonConverter)new AnnouncementConverter() }
		};

		[FileReload("MessagesLoad")]
		public static string MessageFile = Path.Combine(Plugin.ConfigFiles, "messages.json");

		[FileReload("AutoMessageLoad")]
		public static string AutoMessageFile = Path.Combine(Plugin.ConfigFiles, "auto_messages.json");

		[FileReload("RandomMessageLoad")]
		public static string RandomFile = Path.Combine(Plugin.ConfigFiles, "daily_randoms.json");

		[FileReload("AnnouncementLoad")]
		public static string AnnouncementFile = Path.Combine(Plugin.ConfigFiles, "announcements.json");

		public static List<MessagePair> Messages;

		public static List<string> RandomMessages;

		public static List<AutoMessage> AutoMessages;

		public static List<Announcement> Announcements;

		private static int lastSentAuto = 0;

		public Database()
		{
			LoadDatabase();
		}

		private static void LoadDatabase()
		{
			if (!Directory.Exists(Plugin.ConfigFiles))
			{
				Directory.CreateDirectory(Plugin.ConfigFiles);
			}
			MessagesLoad();
			RandomMessageLoad();
			AutoMessageLoad();
			AnnouncementLoad();
		}

		private static void MessagesLoad()
		{
			try
			{
				List<MessagePair> defaultMessages = GetDefaultMessages();
				if (File.Exists(MessageFile))
				{
					string json = File.ReadAllText(MessageFile, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
					List<MessagePair> list = JsonSerializer.Deserialize<List<MessagePair>>(json, prettyJsonOptions);
					bool flag = false;
					foreach (MessagePair defaultMsg in defaultMessages)
					{
						if (!list.Any((MessagePair m) => m.Key == defaultMsg.Key))
						{
							list.Add(defaultMsg);
							flag = true;
						}
					}
					Messages = list;
					if (flag)
					{
						json = JsonSerializer.Serialize(Messages, prettyJsonOptions);
						File.WriteAllText(MessageFile, json, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
					}
				}
				else
				{
					Messages = defaultMessages;
					string contents = JsonSerializer.Serialize(Messages, prettyJsonOptions);
					File.WriteAllText(MessageFile, contents, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
				}
			}
			catch
			{
				Messages = (from m in GetDefaultMessages()
					select new MessagePair(m.Key, "")).ToList();
				Plugin.LogInstance.LogInfo((object)"Messages not loaded.");
			}
		}

		private static List<MessagePair> GetDefaultMessages()
		{
			return new List<MessagePair>(7)
			{
				new MessagePair("PlayerOnline", "{player} is now online."),
				new MessagePair("PlayerOffline", "{player} is now offline."),
				new MessagePair("NewPlayerWelcome", "Welcome to the server {player}!"),
				new MessagePair("NewPlayerAnnounce", "{player} has joined the server for the first time. Say hello!"),
				new MessagePair("NewPlayerMOTD", ""),
				new MessagePair("MOTD", ""),
				new MessagePair("Clanless", "Consider joining a clan!")
			};
		}

		private static void RandomMessageLoad()
		{
			try
			{
				if (File.Exists(RandomFile))
				{
					RandomMessages = JsonSerializer.Deserialize<List<string>>(File.ReadAllText(RandomFile, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)), prettyJsonOptions);
					return;
				}
				RandomMessages = new List<string>(3) { "Dracula's Generals laugh at your attempts.", "But can you pet the Winged Horror?", "Who can be trusted when all creatures of the night are ready to siege?" };
				string contents = JsonSerializer.Serialize(RandomMessages, prettyJsonOptions);
				File.WriteAllText(RandomFile, contents, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
			}
			catch
			{
				RandomMessages = new List<string>();
				Plugin.LogInstance.LogInfo((object)"Random messages not loaded.");
			}
		}

		private static void AnnouncementLoad()
		{
			try
			{
				if (File.Exists(AnnouncementFile))
				{
					Announcements = JsonSerializer.Deserialize<List<Announcement>>(File.ReadAllText(AnnouncementFile, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)), prettyJsonOptions);
					return;
				}
				Announcements = new List<Announcement>(2)
				{
					new Announcement("Brought to you by CrimsonMods", null, new TimeOnly(12, 0), oneTime: false),
					new Announcement("It's Wednesday!", DayOfWeek.Wednesday, new TimeOnly(17, 0), oneTime: false)
				};
				SaveAnnouncements();
			}
			catch (Exception ex)
			{
				Announcements = new List<Announcement>();
				Plugin.LogInstance.LogInfo((object)"Announcements not loaded.");
				Plugin.LogInstance.LogInfo((object)ex.ToString());
			}
		}

		private static void AutoMessageLoad()
		{
			try
			{
				if (File.Exists(AutoMessageFile))
				{
					AutoMessages = JsonSerializer.Deserialize<List<AutoMessage>>(File.ReadAllText(AutoMessageFile, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)), prettyJsonOptions);
					lastSentAuto = 0;
					return;
				}
				AutoMessages = new List<AutoMessage>(2)
				{
					new AutoMessage("Join our discord for more information!", isFirst: true),
					new AutoMessage("VAMP Powered Development!")
				};
				string contents = JsonSerializer.Serialize(AutoMessages, prettyJsonOptions);
				File.WriteAllText(AutoMessageFile, contents, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
			}
			catch (Exception ex)
			{
				AutoMessages = new List<AutoMessage>();
				Plugin.LogInstance.LogInfo((object)"Auto messages not loaded.");
				Plugin.LogInstance.LogInfo((object)ex.ToString());
			}
		}

		public static T GetDailyRandom<T>(IList<T> collection)
		{
			if (collection == null || collection.Count == 0)
			{
				return default(T);
			}
			DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
			int index = (int)((DateTime.UtcNow.Date - dateTime).TotalDays % (double)collection.Count);
			return collection[index];
		}

		public static void SendAutoMessage()
		{
			if (AutoMessages.Count == 0)
			{
				return;
			}
			if (lastSentAuto == 0)
			{
				for (int i = 0; i < AutoMessages.Count; i++)
				{
					if (AutoMessages[i].IsFirst)
					{
						lastSentAuto = i;
						break;
					}
				}
			}
			ChatUtil.SystemSendAll(AutoMessages[lastSentAuto].Content);
			lastSentAuto = (lastSentAuto + 1) % AutoMessages.Count;
		}

		public static void SaveAnnouncements()
		{
			string text = "Announcements are intended to be pre-scheduled and will be sent at the time specified." + Environment.NewLine + "The time is based on the server's timezone (24:00 hour clock), but can be switched to UTC in CrimsonEcho.cfg" + Environment.NewLine + "DayOfWeek must be one of the following values: " + Environment.NewLine + "Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, or Daily" + Environment.NewLine + "Setting OneTime to true will automatically remove the announcement from the list after broadcasting to the server." + Environment.NewLine + "Note: Saved changes will take effect immediately, no server restart is required.";
			string contents = JsonUtil.SerializeWithComments<List<Announcement>>(Announcements, text, prettyJsonOptions);
			File.WriteAllText(AnnouncementFile, contents, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
		}
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public readonly struct Settings
	{
		private static readonly List<string> OrderedSections = new List<string> { "Toggles", "Onboarding", "Customization" };

		public static ConfigEntry<bool> ToggleMod { get; private set; }

		public static ConfigEntry<bool> TimesInUTC { get; private set; }

		public static ConfigEntry<bool> TogglePlayerOnline { get; private set; }

		public static ConfigEntry<bool> TogglePlayerOffline { get; private set; }

		public static ConfigEntry<bool> ToggleMOTD { get; private set; }

		public static ConfigEntry<bool> ToggleRandom { get; private set; }

		public static ConfigEntry<bool> ToggleClanless { get; private set; }

		public static ConfigEntry<bool> ToggleNewPlayerWelcome { get; private set; }

		public static ConfigEntry<bool> ToggleNewPlayerAnnounce { get; private set; }

		public static ConfigEntry<bool> ToggleNewPlayerMOTD { get; private set; }

		public static ConfigEntry<bool> ToggleNewPlayerRandom { get; private set; }

		public static ConfigEntry<int> AutoMessageInterval { get; private set; }

		public static ConfigEntry<bool> ShadowAdmin { get; private set; }

		public static ConfigEntry<bool> ClanPrintout { get; private set; }

		public static ConfigEntry<string> ClanPrintoutAccentColor { get; private set; }

		public static ConfigEntry<string> ClanPrintoutLeaderColor { get; private set; }

		public static void InitConfig()
		{
			ToggleMod = InitConfigEntry(OrderedSections[0], "Toggle", defaultValue: true, "If true the mod will be usable; otherwise it will be disabled.");
			TogglePlayerOnline = InitConfigEntry(OrderedSections[0], "TogglePlayerOnline", defaultValue: true, "If true, the player online message will be shown.");
			TogglePlayerOffline = InitConfigEntry(OrderedSections[0], "TogglePlayerOffline", defaultValue: true, "If true, the player offline message will be shown.");
			ToggleMOTD = InitConfigEntry(OrderedSections[0], "ToggleMOTD", defaultValue: true, "If true, the MOTD message will be shown.");
			ToggleRandom = InitConfigEntry(OrderedSections[0], "ToggleRandom", defaultValue: true, "If true, the random message will be shown.");
			ClanPrintout = InitConfigEntry(OrderedSections[0], "ToggleClanPrintout", defaultValue: false, "If true, the clan printout message will be shown on connection with list of members.");
			ToggleClanless = InitConfigEntry(OrderedSections[0], "ToggleClanless", defaultValue: false, "If true, the clanless message will be shown.");
			ToggleNewPlayerWelcome = InitConfigEntry(OrderedSections[1], "ToggleNewPlayerWelcome", defaultValue: true, "If true, the new player welcome message will be shown.");
			ToggleNewPlayerAnnounce = InitConfigEntry(OrderedSections[1], "ToggleNewPlayerAnnounce", defaultValue: true, "If true, the new player announce message will be shown.");
			ToggleNewPlayerMOTD = InitConfigEntry(OrderedSections[1], "ToggleNewPlayerMOTD", defaultValue: true, "If true, the new player MOTD message will be shown.");
			ToggleNewPlayerRandom = InitConfigEntry(OrderedSections[1], "ToggleNewPlayerRandom", defaultValue: true, "If true, the random message will be shown for new players.");
			TimesInUTC = InitConfigEntry(OrderedSections[2], "TimesInUTC", defaultValue: false, "If true, times in config files will be read as UTC times instead of the server's local time.");
			AutoMessageInterval = InitConfigEntry(OrderedSections[2], "AutoMessageInterval", 30, "The interval (in minutes) between auto messages.");
			ShadowAdmin = InitConfigEntry(OrderedSections[2], "ShadowAdmins", defaultValue: false, "If true, online/offline broadcast messages will not be sent for admins when they login/logoff.");
			ClanPrintoutAccentColor = InitConfigEntry(OrderedSections[2], "ClanPrintoutAccentColor", "#def", "The hex color value of the clan printout label.");
			ClanPrintoutLeaderColor = InitConfigEntry(OrderedSections[2], "ClanPrintoutLeaderTagColor", "#b7309c", "The hex color value of the clan printout leader tag.");
			ReorderConfigSections();
		}

		private static ConfigEntry<T> InitConfigEntry<T>(string section, string key, T defaultValue, string description)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			ConfigEntry<T> val = ((BasePlugin)Plugin.Instance).Config.Bind<T>(section, key, defaultValue, description);
			string text = Path.Combine(Paths.ConfigPath, "CrimsonEcho.cfg");
			ConfigEntry<T> val2 = default(ConfigEntry<T>);
			if (File.Exists(text) && new ConfigFile(text, true).TryGetEntry<T>(section, key, ref val2))
			{
				val.Value = val2.Value;
			}
			return val;
		}

		private static void ReorderConfigSections()
		{
			string path = Path.Combine(Paths.ConfigPath, "CrimsonEcho.cfg");
			if (!File.Exists(path))
			{
				return;
			}
			List<string> list = File.ReadAllLines(path).ToList();
			Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>();
			string text = "";
			foreach (string item in list)
			{
				if (item.StartsWith("["))
				{
					text = item.Trim('[', ']');
					dictionary[text] = new List<string> { item };
				}
				else if (!string.IsNullOrWhiteSpace(text))
				{
					dictionary[text].Add(item);
				}
			}
			using StreamWriter streamWriter = new StreamWriter(path, append: false);
			foreach (string orderedSection in OrderedSections)
			{
				if (!dictionary.ContainsKey(orderedSection))
				{
					continue;
				}
				foreach (string item2 in dictionary[orderedSection])
				{
					streamWriter.WriteLine(item2);
				}
				streamWriter.WriteLine();
			}
		}
	}
}