The current BepInExPack is broken due to the Oakveil update, and mods installed through a mod manager may not work. Join the modding Discord for more information.
Decompiled source of Protector v0.1.10
Protector.dll
Decompiled 10 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using BepInEx.Unity.IL2CPP.Utils.Collections; using HarmonyLib; using Il2CppSystem.Collections.Generic; using Microsoft.CodeAnalysis; using ProjectM; using ProjectM.Network; using ProjectM.Physics; using ProjectM.Scripting; using Protector.Helpers; using Protector.Services; using Steamworks; using Stunlock.Network; using Unity.Collections; using Unity.Entities; using UnityEngine; using VampireCommandFramework; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("Protector")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Whitelist mod")] [assembly: AssemblyFileVersion("0.1.10.0")] [assembly: AssemblyInformationalVersion("0.1.10+1.Branch.main.Sha.c33d0879382e1a0da34861ec55914ba7e637a80e.a440a4ae0990915c07065d07636f6c38d1fd8a93")] [assembly: AssemblyProduct("Protector")] [assembly: AssemblyTitle("Protector")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.10.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.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; } } [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 Protector { internal static class Core { public static GateKeeperService gKs; private static bool hasInitialized; public static World Server { get; } = GetWorld("Server") ?? throw new Exception("There is no Server world (yet)..."); public static EntityManager EntityManager { get; } = Server.EntityManager; public static ServerScriptMapper ServerScriptMapper { get; internal set; } public static ServerGameManager ServerGameManager => ServerScriptMapper.GetServerGameManager(); public static PrefabCollectionSystem PrefabCollectionSystem { get; internal set; } public static ManualLogSource Log => Plugin.LogInstance; public static void Initialize() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown if (!hasInitialized) { Whitelist.Config(Plugin.GateKeeperWhitelistFile.Value); ServerScriptMapper = Server.GetExistingSystemManaged<ServerScriptMapper>(); PrefabCollectionSystem = Server.GetExistingSystemManaged<PrefabCollectionSystem>(); CommandRegistry.RegisterAll(); ManualLogSource log = Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(20, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("Protector"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("["); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("0.1.10"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] core initialized!"); } log.LogInfo(val); gKs = new GateKeeperService(); hasInitialized = true; } } private static World GetWorld(string name) { Enumerator<World> enumerator = World.s_AllWorlds.GetEnumerator(); while (enumerator.MoveNext()) { World current = enumerator.Current; if (current.Name == name) { return current; } } return null; } internal static bool IsUserEnabled(ulong m_SteamID) { return gKs.IsUserEnabled(m_SteamID); } } [BepInPlugin("Protector", "Protector", "0.1.10")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BasePlugin { private Harmony _harmony; public static readonly string RootConfigPath = Path.Combine(Paths.ConfigPath, "Protector"); public static ConfigEntry<bool> GateKeeperKickPlayer; public static ConfigEntry<bool> GateKeeperFileWatcherEnabled; public static ConfigEntry<int> GateKeeperUpdateInterval; public static ConfigEntry<bool> GateKeeperUpdateEnabled; public static ConfigEntry<string> GateKeeperWhitelistFile; internal static Plugin Instance { get; private set; } public static ManualLogSource LogInstance => ((BasePlugin)Instance).Log; public override void Load() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown Instance = this; ManualLogSource log = ((BasePlugin)this).Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(28, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Plugin "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("Protector"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" version "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("0.1.10"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" is loading!"); } log.LogInfo(val); InitConfig(); _harmony = new Harmony("Protector"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); CommandRegistry.RegisterAll(); ManualLogSource log2 = ((BasePlugin)this).Log; val = new BepInExInfoLogInterpolatedStringHandler(27, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Plugin "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("Protector"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" version "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("0.1.10"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" is loaded!"); } log2.LogInfo(val); } private static void InitConfig() { CreateDirectories(RootConfigPath); GateKeeperFileWatcherEnabled = InitConfigEntry("Config", "GateKeeperFileWatcherEnabled", defaultValue: true, "Enable or disable hot monitor of configuration file."); GateKeeperUpdateInterval = InitConfigEntry("Config", "GateKeeperUpdateInterval", 9999, "Delay for background processor in minutes."); GateKeeperUpdateEnabled = InitConfigEntry("Config", "GateKeeperUpdateEnabled", defaultValue: false, "Enable background processor."); GateKeeperKickPlayer = InitConfigEntry("Config", "GateKeeperKickPlayer", defaultValue: true, "Enable kick for not whitelisted players."); GateKeeperWhitelistFile = InitConfigEntry("Config", "GateKeeperWhitelistFile", Path.Combine(RootConfigPath, "WhiteList.txt"), "Path to the WhiteList file."); } 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)Instance).Config.Bind<T>(section, key, defaultValue, description); string text = Path.Combine(Paths.ConfigPath, "Protector.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; } public override bool Unload() { CommandRegistry.UnregisterAssembly(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } return true; } private static void CreateDirectories(string path) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown bool flag = default(bool); if (!Directory.Exists(path)) { ManualLogSource logInstance = LogInstance; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(49, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("No configuration folder found at ["); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(path); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("], creating it."); } logInstance.LogWarning(val); Directory.CreateDirectory(path); } else { ManualLogSource logInstance2 = LogInstance; BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(33, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Configuration folder found at ["); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(path); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("]."); } logInstance2.LogInfo(val2); } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "Protector"; public const string PLUGIN_NAME = "Protector"; public const string PLUGIN_VERSION = "0.1.10"; } } namespace Protector.Services { internal class GateKeeperService { private List<ulong> OldWhitelisted; private FileSystemWatcher fileWatcher; private readonly IgnorePhysicsDebugSystem tokenMonoBehaviour; public const int MAX_REPLY_LENGTH = 509; private List<ulong> Whitelisted { get; set; } public static ManualLogSource Log => Plugin.LogInstance; public GateKeeperService() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown LoadLists(); tokenMonoBehaviour = new GameObject("GateKeeperService").AddComponent<IgnorePhysicsDebugSystem>(); bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val; if (Plugin.GateKeeperUpdateEnabled.Value) { ((MonoBehaviour)tokenMonoBehaviour).StartCoroutine(CollectionExtensions.WrapToIl2Cpp(UpdateLoop())); ManualLogSource log = Log; val = new BepInExInfoLogInterpolatedStringHandler(37, 0, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("GateKeeper background updater started"); } log.LogInfo(val); } if (Plugin.GateKeeperFileWatcherEnabled.Value) { initializeFileWatcher(); ManualLogSource log2 = Log; val = new BepInExInfoLogInterpolatedStringHandler(41, 0, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("GateKeeper background filewatcher started"); } log2.LogInfo(val); } ((MonoBehaviour)tokenMonoBehaviour).StartCoroutine(CollectionExtensions.WrapToIl2Cpp(KickLoop())); ManualLogSource log3 = Log; val = new BepInExInfoLogInterpolatedStringHandler(47, 0, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("GateKeeper background Whitelist monitor started"); } log3.LogInfo(val); } private IEnumerator UpdateLoop() { WaitForSeconds waitForSeconds = new WaitForSeconds((float)(Plugin.GateKeeperUpdateInterval.Value * 60)); while (true) { yield return waitForSeconds; MarkForReload(); } } private IEnumerator KickLoop() { while (true) { if (Whitelist.NeedsReload) { Whitelist.NeedsReload = false; object[] array = Whitelist.Read(); Whitelisted = (List<ulong>)array[0]; OldWhitelisted = (List<ulong>)array[1]; KickUsers(OldWhitelisted); } yield return 0; } } public static void KickUsers(List<ulong> oldWhitelisted) { //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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_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_004a: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.GateKeeperKickPlayer.Value || oldWhitelisted == null || oldWhitelisted.Count == 0) { return; } EntityManager entityManager = Core.Server.EntityManager; EntityQuery val = ((EntityManager)(ref entityManager)).CreateEntityQuery((ComponentType[])(object)new ComponentType[1] { ComponentType.ReadOnly<User>() }); NativeArray<Entity> val2 = ((EntityQuery)(ref val)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2)); foreach (ulong item in oldWhitelisted) { if (Whitelist.Get().Contains(item)) { continue; } Enumerator<Entity> enumerator2 = val2.GetEnumerator(); while (enumerator2.MoveNext()) { Entity current2 = enumerator2.Current; User componentData = ((EntityManager)(ref entityManager)).GetComponentData<User>(current2); if (componentData.PlatformId == item && componentData.IsConnected) { KickUser(item); } } } } public void LoadLists() { object[] array = Whitelist.Read(); Whitelisted = (List<ulong>)array[0]; OldWhitelisted = (List<ulong>)array[1]; } public bool IsUserEnabled(ulong playerId) { if (Whitelisted.Contains(playerId)) { return true; } return false; } private static void KickUser(ulong playerId) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown Core.Server.GetExistingSystemManaged<ServerBootstrapSystem>().Kick(playerId, (ConnectionStatusChangeReason)19, true); ManualLogSource log = Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(56, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("["); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ulong>(playerId); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] was kicked because it was removed from the whitelist."); } log.LogInfo(val); } private void initializeFileWatcher() { fileWatcher = new FileSystemWatcher(Path.GetDirectoryName(Plugin.GateKeeperWhitelistFile.Value)) { NotifyFilter = NotifyFilters.LastWrite, Filter = Path.GetFileName(Plugin.GateKeeperWhitelistFile.Value) }; fileWatcher.Changed += delegate { MarkForReload(); }; fileWatcher.EnableRaisingEvents = true; } public List<ulong> getWhitelisted() { return new List<ulong>(Whitelisted); } public void MarkForReload() { Whitelist.NeedsReload = true; } } } namespace Protector.Patches { [HarmonyPatch(typeof(SpawnTeamSystem_OnPersistenceLoad), "OnUpdate")] public static class InitializationPatch { [HarmonyPostfix] public static void OnUpdatePostfix() { Core.Initialize(); } } [HarmonyPatch(typeof(SteamGameServer))] public class SteamGameServerPatches { [HarmonyPostfix] [HarmonyPatch("BeginAuthSession")] public static void BeginAuthSession(object[] __args, ref object __result) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: 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_0062: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) CSteamID val = (CSteamID)__args[2]; bool flag = default(bool); if (Core.IsUserEnabled(val.m_SteamID)) { ManualLogSource log = GateKeeperService.Log; BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(45, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("FOUND IN WHITELISTED:["); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<ulong>(val.m_SteamID); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("] was allowed to login."); } log.LogInfo(val2); return; } ManualLogSource log2 = GateKeeperService.Log; BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(51, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("NOT FOUND IN WHITELISTED:["); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<ulong>(val.m_SteamID); ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("] was prevented to login."); } log2.LogWarning(val3); __result = (object)(EBeginAuthSessionResult)1; } } } namespace Protector.Helpers { public static class Whitelist { private static List<ulong> Whitelisted; private static string confFile; public static ManualLogSource Log => Plugin.LogInstance; public static bool NeedsReload { get; internal set; } public static bool Exists() { return File.Exists(confFile); } public static void Config(string configurationFile) { confFile = configurationFile; } public static void Initialize() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("#"); stringBuilder.AppendLine("# Edit this file to add or remove player from the whitelist."); stringBuilder.AppendLine("#"); stringBuilder.AppendLine("# If you have enabled HotReload in configuration file, it'll be automatically reloaded"); stringBuilder.AppendLine("# without needing server restart. And if you use KickPlayer option, removed SteamID will"); stringBuilder.AppendLine("# be automatically kicked out the server if connected."); stringBuilder.AppendLine("#"); stringBuilder.AppendLine("# You can use comments in this file with # character, but be aware, you cannot put a"); stringBuilder.AppendLine("# comment on the same line of an SteamID or it'll be skipped by the plugin."); stringBuilder.AppendLine("#"); stringBuilder.AppendLine("# 10101010101010101"); stringBuilder.AppendLine("#"); File.WriteAllText(confFile, stringBuilder.ToString()); } public static object[] Read() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown bool flag = default(bool); if (!Exists()) { ManualLogSource log = Log; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(69, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("No whitelist file found at ["); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(confFile); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("], initializing it with default settings."); } log.LogWarning(val); Initialize(); } List<ulong> whitelisted = Whitelisted; List<ulong> list = ((whitelisted != null && whitelisted.Count > 0) ? Whitelisted : null); Whitelisted = new List<ulong>(); string[] array = WriteSafeReadAllLines(confFile); if (array.Length == 0) { ManualLogSource log2 = Log; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(25, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("There's no SteamIDs in ["); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(confFile); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("]"); } log2.LogWarning(val); return new object[2]; } string[] array2 = array; foreach (string text in array2) { if (!text.StartsWith("#") && !text.Contains("#") && !string.IsNullOrEmpty(text) && ulong.TryParse(text, out var result) && !Whitelisted.Contains(result)) { Whitelisted.Add(result); } } return new object[2] { Whitelisted, list }; } public static string[] WriteSafeReadAllLines(string path) { using FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); using StreamReader streamReader = new StreamReader(stream); List<string> list = new List<string>(); while (!streamReader.EndOfStream) { list.Add(streamReader.ReadLine()); } return list.ToArray(); } public static List<ulong> Get() { return Whitelisted; } } } namespace Protector.Commands { public static class ProtectorCommands { [CommandGroup("Protector", null)] internal class Protector { [Command("list", "l", null, "Returns the list of current whitelisted clients.", null, true)] public static void List(ChatCommandContext ctx) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Whitelisted SteamIDs:"); bool flag = true; foreach (ulong item in Core.gKs.getWhitelisted()) { flag = false; stringBuilder.AppendLine(item.ToString() ?? ""); } if (flag) { stringBuilder.AppendLine("No ids whitelisted"); } ctx.Reply(stringBuilder.ToString()); } [Command("reload", "r", null, "Forces the reload of the whitelist file.", null, true)] public static void Reload(ChatCommandContext ctx) { Core.gKs.MarkForReload(); ctx.Reply("List marked for reload"); } } } }