using System; using System.Collections.Generic; using System.Numerics; using Robust.Client.ViewVariables.Editors; using Robust.Shared.Audio; using Robust.Shared.ContentPack; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; namespace Robust.Client.ViewVariables; internal sealed class ViewVariableControlFactory : IViewVariableControlFactory { [Dependency] private readonly IPrototypeManager _protoManager = default!; [Dependency] private readonly IResourceManager _resManager = default!; [Dependency] private readonly IDependencyCollection _dependencyManager = default!; private readonly Dictionary> _factoriesByType = new(); private readonly List _factoriesWithCondition = new(); public ViewVariableControlFactory() { RegisterForType(_ => new VVPropEditorNumeric(VVPropEditorNumeric.NumberType.SByte)); RegisterForType(_ => new VVPropEditorNumeric(VVPropEditorNumeric.NumberType.Byte)); RegisterForType(_ => new VVPropEditorNumeric(VVPropEditorNumeric.NumberType.UShort)); RegisterForType(_ => new VVPropEditorNumeric(VVPropEditorNumeric.NumberType.Short)); RegisterForType(_ => new VVPropEditorNumeric(VVPropEditorNumeric.NumberType.UInt)); RegisterForType(_ => new VVPropEditorNumeric(VVPropEditorNumeric.NumberType.Int)); RegisterForType(_ => new VVPropEditorNumeric(VVPropEditorNumeric.NumberType.ULong)); RegisterForType(_ => new VVPropEditorNumeric(VVPropEditorNumeric.NumberType.Long)); RegisterForType(_ => new VVPropEditorNumeric(VVPropEditorNumeric.NumberType.Float)); RegisterForType(_ => new VVPropEditorNumeric(VVPropEditorNumeric.NumberType.Float)); RegisterForType(_ => new VVPropEditorNumeric(VVPropEditorNumeric.NumberType.Double)); RegisterForType(_ => new VVPropEditorNumeric(VVPropEditorNumeric.NumberType.Decimal)); RegisterForType(_ => new VVPropEditorString()); RegisterForType(_ => new VVPropEditorNullableEntProtoId()); RegisterForType(_ => new VVPropEditorEntProtoId()); RegisterForType(_ => new VVPropEditorVector2(intVec: false)); RegisterForType(_ => new VVPropEditorVector2(intVec: true)); RegisterForType(_ => new VVPropEditorBoolean()); RegisterForType(_ => new VVPropEditorAngle()); RegisterForType(_ => new VVPropEditorUIBox2(VVPropEditorUIBox2.BoxType.Box2)); RegisterForType(_ => new VVPropEditorUIBox2(VVPropEditorUIBox2.BoxType.Box2i)); RegisterForType(_ => new VVPropEditorUIBox2(VVPropEditorUIBox2.BoxType.UIBox2)); RegisterForType(_ => new VVPropEditorUIBox2(VVPropEditorUIBox2.BoxType.UIBox2i)); RegisterForType(_ => new VVPropEditorEntityCoordinates()); RegisterForType(_ => new VVPropEditorEntityUid()); RegisterForType(_ => new VVPropEditorNetEntity()); RegisterForType(_ => new VVPropEditorColor()); RegisterForType(_ => new VVPropEditorTimeSpan()); RegisterWithCondition( type => type != typeof(ViewVariablesBlobMembers.ServerValueTypeToken) && !type.IsValueType, _ => new VVPropEditorReference() ); RegisterWithCondition( type => type == typeof(ViewVariablesBlobMembers.ServerKeyValuePairToken) || type.IsGenericType && type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>), _ => new VVPropEditorKeyValuePair() ); RegisterForAssignableFrom(_ => new VVPropEditorSoundSpecifier(_protoManager, _resManager)); RegisterForAssignableFrom(type => CreateGenericEditor(type, typeof(VVPropEditorISelfSerializable<>))); RegisterForAssignableFrom(type => CreateGenericEditor(type, typeof(VVPropEditorIPrototype<>))); RegisterForAssignableFrom(type => CreateGenericEditor(type, typeof(VVPropEditorIPrototype<>))); RegisterWithCondition( type => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ProtoId<>), type => { var typeArgumentType = type.GenericTypeArguments[0]; var editor = CreateGenericEditor(typeArgumentType, typeof(VVPropEditorProtoId<>)); _dependencyManager.InjectDependencies(editor); return editor; } ); RegisterWithCondition(type => type.IsEnum, _ => new VVPropEditorEnum()); } /// public void RegisterForType(Func factoryMethod) { _factoriesByType[typeof(T)] = factoryMethod; } /// public void RegisterForAssignableFrom(Func factoryMethod, InsertPosition insertPosition = InsertPosition.First) { int insertIndex = insertPosition == InsertPosition.Last && _factoriesWithCondition.Count > 0 ? _factoriesWithCondition.Count - 1 : 0; _factoriesWithCondition.Insert(insertIndex, new(type => typeof(T).IsAssignableFrom(type), factoryMethod)); } /// public void RegisterWithCondition(Func condition, Func factory, InsertPosition insertPosition = InsertPosition.First) { int insertIndex = insertPosition == InsertPosition.Last && _factoriesWithCondition.Count > 0 ? _factoriesWithCondition.Count - 1 : 0; _factoriesWithCondition.Insert(insertIndex, new(condition, factory)); } /// public VVPropEditor CreateFor(Type? type) { if (type == null) { return new VVPropEditorDummy(); } if (_factoriesByType.TryGetValue(type, out var factory)) { return factory(type); } foreach (var factoryWithCondition in _factoriesWithCondition) { if (factoryWithCondition.CanExecute(type)) { return factoryWithCondition.Create(type); } } return new VVPropEditorDummy(); } private static VVPropEditor CreateGenericEditor(Type typeArgumentType, Type genericConrolType) { var typeToCreate = genericConrolType.MakeGenericType(typeArgumentType); return (VVPropEditor)Activator.CreateInstance(typeToCreate)!; } private sealed record ConditionalViewVariableFactoryMethodContainer( Func CanExecute, Func Create ); }