BodyPrototypeSerializer.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. using System.Linq;
  2. using Content.Shared.Body.Organ;
  3. using Content.Shared.Prototypes;
  4. using Robust.Shared.Prototypes;
  5. using Robust.Shared.Serialization;
  6. using Robust.Shared.Serialization.Manager;
  7. using Robust.Shared.Serialization.Markdown.Mapping;
  8. using Robust.Shared.Serialization.Markdown.Sequence;
  9. using Robust.Shared.Serialization.Markdown.Validation;
  10. using Robust.Shared.Serialization.Markdown.Value;
  11. using Robust.Shared.Serialization.TypeSerializers.Interfaces;
  12. namespace Content.Shared.Body.Prototypes;
  13. [TypeSerializer]
  14. public sealed class BodyPrototypeSerializer : ITypeReader<BodyPrototype, MappingDataNode>
  15. {
  16. private (ValidationNode Node, List<string> Connections) ValidateSlot(MappingDataNode slot, IDependencyCollection dependencies)
  17. {
  18. var nodes = new List<ValidationNode>();
  19. var prototypes = dependencies.Resolve<IPrototypeManager>();
  20. var factory = dependencies.Resolve<IComponentFactory>();
  21. var connections = new List<string>();
  22. if (slot.TryGet("connections", out SequenceDataNode? connectionsNode))
  23. {
  24. foreach (var node in connectionsNode)
  25. {
  26. if (node is not ValueDataNode connection)
  27. {
  28. nodes.Add(new ErrorNode(node, $"Connection is not a value data node"));
  29. continue;
  30. }
  31. connections.Add(connection.Value);
  32. }
  33. }
  34. if (slot.TryGet("organs", out MappingDataNode? organsNode))
  35. {
  36. foreach (var (key, value) in organsNode)
  37. {
  38. if (key is not ValueDataNode)
  39. {
  40. nodes.Add(new ErrorNode(key, $"Key is not a value data node"));
  41. continue;
  42. }
  43. if (value is not ValueDataNode organ)
  44. {
  45. nodes.Add(new ErrorNode(value, $"Value is not a value data node"));
  46. continue;
  47. }
  48. if (!prototypes.TryIndex(organ.Value, out EntityPrototype? organPrototype))
  49. {
  50. nodes.Add(new ErrorNode(value, $"No organ entity prototype found with id {organ.Value}"));
  51. continue;
  52. }
  53. if (!organPrototype.HasComponent<OrganComponent>(factory))
  54. {
  55. nodes.Add(new ErrorNode(value, $"Organ {organ.Value} does not have a body component"));
  56. }
  57. }
  58. }
  59. var validation = new ValidatedSequenceNode(nodes);
  60. return (validation, connections);
  61. }
  62. public ValidationNode Validate(ISerializationManager serializationManager, MappingDataNode node,
  63. IDependencyCollection dependencies, ISerializationContext? context = null)
  64. {
  65. var nodes = new List<ValidationNode>();
  66. if (!node.TryGet("root", out ValueDataNode? root))
  67. nodes.Add(new ErrorNode(node, $"No root value data node found"));
  68. if (!node.TryGet("slots", out MappingDataNode? slots))
  69. {
  70. nodes.Add(new ErrorNode(node, $"No slots mapping data node found"));
  71. }
  72. else if (root != null)
  73. {
  74. if (!slots.TryGet(root.Value, out MappingDataNode? _))
  75. {
  76. nodes.Add(new ErrorNode(slots, $"No slot found with id {root.Value}"));
  77. return new ValidatedSequenceNode(nodes);
  78. }
  79. foreach (var (key, value) in slots)
  80. {
  81. if (key is not ValueDataNode)
  82. {
  83. nodes.Add(new ErrorNode(key, $"Key is not a value data node"));
  84. continue;
  85. }
  86. if (value is not MappingDataNode slot)
  87. {
  88. nodes.Add(new ErrorNode(value, $"Slot is not a mapping data node"));
  89. continue;
  90. }
  91. var result = ValidateSlot(slot, dependencies);
  92. nodes.Add(result.Node);
  93. foreach (var connection in result.Connections)
  94. {
  95. if (!slots.TryGet(connection, out MappingDataNode? _))
  96. nodes.Add(new ErrorNode(slots, $"No slot found with id {connection}"));
  97. }
  98. }
  99. }
  100. return new ValidatedSequenceNode(nodes);
  101. }
  102. public BodyPrototype Read(ISerializationManager serializationManager, MappingDataNode node,
  103. IDependencyCollection dependencies,
  104. SerializationHookContext hookCtx, ISerializationContext? context = null,
  105. ISerializationManager.InstantiationDelegate<BodyPrototype>? instanceProvider = null)
  106. {
  107. var id = node.Get<ValueDataNode>("id").Value;
  108. var name = node.Get<ValueDataNode>("name").Value;
  109. var root = node.Get<ValueDataNode>("root").Value;
  110. var slotNodes = node.Get<MappingDataNode>("slots");
  111. var allConnections = new Dictionary<string, (string? Part, HashSet<string>? Connections, Dictionary<string, string>? Organs)>();
  112. foreach (var (keyNode, valueNode) in slotNodes)
  113. {
  114. var slotId = ((ValueDataNode) keyNode).Value;
  115. var slot = ((MappingDataNode) valueNode);
  116. string? part = null;
  117. if (slot.TryGet<ValueDataNode>("part", out var value))
  118. {
  119. part = value.Value;
  120. }
  121. HashSet<string>? connections = null;
  122. if (slot.TryGet("connections", out SequenceDataNode? slotConnectionsNode))
  123. {
  124. connections = new HashSet<string>();
  125. foreach (var connection in slotConnectionsNode.Cast<ValueDataNode>())
  126. {
  127. connections.Add(connection.Value);
  128. }
  129. }
  130. Dictionary<string, string>? organs = null;
  131. if (slot.TryGet("organs", out MappingDataNode? slotOrgansNode))
  132. {
  133. organs = new Dictionary<string, string>();
  134. foreach (var (organKeyNode, organValueNode) in slotOrgansNode)
  135. {
  136. organs.Add(((ValueDataNode) organKeyNode).Value, ((ValueDataNode) organValueNode).Value);
  137. }
  138. }
  139. allConnections.Add(slotId, (part, connections, organs));
  140. }
  141. foreach (var (slotId, (_, connections, _)) in allConnections)
  142. {
  143. if (connections == null)
  144. continue;
  145. foreach (var connection in connections)
  146. {
  147. var other = allConnections[connection];
  148. other.Connections ??= new HashSet<string>();
  149. other.Connections.Add(slotId);
  150. allConnections[connection] = other;
  151. }
  152. }
  153. var slots = new Dictionary<string, BodyPrototypeSlot>();
  154. foreach (var (slotId, (part, connections, organs)) in allConnections)
  155. {
  156. var slot = new BodyPrototypeSlot(part, connections ?? new HashSet<string>(), organs ?? new Dictionary<string, string>());
  157. slots.Add(slotId, slot);
  158. }
  159. return new BodyPrototype(id, name, root, slots);
  160. }
  161. }