public bool TryDoCommand(Players.Player causedBy, string chattext, List <string> splits)
        {
            if (!splits[0].Equals("/lastseen"))
            {
                return(false);
            }
            var m = Regex.Match(chattext, @"/lastseen (?<playername>['].+[']|[^ ]+)");

            if (!m.Success)
            {
                Chat.Send(causedBy, "Command didn't match, use /lastseen [playername]");
                return(true);
            }
            var targetPlayerName = m.Groups ["playername"].Value;

            Players.Player targetPlayer;
            string         error;

            if (!PlayerHelper.TryGetPlayer(targetPlayerName, out targetPlayer, out error, true))
            {
                Chat.Send(causedBy, $"Could not find player '{targetPlayerName}'; {error}");
                return(true);
            }
            var lastSeen = ActivityTracker.GetLastSeen(targetPlayer.ID.ToStringReadable());

            Chat.Send(causedBy, $"Player {targetPlayer.ID.ToStringReadable()} last seen {lastSeen}");
            return(true);
        }
        // time played is always player based, no colony version needed
        public Dictionary <string, int> ScoreByTime(List <Players.Player> players)
        {
            Dictionary <string, int> results = new Dictionary <string, int>();

            foreach (Players.Player player in players)
            {
                long seconds = ActivityTracker.GetOrCreateStats(player.ID.ToStringReadable()).secondsPlayed;
                results[player.Name] = (int)(seconds / 60);
            }
            return(results);
        }
        public bool TryDoCommand(Players.Player causedBy, string chattext, List <string> splits)
        {
            if (!splits[0].Equals("/inactive"))
            {
                return(false);
            }
            if (!PermissionsManager.CheckAndWarnPermission(causedBy, AntiGrief.MOD_PREFIX + "inactive"))
            {
                return(true);
            }
            int days;

            if (splits.Count == 2)
            {
                if (!int.TryParse(splits[1], out days))
                {
                    Chat.Send(causedBy, $"Could not parse days value");
                    return(true);
                }
            }
            else
            {
                Chat.Send(causedBy, "Syntax: /inactive {days}");
                return(true);
            }

            string resultMsg = "";
            int    counter   = 0;

            foreach (KeyValuePair <Players.Player, int> entry in ActivityTracker.GetInactivePlayers(days))
            {
                Players.Player player       = entry.Key;
                int            inactiveDays = entry.Value;
                if (resultMsg.Length > 0)
                {
                    resultMsg += ", ";
                }
                resultMsg += $"{player.ID.ToStringReadable()}({inactiveDays})";
                counter++;
            }
            if (counter == 0)
            {
                resultMsg = "No inactive players found";
            }
            else
            {
                resultMsg += $". In total {counter} players";
            }
            Chat.Send(causedBy, resultMsg);
            return(true);
        }
        public bool TryDoCommand(Players.Player causedBy, string chattext, List <string> splits)
        {
            if (!splits[0].Equals("/list"))
            {
                return(false);
            }
            Match m = Regex.Match(chattext, @"/list (?<playername>['].+[']|[^ ]+)");

            if (!m.Success)
            {
                Chat.Send(causedBy, "Syntax: /list {playername}");
                return(true);
            }
            if (!PermissionsManager.CheckAndWarnPermission(causedBy, AntiGrief.MOD_PREFIX + "listplayer"))
            {
                return(true);
            }

            string targetName = m.Groups["playername"].Value;
            string error;

            Players.Player targetPlayer;
            if (!PlayerHelper.TryGetPlayer(targetName, out targetPlayer, out error, true))
            {
                Chat.Send(causedBy, $"Could not find '{targetName}'; {error}");
                return(true);
            }

            string lastSeen = ActivityTracker.GetLastSeen(targetPlayer.ID.ToStringReadable());
            string colonies = "";
            int    count    = 0;

            for (int i = 0; i < targetPlayer.Colonies.Length; i++)
            {
                if (!colonies.Equals(""))
                {
                    colonies += ", ";
                }
                colonies += targetPlayer.Colonies[i].Name;
                count++;
            }

            Chat.Send(causedBy, $"Player {targetPlayer.Name} last seen {lastSeen}");
            Chat.Send(causedBy, $"{targetPlayer.Name} owns {count} colonies: {colonies}");
            return(true);
        }
        public bool TryDoCommand(Players.Player causedBy, string chattext, List <string> splits)
        {
            if (!splits[0].Equals("/purgebanner"))
            {
                return(false);
            }
            if (!PermissionsManager.CheckAndWarnPermission(causedBy, AntiGrief.MOD_PREFIX + "purgebanner"))
            {
                return(true);
            }

            // command: /purgebanner all <range> (Purge ALL colonies within range)
            if (splits.Count == 3 && splits[1].Equals("all"))
            {
                if (!PermissionsManager.CheckAndWarnPermission(causedBy, AntiGrief.MOD_PREFIX + "purgeallbanner"))
                {
                    return(true);
                }
                int range = 0;
                if (!int.TryParse(splits[2], out range))
                {
                    Chat.Send(causedBy, "Syntax: /purgebanner all <range>");
                    return(true);
                }
                int counter = PurgeAllColonies(causedBy, range);
                Chat.Send(causedBy, $"Purged {counter} colonies within range");
                return(true);
            }

            // command: /purgebanner days <minage> (Purge ALL colonies from inactive players)
            if (splits.Count == 3 && splits[1].Equals("days"))
            {
                if (!PermissionsManager.CheckAndWarnPermission(causedBy, AntiGrief.MOD_PREFIX + "purgeallbanner"))
                {
                    return(true);
                }
                int minage = int.MaxValue;
                if (!int.TryParse(splits[2], out minage))
                {
                    Chat.Send(causedBy, "Syntax: /purgebanner days <minage>");
                    return(true);
                }

                int counter = 0;
                foreach (KeyValuePair <Players.Player, int> entry in ActivityTracker.GetInactivePlayers(minage))
                {
                    Players.Player player = entry.Key;
                    counter += PurgePlayerColonies(causedBy, player);
                }
                Chat.Send(causedBy, $"Purged {counter} colonies from inactive players");
                return(true);
            }

            Colony colony = null;

            BannerTracker.Banner banner = null;
            int shortestDistance        = int.MaxValue;

            foreach (Colony checkColony in ServerManager.ColonyTracker.ColoniesByID.Values)
            {
                foreach (BannerTracker.Banner checkBanner in checkColony.Banners)
                {
                    int distX    = (int)(causedBy.Position.x - checkBanner.Position.x);
                    int distZ    = (int)(causedBy.Position.z - checkBanner.Position.z);
                    int distance = (int)System.Math.Sqrt(System.Math.Pow(distX, 2) + System.Math.Pow(distZ, 2));
                    if (distance < shortestDistance)
                    {
                        shortestDistance = distance;
                        banner           = checkBanner;
                        colony           = checkColony;
                    }
                }
            }

            if (banner == null)
            {
                Chat.Send(causedBy, "No banners found at all");
                return(true);
            }
            if (shortestDistance > 100)
            {
                Chat.Send(causedBy, "Closest banner is more than 100 blocks away. Not doing anything, too risky");
                return(true);
            }

            // command: /purgebanner { colony | <playername> }
            if (splits.Count == 2)
            {
                if (splits[1].Equals("colony") && colony != null)
                {
                    PurgeColony(causedBy, colony);
                }
                else
                {
                    PurgePlayerFromColonies(causedBy, splits[1]);
                    Chat.Send(causedBy, $"Freed {splits[1]} from any colonies");
                }
                return(true);
            }

            if (colony.Banners.Length > 1)
            {
                ServerManager.ClientCommands.DeleteBannerTo(causedBy, colony, banner.Position);
                Chat.Send(causedBy, $"Deleted banner at {banner.Position.x},{banner.Position.z}. Colony still has more banners");
            }
            else
            {
                ServerManager.ClientCommands.DeleteColonyAndBanner(causedBy, colony, banner.Position);
                Chat.Send(causedBy, $"Deleted banner at {banner.Position.x},{banner.Position.z} and also the colony.");
            }
            return(true);
        }