public void OnSimUpdated(FrameSnapshot frame, float interpolation, bool replay)
        {
            if (!replay)
            {
                // Don't update selections from sim during play, it's controlled via direct user input
                return;
            }

            // Do update selections during replay

            // @TODO: determine which entities were actually updated last tick and only loop through them (raise event when SimSystem makes update?)
            SimSelectable[] simSelections = frame.Snapshot.GetComponents <SimSelectable>().Where(s => s.Selected).ToArray();
            if (simSelections.Length <= 0)
            {
                Clear();
                return;
            }
            List <SelectableComponent> remainingSelections = Selected.ToList();

            for (int i = 0; i < simSelections.Length; i++)
            {
                SelectableComponent selection = GameState.GetGameObject(simSelections[i].EntityID).GameObject.GetComponent <SelectableComponent>();
                remainingSelections.Remove(selection);
                Select(selection, true);
            }
            foreach (SelectableComponent deselect in remainingSelections)
            {
                deselect.Deselect();
            }
        }
        protected void SelectActionAtScreenPosition(Vector2 position, bool multi)
        {
            Vector2             worldPosition = UnityEngine.Camera.main.ScreenToWorldPoint(position);
            RaycastHit2D        hit           = Physics2D.Raycast(worldPosition, Vector2.zero);
            SelectableComponent selection     = hit.transform?.gameObject.GetComponent <SelectableComponent>();

            UpdateSelections(selection, multi);
        }
 protected void UpdateSelections(SelectableComponent selection, bool multi)
 {
     if (IsSelected(selection) && (multi || Selected.Any()))
     {
         Deselect(selection, multi);
     }
     else
     {
         Select(selection, multi);
     }
 }
 protected void Deselect(SelectableComponent selection, bool multi)
 {
     if (!multi)
     {
         Clear();
     }
     if (!IsSelected(selection))
     {
         return;
     }
     Selected.Remove(selection);
     selection.Deselect();
     InvokeEvent(SelectAction.Deselected, selection, multi);
 }
 public void Clear(SelectableComponent ignore = null)
 {
     if (Selected.Count <= 0)
     {
         return;
     }
     foreach (SelectableComponent selected in Selected)
     {
         if (selected != ignore)
         {
             selected.Deselect();
         }
     }
     Selected.Clear();
     InvokeEvent(SelectAction.Cleared);
 }
 public void Select(SelectableComponent selection, bool multi)
 {
     if (!multi)
     {
         Clear(Selected.Count == 1 ? selection : null);
     }
     if (selection == null)
     {
         return;
     }
     if (IsSelected(selection))
     {
         return;
     }
     Selected.Add(selection);
     selection.Select();
     InvokeEvent(SelectAction.Selected, selection, multi);
 }
 public bool IsSelected(SelectableComponent selectable)
 {
     return(selectable == null ? false : Selected.Contains(selectable));
 }
 private void InvokeEvent(SelectAction action, SelectableComponent selection = null, bool multi = false)
 {
     OnSelectionUpdated?.Invoke(new SelectionUpdatedEvent(action, selection?.GetComponent <Simulation.SimEntityComponent>().EntityID ?? 0, multi));
 }