1
0

InteractionTest.EntitySpecifier.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #nullable enable
  2. using Content.Shared.Stacks;
  3. using Robust.Shared.GameObjects;
  4. using Robust.Shared.Map;
  5. using Robust.Shared.Prototypes;
  6. using static Robust.UnitTesting.RobustIntegrationTest;
  7. namespace Content.IntegrationTests.Tests.Interaction;
  8. public abstract partial class InteractionTest
  9. {
  10. /// <summary>
  11. /// Utility class for working with prototypes ids that may refer to stacks or entities.
  12. /// </summary>
  13. /// <remarks>
  14. /// Intended to make tests easier by removing ambiguity around "SheetSteel1", "SheetSteel", and "Steel". All three
  15. /// should be treated identically by interaction tests.
  16. /// </remarks>
  17. protected sealed class EntitySpecifier
  18. {
  19. /// <summary>
  20. /// Either the stack or entity prototype for this entity. Stack prototypes take priority.
  21. /// </summary>
  22. public string Prototype;
  23. /// <summary>
  24. /// The quantity. If the entity has a stack component, this is the total stack quantity.
  25. /// Otherwise this is the number of entities.
  26. /// </summary>
  27. /// <remarks>
  28. /// If used for spawning and this number is larger than the max stack size, only a single stack will be spawned.
  29. /// </remarks>
  30. public int Quantity;
  31. /// <summary>
  32. /// If true, a check has been performed to see if the prototype is an entity prototype with a stack component,
  33. /// in which case the specifier was converted into a stack-specifier
  34. /// </summary>
  35. public bool Converted;
  36. public EntitySpecifier(string prototype, int quantity, bool converted = false)
  37. {
  38. Assert.That(quantity, Is.GreaterThan(0));
  39. Prototype = prototype;
  40. Quantity = quantity;
  41. Converted = converted;
  42. }
  43. public static implicit operator EntitySpecifier(string prototype)
  44. => new(prototype, 1);
  45. public static implicit operator EntitySpecifier((string, int) tuple)
  46. => new(tuple.Item1, tuple.Item2);
  47. /// <summary>
  48. /// Convert applicable entity prototypes into stack prototypes.
  49. /// </summary>
  50. public async Task ConvertToStack(IPrototypeManager protoMan, IComponentFactory factory, ServerIntegrationInstance server)
  51. {
  52. if (Converted)
  53. return;
  54. Converted = true;
  55. if (string.IsNullOrWhiteSpace(Prototype))
  56. return;
  57. if (protoMan.HasIndex<StackPrototype>(Prototype))
  58. return;
  59. if (!protoMan.TryIndex<EntityPrototype>(Prototype, out var entProto))
  60. {
  61. Assert.Fail($"Unknown prototype: {Prototype}");
  62. return;
  63. }
  64. StackComponent? stack = null;
  65. await server.WaitPost(() =>
  66. {
  67. entProto.TryGetComponent(factory.GetComponentName(typeof(StackComponent)), out stack);
  68. });
  69. if (stack != null)
  70. Prototype = stack.StackTypeId;
  71. }
  72. }
  73. protected async Task<EntityUid> SpawnEntity(EntitySpecifier spec, EntityCoordinates coords)
  74. {
  75. EntityUid uid = default!;
  76. if (ProtoMan.TryIndex<StackPrototype>(spec.Prototype, out var stackProto))
  77. {
  78. await Server.WaitPost(() =>
  79. {
  80. uid = SEntMan.SpawnEntity(stackProto.Spawn, coords);
  81. Stack.SetCount(uid, spec.Quantity);
  82. });
  83. return uid;
  84. }
  85. if (!ProtoMan.TryIndex<EntityPrototype>(spec.Prototype, out var entProto))
  86. {
  87. Assert.Fail($"Unknown prototype: {spec.Prototype}");
  88. return default;
  89. }
  90. StackComponent? stack = null;
  91. await Server.WaitPost(() =>
  92. {
  93. entProto.TryGetComponent(Factory.GetComponentName(typeof(StackComponent)), out stack);
  94. });
  95. if (stack != null)
  96. return await SpawnEntity((stack.StackTypeId, spec.Quantity), coords);
  97. Assert.That(spec.Quantity, Is.EqualTo(1), "SpawnEntity only supports returning a singular entity");
  98. await Server.WaitPost(() => uid = SEntMan.SpawnAtPosition(spec.Prototype, coords));
  99. return uid;
  100. }
  101. /// <summary>
  102. /// Convert an entity-uid to a matching entity specifier. Useful when doing entity lookups & checking that the
  103. /// right quantity of entities/materials were produced. Returns null if passed an entity with a null prototype.
  104. /// </summary>
  105. protected EntitySpecifier? ToEntitySpecifier(EntityUid uid)
  106. {
  107. if (SEntMan.TryGetComponent(uid, out StackComponent? stack))
  108. return new EntitySpecifier(stack.StackTypeId, stack.Count) { Converted = true };
  109. var meta = SEntMan.GetComponent<MetaDataComponent>(uid);
  110. if (meta.EntityPrototype is null)
  111. return null;
  112. return new(meta.EntityPrototype.ID, 1) { Converted = true };
  113. }
  114. }