// Public
        public override void OnCommandGroupCreated(CommandGroup group)
        {
            var commonData = new CommonGroupData();

            group.AddCustomData(commonData);

            var rememberedPathStates = new RememberedPathStates(group.Units.Count);

            group.AddCustomData(rememberedPathStates);

            if (group is PatrolGroup)
            {
                var data = new PatrolData(group.Units);
                group.AddCustomData(data);
                group.OnUnitsWillBeRemoved += (evnt) =>
                {
                    data.RemoveRange(evnt.UnitsIndices);
                };
            }

            group.OnUnitsWillBeRemoved += (evnt) =>
            {
                rememberedPathStates.RemoveRange(evnt.UnitsIndices);
                commonData.Reset();
            };
        }
        public override void OnUpdate(CommandGroup group)
        {
            var commonData = group.GetCustomData <CommonGroupData>();

            commonData.Update(group.Units, 0);
            var commander = commonData.Commander;

            var         targetPos      = Vector3.zero;
            var         mayUpdatePaths = commonData.NewCommander && !commander.Paths.CurrentPath;
            IMovable    movable        = null;
            PatrolData  patrolData     = null;
            PatrolGroup patrolGroup    = null;

            if (group is GoToGroup)
            {
                var goToGroup = group as GoToGroup;
                targetPos = goToGroup.Destination;
            }
            else if (group is FollowGroup)
            {
                var followGroup = group as FollowGroup;
                targetPos = followGroup.Target.transform.position;
                movable   = followGroup.Target.GetComponent <IMovable>();
            }
            else if (group is AttackGroup)
            {
                var attackGroup = group as AttackGroup;
                targetPos = attackGroup.Target.Position;
                movable   = attackGroup.Target.GameObject.GetComponent <IMovable>();
            }
            else if (group is PatrolGroup)
            {
                patrolGroup    = group as PatrolGroup;
                targetPos      = patrolGroup.Destination;
                patrolData     = patrolGroup.GetCustomData <PatrolData>(false);
                mayUpdatePaths = !patrolData.HasGeneratedPaths;
                if (!patrolData.HasGeneratedPaths)
                {
                    patrolData.HasGeneratedPaths = true;
                }
            }

            if (movable != null)
            {
                mayUpdatePaths |= movable.Velocity != Vector3.zero;
            }

            if (mayUpdatePaths)
            {
                SetCommanderPath(commonData, targetPos);
                EnsureNextNodeIsReachable(commander);

                if (group.Units.Count > 0)
                {
                    SetUnitPaths(commonData, group.Units);
                }
            }

            var rememberedPathStates = group.GetCustomData <RememberedPathStates>();

            for (int i = 0; i < group.Units.Count; i++)
            {
                var unit        = group.Units[i];
                var currentPath = unit.Paths.CurrentPath;
                if (currentPath && !currentPath.Traversed)
                {
                    var lastPathState = rememberedPathStates.LastPathState[i];
                    if (currentPath.NextNodeIndex != lastPathState?.LastNextNodeIndex ||
                        currentPath != lastPathState?.LastCurrentPath)
                    {
                        EnsureNextNodeIsReachable(unit);
                    }
                }
                else if (patrolGroup && !currentPath)
                {
                    var reversedPath = new Path(new Vector3[] { patrolData.SourcePosition[i] });
                    patrolData.SourcePosition[i] = unit.Unit.Position;
                    unit.Paths.PushPath(reversedPath);
                    EnsureNextNodeIsReachable(unit);
                }
            }

            rememberedPathStates.Update(group.Units);
        }