Decompiled source of OperatorQueueControl v1.0.0

plugins/OperatorQueueControl/OperatorQueueControl.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates;
using EntityStates.DroneTech.Weapon;
using Microsoft.CodeAnalysis;
using On;
using On.EntityStates.DroneTech.Weapon;
using OperatorQueueControl.Core;
using RoR2;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("OperatorQueueControl")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+e72b8852648bfaa0e251c764feeb4ce094d6f6d5")]
[assembly: AssemblyProduct("OperatorQueueControl")]
[assembly: AssemblyTitle("OperatorQueueControl")]
[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 OperatorQueueControl
{
	internal static class Log
	{
		private static ManualLogSource _logSource;

		internal static void Init(ManualLogSource logSource)
		{
			_logSource = logSource;
		}

		[Conditional("DEBUG")]
		internal static void Info(object data)
		{
			ManualLogSource logSource = _logSource;
			if (logSource != null)
			{
				logSource.LogInfo(data);
			}
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("shay.OperatorQueueControl", "Operator Queue Control", "1.4.0")]
	public sealed class OperatorQueueControlPlugin : BaseUnityPlugin
	{
		private enum DroneControlActionType : byte
		{
			Skip = 1,
			ToggleLock
		}

		private readonly struct ActionResult
		{
			public bool Success { get; }

			public string Message { get; }

			private ActionResult(bool success, string message)
			{
				Success = success;
				Message = message;
			}

			public static ActionResult SuccessResult(string message)
			{
				return new ActionResult(success: true, message);
			}

			public static ActionResult Failure(string message)
			{
				return new ActionResult(success: false, message);
			}
		}

		private sealed class DroneControlRequestMessage : MessageBase
		{
			public byte Action;

			public NetworkInstanceId BodyNetId;

			public override void Serialize(NetworkWriter writer)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				writer.Write(Action);
				writer.Write(BodyNetId);
			}

			public override void Deserialize(NetworkReader reader)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				Action = reader.ReadByte();
				BodyNetId = reader.ReadNetworkId();
			}
		}

		private sealed class DroneControlResponseMessage : MessageBase
		{
			public bool Success;

			public string Message = string.Empty;

			public override void Serialize(NetworkWriter writer)
			{
				writer.Write(Success);
				writer.Write(Message ?? string.Empty);
			}

			public override void Deserialize(NetworkReader reader)
			{
				Success = reader.ReadBoolean();
				Message = reader.ReadString();
			}

			public static DroneControlResponseMessage Create(bool success, string message)
			{
				return new DroneControlResponseMessage
				{
					Success = success,
					Message = (message ?? string.Empty)
				};
			}
		}

		public const string PluginAuthor = "shay";

		public const string PluginId = "OperatorQueueControl";

		public const string PluginDisplayName = "Operator Queue Control";

		public const string PluginGUID = "shay.OperatorQueueControl";

		public const string PluginVersion = "1.4.0";

		private const string OperatorBodyName = "DroneTechBody";

		private const string RiskOfOptionsGuid = "com.rune580.riskofoptions";

		private const short DroneControlRequestMessageType = 32001;

		private const short DroneControlResponseMessageType = 32002;

		private const DroneControlInputMode InputMode = 1;

		private static readonly FieldInfo DroneTechUiField = typeof(DroneTechController).GetField("UI", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private readonly DroneQueueEngine _queueEngine = new DroneQueueEngine();

		private ConfigEntry<bool> _enableSkipKeybind;

		private ConfigEntry<KeyboardShortcut> _skipKeybind;

		private ConfigEntry<bool> _enableLockKeybind;

		private ConfigEntry<KeyboardShortcut> _lockToggleKeybind;

		private ConfigEntry<bool> _showFeedback;

		private readonly Dictionary<int, DroneLockState> _lockStatesByController = new Dictionary<int, DroneLockState>();

		private readonly HashSet<int> _controllersInAdminOverride = new HashSet<int>();

		private bool _serverRequestHandlerRegistered;

		private bool _clientResponseHandlerRegistered;

		private void Awake()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			Log.Init(((BaseUnityPlugin)this).Logger);
			BindConfig();
			RegisterRiskOfOptions();
			DroneTechController.ReturnDrone += new hook_ReturnDrone(DroneTechController_ReturnDrone);
			Activate.OnEnter += new hook_OnEnter(Activate_OnEnter);
			Run.onRunStartGlobal += OnRunStartGlobal;
			Run.onRunDestroyGlobal += OnRunDestroyGlobal;
		}

		private void OnDestroy()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			DroneTechController.ReturnDrone -= new hook_ReturnDrone(DroneTechController_ReturnDrone);
			Activate.OnEnter -= new hook_OnEnter(Activate_OnEnter);
			Run.onRunStartGlobal -= OnRunStartGlobal;
			Run.onRunDestroyGlobal -= OnRunDestroyGlobal;
		}

		private void Update()
		{
			//IL_0019: 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)
			EnsureNetworkHandlersRegistered();
			if (_enableLockKeybind.Value && IsShortcutPressed(_lockToggleKeybind.Value))
			{
				ToggleDroneLock();
			}
			if (_enableSkipKeybind.Value && IsShortcutPressed(_skipKeybind.Value))
			{
				TrySkipCurrentDrone();
			}
			MaintainLockedCurrentDrone();
		}

		private void TrySkipCurrentDrone()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetLocalOperatorController(out var controller, out var reason))
			{
				Feedback(reason);
				return;
			}
			DroneControlInputDecision val = DroneControlAuthorityPolicy.Evaluate((DroneControlInputMode)1, NetworkServer.active, NetworkClient.active);
			if ((int)val.Route == 2)
			{
				if (!TrySendClientActionRequest(controller, DroneControlActionType.Skip, out var reason2))
				{
					Feedback(reason2);
				}
				return;
			}
			if ((int)val.Route == 0)
			{
				Feedback(val.Message);
				return;
			}
			ActionResult actionResult = ApplySkipToController(controller, feedbackRequested: true);
			if (!actionResult.Success && !string.IsNullOrWhiteSpace(actionResult.Message))
			{
				Feedback(actionResult.Message);
			}
		}

		private void ToggleDroneLock()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetLocalOperatorController(out var controller, out var reason))
			{
				Feedback(reason);
				return;
			}
			DroneControlInputDecision val = DroneControlAuthorityPolicy.Evaluate((DroneControlInputMode)1, NetworkServer.active, NetworkClient.active);
			if ((int)val.Route == 2)
			{
				if (!TrySendClientActionRequest(controller, DroneControlActionType.ToggleLock, out var reason2))
				{
					Feedback(reason2);
				}
				return;
			}
			if ((int)val.Route == 0)
			{
				Feedback(val.Message);
				return;
			}
			ActionResult actionResult = ApplyToggleLockToController(controller, feedbackRequested: true);
			if (!actionResult.Success && !string.IsNullOrWhiteSpace(actionResult.Message))
			{
				Feedback(actionResult.Message);
			}
		}

		private ActionResult ApplySkipToController(DroneTechController controller, bool feedbackRequested)
		{
			//IL_001a: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)controller))
			{
				return ActionResult.Failure("Operator drone controller not found.");
			}
			DroneLockState lockState = GetLockState(((Object)controller).GetInstanceID());
			SkipResult val = _queueEngine.Skip(lockState, (IReadOnlyList<DroneId>)BuildQueueIds(controller.DroneQueue));
			if (!val.Success)
			{
				return ActionResult.Failure(val.Message);
			}
			ApplyQueueOrder(controller, val.Queue);
			SetCurrentDroneFromQueueHead(controller);
			TryRefreshDroneQueueUi(controller);
			if (feedbackRequested)
			{
				if (TryGetOwnedDroneById(controller, val.SkippedDrone, out var droneInfo))
				{
					Feedback("Moved " + GetDroneLabel(droneInfo) + " to the back of the queue.");
				}
				else
				{
					Feedback(val.Message);
				}
			}
			return ActionResult.SuccessResult(val.Message);
		}

		private ActionResult ApplyToggleLockToController(DroneTechController controller, bool feedbackRequested)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)controller))
			{
				return ActionResult.Failure("Operator drone controller not found.");
			}
			int instanceID = ((Object)controller).GetInstanceID();
			DroneLockState lockState = GetLockState(instanceID);
			ToggleLockResult val = _queueEngine.ToggleLock(lockState, GetDroneId(controller.CurrentDrone), (IReadOnlyList<DroneId>)BuildQueueIds(controller.DroneQueue));
			if (!val.Success)
			{
				return ActionResult.Failure(val.Message);
			}
			DroneLockState val2 = lockState;
			SetLockState(instanceID, val.LockState);
			ApplyQueueOrder(controller, val.Queue);
			TryRefreshDroneQueueUi(controller);
			DroneLockState lockState2 = GetLockState(instanceID);
			if (((DroneLockState)(ref lockState2)).IsEnabled)
			{
				if (!TryGetOwnedDroneById(controller, ((DroneLockState)(ref lockState2)).LockedDroneId, out var droneInfo))
				{
					ClearLock(instanceID, "Locked drone is no longer available. Lock disabled.");
					return ActionResult.Failure("Locked drone is no longer available. Lock disabled.");
				}
				SetCurrentDroneImmediate(controller, droneInfo);
				if (feedbackRequested)
				{
					Feedback("Locked drone: " + GetDroneLabel(droneInfo));
				}
				return ActionResult.SuccessResult("Locked drone: " + GetDroneLabel(droneInfo));
			}
			SetCurrentDroneFromQueueHead(controller);
			if (((DroneLockState)(ref val2)).IsEnabled && feedbackRequested)
			{
				Feedback("Drone lock disabled.");
			}
			return ActionResult.SuccessResult("Drone lock disabled.");
		}

		private void EnsureNetworkHandlersRegistered()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			if (NetworkServer.active && !_serverRequestHandlerRegistered)
			{
				NetworkServer.RegisterHandler((short)32001, new NetworkMessageDelegate(OnDroneControlRequestMessage));
				_serverRequestHandlerRegistered = true;
			}
			else if (!NetworkServer.active)
			{
				_serverRequestHandlerRegistered = false;
			}
			NetworkClient val = NetworkManager.singleton?.client;
			if (val != null && !_clientResponseHandlerRegistered)
			{
				val.RegisterHandler((short)32002, new NetworkMessageDelegate(OnDroneControlResponseMessage));
				_clientResponseHandlerRegistered = true;
			}
			else if (val == null)
			{
				_clientResponseHandlerRegistered = false;
			}
		}

		private bool TrySendClientActionRequest(DroneTechController controller, DroneControlActionType action, out string reason)
		{
			//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_0088: 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)
			reason = string.Empty;
			if (!Object.op_Implicit((Object)(object)controller))
			{
				reason = "Operator drone controller not found.";
				return false;
			}
			CharacterBody component = ((Component)controller).GetComponent<CharacterBody>();
			NetworkIdentity val = (Object.op_Implicit((Object)(object)component) ? ((Component)component).GetComponent<NetworkIdentity>() : null);
			if (!Object.op_Implicit((Object)(object)val) || val.netId == NetworkInstanceId.Invalid)
			{
				reason = "Unable to identify local Operator network body.";
				return false;
			}
			NetworkClient val2 = NetworkManager.singleton?.client;
			if (val2 == null || !val2.isConnected)
			{
				reason = "No active network client connection. Host the run or connect to a host.";
				return false;
			}
			DroneControlRequestMessage droneControlRequestMessage = new DroneControlRequestMessage
			{
				Action = (byte)action,
				BodyNetId = val.netId
			};
			val2.Send((short)32001, (MessageBase)(object)droneControlRequestMessage);
			return true;
		}

		private void OnDroneControlRequestMessage(NetworkMessage netMsg)
		{
			if (NetworkServer.active)
			{
				DroneControlRequestMessage request = netMsg.ReadMessage<DroneControlRequestMessage>();
				DroneControlResponseMessage droneControlResponseMessage = HandleServerActionRequest(netMsg.conn, request);
				NetworkConnection conn = netMsg.conn;
				if (conn != null)
				{
					conn.Send((short)32002, (MessageBase)(object)droneControlResponseMessage);
				}
			}
		}

		private DroneControlResponseMessage HandleServerActionRequest(NetworkConnection senderConnection, DroneControlRequestMessage request)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			if (!TryResolveAuthorizedController(senderConnection, request.BodyNetId, out var controller, out var reason))
			{
				return DroneControlResponseMessage.Create(success: false, reason);
			}
			return (DroneControlActionType)request.Action switch
			{
				DroneControlActionType.Skip => BuildResponse(ApplySkipToController(controller, feedbackRequested: false)), 
				DroneControlActionType.ToggleLock => BuildResponse(ApplyToggleLockToController(controller, feedbackRequested: false)), 
				_ => DroneControlResponseMessage.Create(success: false, "Unknown drone control action requested."), 
			};
		}

		private static DroneControlResponseMessage BuildResponse(ActionResult result)
		{
			return DroneControlResponseMessage.Create(result.Success, result.Message);
		}

		private bool TryResolveAuthorizedController(NetworkConnection senderConnection, NetworkInstanceId bodyNetId, out DroneTechController controller, out string reason)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			controller = null;
			reason = string.Empty;
			if (senderConnection == null)
			{
				reason = "Missing network sender connection.";
				return false;
			}
			GameObject val = Util.FindNetworkObject(bodyNetId);
			CharacterBody val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<CharacterBody>() : null);
			if (!IsOperatorBody(val2))
			{
				reason = "The requested body is not a valid Operator body.";
				return false;
			}
			NetworkUser val3 = TryGetNetworkUserFromConnection(senderConnection);
			if (!Object.op_Implicit((Object)(object)val3) || (Object)(object)val3.master != (Object)(object)val2.master)
			{
				reason = "You do not own that Operator body.";
				return false;
			}
			controller = ((Component)val2).GetComponent<DroneTechController>();
			if (!Object.op_Implicit((Object)(object)controller))
			{
				reason = "Operator drone controller not found on requested body.";
				return false;
			}
			return true;
		}

		private static NetworkUser TryGetNetworkUserFromConnection(NetworkConnection connection)
		{
			if (((connection != null) ? connection.playerControllers : null) == null)
			{
				return null;
			}
			for (int i = 0; i < connection.playerControllers.Count; i++)
			{
				GameObject gameObject = connection.playerControllers[i].gameObject;
				if (Object.op_Implicit((Object)(object)gameObject))
				{
					NetworkUser component = gameObject.GetComponent<NetworkUser>();
					if (Object.op_Implicit((Object)(object)component))
					{
						return component;
					}
				}
			}
			return null;
		}

		private void OnDroneControlResponseMessage(NetworkMessage netMsg)
		{
			DroneControlResponseMessage droneControlResponseMessage = netMsg.ReadMessage<DroneControlResponseMessage>();
			if (!string.IsNullOrWhiteSpace(droneControlResponseMessage.Message))
			{
				Feedback(droneControlResponseMessage.Message);
			}
		}

		private void DroneTechController_ReturnDrone(orig_ReturnDrone orig, DroneTechController self, DroneInfo droneInfo)
		{
			//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_0045: 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)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			orig.Invoke(self, droneInfo);
			if (!NetworkServer.active || !Object.op_Implicit((Object)(object)self))
			{
				return;
			}
			int instanceID = ((Object)self).GetInstanceID();
			DroneLockState lockState = GetLockState(instanceID);
			if (!((DroneLockState)(ref lockState)).IsEnabled || !_controllersInAdminOverride.Contains(instanceID))
			{
				return;
			}
			ReturnDroneResult val = _queueEngine.HandleReturn(lockState, true, (IReadOnlyList<DroneId>)BuildQueueIds(self.DroneQueue));
			SetLockState(instanceID, val.LockState);
			if (val.QueueChanged)
			{
				ApplyQueueOrder(self, val.Queue);
				TryRefreshDroneQueueUi(self);
			}
			DroneLockState lockState2 = GetLockState(instanceID);
			if (((DroneLockState)(ref lockState2)).IsEnabled)
			{
				if (TryGetOwnedDroneById(self, ((DroneLockState)(ref lockState2)).LockedDroneId, out var droneInfo2))
				{
					SetCurrentDroneImmediate(self, droneInfo2);
				}
				else
				{
					ClearLock(instanceID, "Locked drone is no longer available. Lock disabled.");
				}
			}
		}

		private void Activate_OnEnter(orig_OnEnter orig, Activate self)
		{
			DroneTechController val = ResolveControllerForAdminOverride(self);
			int num = (Object.op_Implicit((Object)(object)val) ? ((Object)val).GetInstanceID() : int.MinValue);
			if (num != int.MinValue)
			{
				_controllersInAdminOverride.Add(num);
			}
			try
			{
				PrepareLockedDroneForAdminOverride(val);
				orig.Invoke(self);
			}
			finally
			{
				if (num != int.MinValue)
				{
					_controllersInAdminOverride.Remove(num);
				}
			}
		}

		private DroneTechController ResolveControllerForAdminOverride(Activate state)
		{
			if (Object.op_Implicit((Object)(object)state?.droneController))
			{
				return state.droneController;
			}
			CharacterBody val = ((state != null) ? ((EntityState)state).characterBody : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				DroneTechController component = ((Component)val).GetComponent<DroneTechController>();
				if (Object.op_Implicit((Object)(object)component))
				{
					return component;
				}
			}
			return ResolveTrackedControllerFallback();
		}

		private DroneTechController ResolveTrackedControllerFallback()
		{
			LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
			CharacterBody val = ((firstLocalUser != null) ? firstLocalUser.cachedBody : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			return ((Component)val).GetComponent<DroneTechController>();
		}

		private void PrepareLockedDroneForAdminOverride(DroneTechController controller)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkServer.active || !Object.op_Implicit((Object)(object)controller))
			{
				return;
			}
			int instanceID = ((Object)controller).GetInstanceID();
			DroneLockState lockState = GetLockState(instanceID);
			if (((DroneLockState)(ref lockState)).IsEnabled)
			{
				if (!TryGetOwnedDroneById(controller, ((DroneLockState)(ref lockState)).LockedDroneId, out var droneInfo))
				{
					ClearLock(instanceID, "Locked drone is no longer available. Lock disabled.");
				}
				else
				{
					EnsureDroneAtQueueHead(controller, droneInfo);
				}
			}
		}

		private static List<DroneId> BuildQueueIds(List<DroneInfo> queue)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			List<DroneId> list = new List<DroneId>(queue.Count);
			foreach (DroneInfo item in queue)
			{
				DroneId droneId = GetDroneId(item);
				if (((DroneId)(ref droneId)).IsValid)
				{
					list.Add(droneId);
				}
			}
			return list;
		}

		private static void ApplyQueueOrder(DroneTechController controller, IReadOnlyList<DroneId> queueOrder)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)controller))
			{
				return;
			}
			Dictionary<DroneId, DroneInfo> dictionary = new Dictionary<DroneId, DroneInfo>();
			foreach (DroneInfo item in controller.DroneQueue)
			{
				DroneId droneId = GetDroneId(item);
				if (((DroneId)(ref droneId)).IsValid && !dictionary.ContainsKey(droneId))
				{
					dictionary.Add(droneId, item);
				}
			}
			if (dictionary.Count != queueOrder.Count)
			{
				return;
			}
			List<DroneInfo> list = new List<DroneInfo>(queueOrder.Count);
			foreach (DroneId item2 in queueOrder)
			{
				if (!dictionary.TryGetValue(item2, out var value))
				{
					return;
				}
				list.Add(value);
			}
			controller.DroneQueue.Clear();
			controller.DroneQueue.AddRange(list);
		}

		private static void SetCurrentDroneFromQueueHead(DroneTechController controller)
		{
			if (Object.op_Implicit((Object)(object)controller))
			{
				if (controller.DroneQueue.Count > 0)
				{
					SetCurrentDroneImmediate(controller, controller.DroneQueue[0]);
				}
				else
				{
					SetCurrentDroneImmediate(controller, null);
				}
			}
		}

		private static void SetCurrentDroneImmediate(DroneTechController controller, DroneInfo droneInfo)
		{
			if (Object.op_Implicit((Object)(object)controller))
			{
				controller.SetCurrentDrone(droneInfo);
			}
		}

		private static bool EnsureDroneAtQueueHead(DroneTechController controller, DroneInfo droneInfo)
		{
			//IL_003f: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)controller) || (Object)(object)droneInfo?.commandReceiver == (Object)null)
			{
				return false;
			}
			DroneId val = ((controller.DroneQueue.Count > 0) ? GetDroneId(controller.DroneQueue[0]) : DroneId.None);
			DroneId droneId = GetDroneId(droneInfo);
			int num = 0;
			for (int num2 = controller.DroneQueue.Count - 1; num2 >= 0; num2--)
			{
				if (GetDroneId(controller.DroneQueue[num2]) == droneId)
				{
					controller.DroneQueue.RemoveAt(num2);
					num++;
				}
			}
			if (droneInfo.commandReceiver.IsReady())
			{
				controller.DroneQueue.Insert(0, droneInfo);
				SetCurrentDroneImmediate(controller, droneInfo);
				DroneId val2 = ((controller.DroneQueue.Count > 0) ? GetDroneId(controller.DroneQueue[0]) : DroneId.None);
				if (num <= 1)
				{
					return val != val2;
				}
				return true;
			}
			return false;
		}

		private static void TryRefreshDroneQueueUi(DroneTechController controller)
		{
			if (Object.op_Implicit((Object)(object)controller))
			{
				object? obj = DroneTechUiField?.GetValue(controller);
				DroneTechSurvivorUIController val = (DroneTechSurvivorUIController)((obj is DroneTechSurvivorUIController) ? obj : null);
				if (val != null)
				{
					val.TryUpdateIcons(controller.DroneQueue, controller.AllDrones);
				}
			}
		}

		private static bool TryGetOwnedDroneById(DroneTechController controller, DroneId droneId, out DroneInfo droneInfo)
		{
			//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)
			droneInfo = null;
			if (!Object.op_Implicit((Object)(object)controller) || !((DroneId)(ref droneId)).IsValid)
			{
				return false;
			}
			foreach (DroneInfo allDrone in controller.AllDrones)
			{
				if (!(GetDroneId(allDrone) != droneId))
				{
					droneInfo = allDrone;
					return true;
				}
			}
			return false;
		}

		private bool TryGetLocalOperatorController(out DroneTechController controller, out string reason)
		{
			controller = null;
			reason = string.Empty;
			LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
			if (firstLocalUser == null)
			{
				reason = "No local user found.";
				return false;
			}
			CharacterBody cachedBody = firstLocalUser.cachedBody;
			if (!Object.op_Implicit((Object)(object)cachedBody))
			{
				reason = "No active character body.";
				return false;
			}
			if (!IsOperatorBody(cachedBody))
			{
				reason = "You need to be playing Operator to use this.";
				return false;
			}
			controller = ((Component)cachedBody).GetComponent<DroneTechController>();
			if (!Object.op_Implicit((Object)(object)controller))
			{
				reason = "Operator drone controller not found on this body.";
				return false;
			}
			return true;
		}

		private void BindConfig()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			_enableSkipKeybind = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableSkipKeybind", true, "Enable the skip current drone keybind.");
			_skipKeybind = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "SkipKeybind", new KeyboardShortcut((KeyCode)103, Array.Empty<KeyCode>()), "Moves the current next-up drone to the back of the queue.");
			_enableLockKeybind = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableLockKeybind", true, "Enable the lock current drone keybind.");
			_lockToggleKeybind = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "LockToggleKeybind", new KeyboardShortcut((KeyCode)118, Array.Empty<KeyCode>()), "Toggle locking ADMIN-OVERRIDE to the current next-up drone.");
			_showFeedback = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowFeedback", false, "Show chat feedback when actions are triggered.");
		}

		private void RegisterRiskOfOptions()
		{
			if (!Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"))
			{
				return;
			}
			try
			{
				Type type = Type.GetType("RiskOfOptions.ModSettingsManager, RiskOfOptions");
				Type type2 = Type.GetType("RiskOfOptions.Options.CheckBoxOption, RiskOfOptions");
				Type type3 = Type.GetType("RiskOfOptions.Options.KeyBindOption, RiskOfOptions");
				if (!(type == null) && !(type2 == null) && !(type3 == null))
				{
					InvokeRiskOfOptionsMethod(type, "SetModDescription", "Rebind skip/lock controls and toggle feedback without editing config files.");
					AddRiskOfOptionsOption(type, CreateRiskOfOptionsOption(type2, _enableSkipKeybind));
					AddRiskOfOptionsOption(type, CreateRiskOfOptionsOption(type3, _skipKeybind));
					AddRiskOfOptionsOption(type, CreateRiskOfOptionsOption(type2, _enableLockKeybind));
					AddRiskOfOptionsOption(type, CreateRiskOfOptionsOption(type3, _lockToggleKeybind));
					AddRiskOfOptionsOption(type, CreateRiskOfOptionsOption(type2, _showFeedback));
				}
			}
			catch (Exception)
			{
			}
		}

		private static void AddRiskOfOptionsOption(Type modSettingsManagerType, object optionInstance)
		{
			if (optionInstance != null)
			{
				InvokeRiskOfOptionsMethod(modSettingsManagerType, "AddOption", optionInstance);
			}
		}

		private static object CreateRiskOfOptionsOption(Type optionType, object configEntry)
		{
			ConstructorInfo[] constructors = optionType.GetConstructors();
			foreach (ConstructorInfo constructorInfo in constructors)
			{
				ParameterInfo[] parameters = constructorInfo.GetParameters();
				if (parameters.Length == 1 && parameters[0].ParameterType.IsInstanceOfType(configEntry))
				{
					return constructorInfo.Invoke(new object[1] { configEntry });
				}
			}
			return null;
		}

		private static void InvokeRiskOfOptionsMethod(Type managerType, string methodName, params object[] arguments)
		{
			MethodInfo[] methods = managerType.GetMethods(BindingFlags.Static | BindingFlags.Public);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name != methodName)
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length != arguments.Length)
				{
					continue;
				}
				bool flag = true;
				for (int j = 0; j < parameters.Length; j++)
				{
					object obj = arguments[j];
					if (obj == null)
					{
						if (parameters[j].ParameterType.IsValueType)
						{
							flag = false;
							break;
						}
					}
					else if (!parameters[j].ParameterType.IsInstanceOfType(obj))
					{
						flag = false;
						break;
					}
				}
				if (flag)
				{
					methodInfo.Invoke(null, arguments);
					break;
				}
			}
		}

		private void OnRunStartGlobal(Run _)
		{
			ClearRunState();
		}

		private void OnRunDestroyGlobal(Run _)
		{
			ClearRunState();
		}

		private void ClearRunState()
		{
			_lockStatesByController.Clear();
			_controllersInAdminOverride.Clear();
		}

		private void MaintainLockedCurrentDrone()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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)
			if (!NetworkServer.active || !TryGetLocalOperatorController(out var controller, out var _))
			{
				return;
			}
			int instanceID = ((Object)controller).GetInstanceID();
			DroneLockState lockState = GetLockState(instanceID);
			if (!((DroneLockState)(ref lockState)).IsEnabled)
			{
				return;
			}
			if (!TryGetOwnedDroneById(controller, ((DroneLockState)(ref lockState)).LockedDroneId, out var droneInfo))
			{
				ClearLock(instanceID, "Locked drone is no longer available. Lock disabled.");
				return;
			}
			bool num = EnsureDroneAtQueueHead(controller, droneInfo);
			SetCurrentDroneImmediate(controller, droneInfo);
			if (num)
			{
				TryRefreshDroneQueueUi(controller);
			}
		}

		private DroneLockState GetLockState(int controllerId)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			if (_lockStatesByController.TryGetValue(controllerId, out var value))
			{
				return value;
			}
			return DroneLockState.Disabled;
		}

		private void SetLockState(int controllerId, DroneLockState lockState)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			if (((DroneLockState)(ref lockState)).IsEnabled)
			{
				_lockStatesByController[controllerId] = lockState;
			}
			else
			{
				_lockStatesByController.Remove(controllerId);
			}
		}

		private void ClearLock(int controllerId, string reason = "")
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			DroneLockState lockState = GetLockState(controllerId);
			bool isEnabled = ((DroneLockState)(ref lockState)).IsEnabled;
			_lockStatesByController.Remove(controllerId);
			if (isEnabled && !string.IsNullOrWhiteSpace(reason))
			{
				Feedback(reason);
			}
		}

		private static bool IsOperatorBody(CharacterBody body)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)body))
			{
				return false;
			}
			return body.bodyIndex == BodyCatalog.FindBodyIndex("DroneTechBody");
		}

		private void Feedback(string message)
		{
			if (_showFeedback.Value)
			{
				Chat.AddMessage("[Operator Queue Control] " + message);
			}
		}

		private static bool IsShortcutPressed(KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0 || !Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return false;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if (!Input.GetKey(modifier))
				{
					return false;
				}
			}
			return true;
		}

		private static DroneId GetDroneId(DroneInfo droneInfo)
		{
			//IL_002a: 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)
			if ((Object)(object)droneInfo?.commandReceiver == (Object)null)
			{
				return DroneId.None;
			}
			return new DroneId(((Object)((Component)droneInfo.commandReceiver).gameObject).GetInstanceID());
		}

		private static string GetDroneLabel(DroneInfo droneInfo)
		{
			if ((Object)(object)droneInfo?.commandReceiver == (Object)null)
			{
				return "Unknown Drone";
			}
			CharacterBody characterBody = droneInfo.commandReceiver.characterBody;
			if (Object.op_Implicit((Object)(object)characterBody))
			{
				string @string = Language.GetString(characterBody.baseNameToken);
				if (!string.IsNullOrWhiteSpace(@string) && @string != characterBody.baseNameToken)
				{
					return @string;
				}
				if (!string.IsNullOrWhiteSpace(characterBody.baseNameToken))
				{
					return characterBody.baseNameToken;
				}
				return ((Object)characterBody).name;
			}
			return ((Object)droneInfo.commandReceiver).name;
		}
	}
}

plugins/OperatorQueueControl/OperatorQueueControl.Core.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("OperatorQueueControl.Core")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+e72b8852648bfaa0e251c764feeb4ce094d6f6d5")]
[assembly: AssemblyProduct("OperatorQueueControl.Core")]
[assembly: AssemblyTitle("OperatorQueueControl.Core")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 OperatorQueueControl.Core
{
	public enum DroneControlInputMode
	{
		HostOnly,
		ClientRequestServerApply
	}
	public enum DroneControlInputRoute
	{
		Reject,
		ApplyLocally,
		SendToServer
	}
	public sealed class DroneControlInputDecision
	{
		public DroneControlInputRoute Route { get; }

		public string Message { get; }

		public DroneControlInputDecision(DroneControlInputRoute route, string message)
		{
			Route = route;
			Message = message;
		}
	}
	public static class DroneControlAuthorityPolicy
	{
		public static DroneControlInputDecision Evaluate(DroneControlInputMode mode, bool isServerActive, bool isClientActive)
		{
			if (mode == DroneControlInputMode.HostOnly)
			{
				if (isServerActive)
				{
					return new DroneControlInputDecision(DroneControlInputRoute.ApplyLocally, "Applying action on host/server.");
				}
				return new DroneControlInputDecision(DroneControlInputRoute.Reject, "This action requires host authority in host-only mode.");
			}
			if (isServerActive)
			{
				return new DroneControlInputDecision(DroneControlInputRoute.ApplyLocally, "Applying action on server authority.");
			}
			if (isClientActive)
			{
				return new DroneControlInputDecision(DroneControlInputRoute.SendToServer, "Client request will be sent to server for validation and execution.");
			}
			return new DroneControlInputDecision(DroneControlInputRoute.Reject, "Unable to execute action: no server authority and no active client connection.");
		}
	}
	public readonly struct DroneId : IEquatable<DroneId>
	{
		public int Value { get; }

		public bool IsValid => Value != 0;

		public static DroneId None => new DroneId(0);

		public DroneId(int value)
		{
			Value = value;
		}

		public bool Equals(DroneId other)
		{
			return Value == other.Value;
		}

		public override bool Equals(object? obj)
		{
			if (obj is DroneId other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return Value;
		}

		public override string ToString()
		{
			if (!IsValid)
			{
				return "None";
			}
			return Value.ToString();
		}

		public static bool operator ==(DroneId left, DroneId right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(DroneId left, DroneId right)
		{
			return !left.Equals(right);
		}
	}
	public readonly struct DroneLockState : IEquatable<DroneLockState>
	{
		public bool IsEnabled { get; }

		public DroneId LockedDroneId { get; }

		public static DroneLockState Disabled => new DroneLockState(isEnabled: false, DroneId.None);

		public DroneLockState(bool isEnabled, DroneId lockedDroneId)
		{
			IsEnabled = isEnabled;
			LockedDroneId = lockedDroneId;
		}

		public static DroneLockState Enabled(DroneId lockedDroneId)
		{
			return new DroneLockState(isEnabled: true, lockedDroneId);
		}

		public bool Equals(DroneLockState other)
		{
			if (IsEnabled == other.IsEnabled)
			{
				return LockedDroneId == other.LockedDroneId;
			}
			return false;
		}

		public override bool Equals(object? obj)
		{
			if (obj is DroneLockState other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return HashCode.Combine(IsEnabled, LockedDroneId);
		}

		public static bool operator ==(DroneLockState left, DroneLockState right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(DroneLockState left, DroneLockState right)
		{
			return !left.Equals(right);
		}
	}
	public sealed class DroneQueueEngine
	{
		public ToggleLockResult ToggleLock(DroneLockState currentLockState, DroneId currentDroneId, IReadOnlyList<DroneId> queue)
		{
			if (currentLockState.IsEnabled)
			{
				return new ToggleLockResult(success: true, DroneLockState.Disabled, CopyQueue(queue), "Drone lock disabled.");
			}
			if (!currentDroneId.IsValid)
			{
				return new ToggleLockResult(success: false, currentLockState, CopyQueue(queue), "No current next-up drone to lock.");
			}
			List<DroneId> queue2 = CopyQueue(queue);
			List<DroneId> list = PromoteDroneToFront(queue2, currentDroneId);
			if (list == null)
			{
				return new ToggleLockResult(success: false, currentLockState, queue2, "Unable to identify the selected drone.");
			}
			return new ToggleLockResult(success: true, DroneLockState.Enabled(currentDroneId), list, $"Locked drone: {currentDroneId}");
		}

		public SkipResult Skip(DroneLockState lockState, IReadOnlyList<DroneId> queue)
		{
			List<DroneId> list = CopyQueue(queue);
			if (lockState.IsEnabled)
			{
				return new SkipResult(success: false, blockedByLock: true, DroneId.None, list, "Skip is disabled while drone lock is active.");
			}
			if (list.Count == 0)
			{
				return new SkipResult(success: false, blockedByLock: false, DroneId.None, list, "No ready drones to skip.");
			}
			DroneId droneId = list[0];
			list.RemoveAt(0);
			list.Add(droneId);
			return new SkipResult(success: true, blockedByLock: false, droneId, list, $"Moved {droneId} to the back of the queue.");
		}

		public SelectReadyDroneResult SelectReadyDrone(DroneLockState lockState, bool isAdminOverride, IReadOnlyList<DroneId> queue)
		{
			if (queue.Count == 0)
			{
				return new SelectReadyDroneResult(hasSelection: false, DroneId.None, lockState, null);
			}
			if (!lockState.IsEnabled || !isAdminOverride)
			{
				return new SelectReadyDroneResult(hasSelection: true, queue[0], lockState, null);
			}
			if (!TryFindIndex(queue, lockState.LockedDroneId, out var _))
			{
				return new SelectReadyDroneResult(hasSelection: true, queue[0], DroneLockState.Disabled, "Locked drone is no longer available. Lock disabled.");
			}
			return new SelectReadyDroneResult(hasSelection: true, lockState.LockedDroneId, lockState, null);
		}

		public ReturnDroneResult HandleReturn(DroneLockState lockState, bool isAdminOverride, IReadOnlyList<DroneId> queue)
		{
			List<DroneId> list = CopyQueue(queue);
			DroneId droneId = ((list.Count > 0) ? list[0] : DroneId.None);
			if (!lockState.IsEnabled || !isAdminOverride)
			{
				return new ReturnDroneResult(lockState, list, queueChanged: false, null);
			}
			List<DroneId> list2 = PromoteDroneToFront(list, lockState.LockedDroneId);
			if (list2 == null)
			{
				return new ReturnDroneResult(lockState, list, queueChanged: false, null);
			}
			bool queueChanged = list.Count > 0 && list[0] != droneId;
			return new ReturnDroneResult(lockState, list2, queueChanged, null);
		}

		private static List<DroneId> CopyQueue(IReadOnlyList<DroneId> queue)
		{
			List<DroneId> list = new List<DroneId>(queue.Count);
			for (int i = 0; i < queue.Count; i++)
			{
				list.Add(queue[i]);
			}
			return list;
		}

		private static bool TryFindIndex(IReadOnlyList<DroneId> queue, DroneId droneId, out int index)
		{
			for (int i = 0; i < queue.Count; i++)
			{
				if (queue[i] == droneId)
				{
					index = i;
					return true;
				}
			}
			index = -1;
			return false;
		}

		private static List<DroneId>? PromoteDroneToFront(List<DroneId> queue, DroneId droneId)
		{
			if (!droneId.IsValid)
			{
				return null;
			}
			if (!TryFindIndex(queue, droneId, out var index))
			{
				return null;
			}
			if (index > 0)
			{
				queue.RemoveAt(index);
				queue.Insert(0, droneId);
			}
			return queue;
		}
	}
	public sealed class ToggleLockResult
	{
		public bool Success { get; }

		public DroneLockState LockState { get; }

		public IReadOnlyList<DroneId> Queue { get; }

		public string Message { get; }

		public ToggleLockResult(bool success, DroneLockState lockState, IReadOnlyList<DroneId> queue, string message)
		{
			Success = success;
			LockState = lockState;
			Queue = queue;
			Message = message;
		}
	}
	public sealed class SkipResult
	{
		public bool Success { get; }

		public bool BlockedByLock { get; }

		public DroneId SkippedDrone { get; }

		public IReadOnlyList<DroneId> Queue { get; }

		public string Message { get; }

		public SkipResult(bool success, bool blockedByLock, DroneId skippedDrone, IReadOnlyList<DroneId> queue, string message)
		{
			Success = success;
			BlockedByLock = blockedByLock;
			SkippedDrone = skippedDrone;
			Queue = queue;
			Message = message;
		}
	}
	public sealed class SelectReadyDroneResult
	{
		public bool HasSelection { get; }

		public DroneId SelectedDrone { get; }

		public DroneLockState LockState { get; }

		public string? LockClearedReason { get; }

		public SelectReadyDroneResult(bool hasSelection, DroneId selectedDrone, DroneLockState lockState, string? lockClearedReason)
		{
			HasSelection = hasSelection;
			SelectedDrone = selectedDrone;
			LockState = lockState;
			LockClearedReason = lockClearedReason;
		}
	}
	public sealed class ReturnDroneResult
	{
		public DroneLockState LockState { get; }

		public IReadOnlyList<DroneId> Queue { get; }

		public bool QueueChanged { get; }

		public string? LockClearedReason { get; }

		public ReturnDroneResult(DroneLockState lockState, IReadOnlyList<DroneId> queue, bool queueChanged, string? lockClearedReason)
		{
			LockState = lockState;
			Queue = queue;
			QueueChanged = queueChanged;
			LockClearedReason = lockClearedReason;
		}
	}
}