using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using Robust.Shared.ViewVariables; using System.Collections.Generic; using System.Diagnostics; using System.Linq; namespace Content.Server.GameObjects.Components.NodeContainer.Nodes { /// /// Organizes themselves into distinct s with other s /// that they can "reach" and have the same . /// public abstract class Node { /// /// An ID used as a criteria for combining into groups. Determines which /// implementation is used as a group, detailed in . /// [ViewVariables] public NodeGroupID NodeGroupID { get; private set; } [ViewVariables] public INodeGroup NodeGroup { get => _nodeGroup; set => SetNodeGroup(value); } private INodeGroup _nodeGroup = BaseNodeGroup.NullGroup; [ViewVariables] public IEntity Owner { get; private set; } private bool _needsGroup = true; private bool _deleting = false; #pragma warning disable 649 [Dependency] private readonly INodeGroupFactory _nodeGroupFactory; #pragma warning restore 649 public void Initialize(NodeGroupID nodeGroupID, IEntity owner) { NodeGroupID = nodeGroupID; Owner = owner; } public void OnContainerInitialize() { TryAssignGroupIfNeeded(); CombineGroupWithReachable(); } public void OnContainerRemove() { _deleting = true; NodeGroup.RemoveNode(this); } public bool TryAssignGroupIfNeeded() { if (!_needsGroup) { return false; } NodeGroup = GetReachableCompatibleGroups().FirstOrDefault() ?? MakeNewGroup(); return true; } public void StartSpreadingGroup() { NodeGroup.BeforeRemakeSpread(); SpreadGroup(); NodeGroup.AfterRemakeSpread(); } public void SpreadGroup() { Debug.Assert(!_needsGroup); foreach (var node in GetReachableCompatibleNodes().Where(node => node._needsGroup == true)) { node.NodeGroup = NodeGroup; node.SpreadGroup(); } } public void ClearNodeGroup() { _nodeGroup = BaseNodeGroup.NullGroup; _needsGroup = true; } /// /// How this node will attempt to find other reachable s to group with. /// Returns a set of s to consider grouping with. Should not return this current . /// protected abstract IEnumerable GetReachableNodes(); private IEnumerable GetReachableCompatibleNodes() { return GetReachableNodes().Where(node => node.NodeGroupID == NodeGroupID) .Where(node => node._deleting == false); } private IEnumerable GetReachableCompatibleGroups() { return GetReachableCompatibleNodes().Where(node => node._needsGroup == false) .Select(node => node.NodeGroup) .Where(group => group != NodeGroup); } private void CombineGroupWithReachable() { Debug.Assert(!_needsGroup); foreach (var group in GetReachableCompatibleGroups()) { NodeGroup.CombineGroup(group); } } private void SetNodeGroup(INodeGroup newGroup) { _nodeGroup = newGroup; NodeGroup.AddNode(this); _needsGroup = false; } private INodeGroup MakeNewGroup() { return _nodeGroupFactory.MakeNodeGroup(NodeGroupID); } } }