using System; using System.Collections.Generic; using System.Reflection; using Robust.Shared.Reflection; using Robust.Shared.Serialization; namespace Robust.Shared.Input { /// /// A networked identifier for a . /// [Serializable, NetSerializable] public readonly struct KeyFunctionId : IEquatable { private readonly int _value; public KeyFunctionId(int id) { _value = id; } public static explicit operator int(KeyFunctionId funcId) { return funcId._value; } public override string ToString() { return _value.ToString(); } public bool Equals(KeyFunctionId other) { return _value == other._value; } public override bool Equals(object? obj) { return obj is KeyFunctionId other && Equals(other); } public override int GetHashCode() { return _value; } public static bool operator ==(KeyFunctionId left, KeyFunctionId right) { return left.Equals(right); } public static bool operator !=(KeyFunctionId left, KeyFunctionId right) { return !left.Equals(right); } } /// /// Sets up a mapping of to for network messages. /// public sealed class BoundKeyMap { private readonly IReflectionManager reflectionManager; private readonly Dictionary KeyFunctionsMap = new(); private readonly List KeyFunctionsList = new(); public BoundKeyMap(IReflectionManager reflectionManager) { this.reflectionManager = reflectionManager; } internal IEnumerable AllKeyFunctions => KeyFunctionsList; public void PopulateKeyFunctionsMap() { if (KeyFunctionsMap.Count != 0) { throw new InvalidOperationException("Cannot run this method twice."); } foreach (var type in reflectionManager.FindTypesWithAttribute()) { foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)) { // This check makes sure we ONLY get readonly fields with the type we want. if (field.IsLiteral || !field.IsInitOnly || field.FieldType != typeof(BoundKeyFunction)) { continue; } KeyFunctionsList.Add((BoundKeyFunction)field.GetValue(null)!); } } KeyFunctionsList.Sort(); for (var i = 0; i < KeyFunctionsList.Count; i++) { KeyFunctionsMap.Add(KeyFunctionsList[i], new KeyFunctionId(i)); } } public bool FunctionExists(string name) { return KeyFunctionsMap.ContainsKey(new BoundKeyFunction(name)); } public KeyFunctionId KeyFunctionID(BoundKeyFunction function) { return KeyFunctionsMap[function]; } public BoundKeyFunction KeyFunctionName(KeyFunctionId function) { return KeyFunctionsList[(int) function]; } public bool TryGetKeyFunction(KeyFunctionId funcId, out BoundKeyFunction func) { var list = KeyFunctionsList; var index = (int) funcId; if (0 > index || index >= list.Count) { func = default; return false; } func = list[index]; return true; } } }