using System; using System.Collections.Generic; namespace Robust.Shared.Prototypes { public sealed class PrototypeInheritanceTree { private Dictionary> _nodes = new(); private Dictionary> _pendingParent = new(); private HashSet _baseNodes = new(); private Dictionary _parents = new(); public IReadOnlySet BaseNodes => _baseNodes; public IReadOnlySet Children(string id) { if (!_nodes.ContainsKey(id)) throw new ArgumentException($"ID {id} not present in InheritanceTree", nameof(id)); return _nodes[id]; } public string GetBaseNode(string id) { if (!_nodes.ContainsKey(id)) throw new ArgumentException($"ID {id} not present in InheritanceTree", nameof(id)); var parent = id; while (_parents.TryGetValue(parent, out var nextParent)) { parent = nextParent; } return parent; } public string? GetParent(string id) { return _parents.GetValueOrDefault(id); } public void AddId(string id, string? parent, bool overwrite = false) { if (overwrite && HasId(id)) { RemoveId(id); } if (_nodes.ContainsKey(id)) throw new ArgumentException($"ID {id} already present in InheritanceTree", nameof(id)); if (parent != null) { _parents.Add(id, parent); if (_nodes.TryGetValue(parent, out var parentsChildren)) { parentsChildren.Add(id); } else { if (!_pendingParent.TryGetValue(parent, out _)) { _pendingParent[parent] = new HashSet(); } _pendingParent[parent].Add(id); } //cycle detection var currentParent = parent; while (currentParent != null) { if (currentParent == id) throw new InvalidOperationException( $"Cycle detected when trying to add id {id} with parent {parent}"); _parents.TryGetValue(currentParent, out currentParent); } } else { _baseNodes.Add(id); } if (!_pendingParent.TryGetValue(id, out var ourChildren)) ourChildren = new HashSet(); _nodes.Add(id, ourChildren); } public bool HasId(string id) { return _nodes.ContainsKey(id); } public void RemoveId(string id) { if (!_nodes.ContainsKey(id)) throw new ArgumentException($"ID {id} not present in InheritanceTree", nameof(id)); _nodes.Remove(id); foreach (var (_, children) in _pendingParent) { children.Remove(id); } _baseNodes.Remove(id); _parents.Remove(id); } } }