static BlockDBUndoArgs ParseBlockDBUndoParams([NotNull] Player player, [NotNull] CommandReader cmd,
[NotNull] string cmdName, bool not) {
if (player == null) throw new ArgumentNullException("player");
if (cmd == null) throw new ArgumentNullException("cmd");
if (cmdName == null) throw new ArgumentNullException("cmdName");
// check if command's being called by a worldless player (e.g. console)
World playerWorld = player.World;
if (playerWorld == null) PlayerOpException.ThrowNoWorld(player);
// ensure that BlockDB is enabled
if (!BlockDB.IsEnabledGlobally) {
player.Message("&W{0}: BlockDB is disabled on this server.", cmdName);
return null;
}
if (!playerWorld.BlockDB.IsEnabled) {
player.Message("&W{0}: BlockDB is disabled in this world.", cmdName);
return null;
}
// parse the first parameter - either numeric or time limit
string range = cmd.Next();
if (range == null) {
CdUndoPlayer.PrintUsage(player);
return null;
}
int countLimit;
TimeSpan ageLimit = TimeSpan.Zero;
if (!Int32.TryParse(range, out countLimit) && !range.TryParseMiniTimeSpan(out ageLimit)) {
player.Message("{0}: First parameter should be a number or a timespan.", cmdName);
return null;
}
if (ageLimit > DateTimeUtil.MaxTimeSpan) {
player.MessageMaxTimeSpan();
return null;
}
// parse second and consequent parameters (player names)
HashSet<PlayerInfo> targets = new HashSet<PlayerInfo>();
bool allPlayers = false;
while (true) {
string name = cmd.Next();
if (name == null) {
break;
} else if (name == "*") {
// all players
if (not) {
player.Message("{0}: \"*\" not allowed (cannot undo \"everyone except everyone\")", cmdName);
return null;
}
if (allPlayers) {
player.Message("{0}: \"*\" was listed twice.", cmdName);
return null;
}
allPlayers = true;
} else {
// individual player
PlayerInfo target = PlayerDB.FindPlayerInfoOrPrintMatches(player, name, SearchOptions.IncludeSelf);
if (target == null) {
return null;
}
if (targets.Contains(target)) {
player.Message("{0}: Player {1}&S was listed twice.",
target.ClassyName,
cmdName);
return null;
}
// make sure player has the permission
if (!not &&
player.Info != target && !player.Can(Permission.UndoAll) &&
!player.Can(Permission.UndoOthersActions, target.Rank)) {
player.Message("&W{0}: You may only undo actions of players ranked {1}&S or lower.",
cmdName,
player.Info.Rank.GetLimit(Permission.UndoOthersActions).ClassyName);
player.Message("Player {0}&S is ranked {1}",
target.ClassyName,
target.Rank.ClassyName);
return null;
}
targets.Add(target);
}
}
if (targets.Count == 0 && !allPlayers) {
player.Message("{0}: Specify at least one player name, or \"*\" to undo everyone.", cmdName);
return null;
}
if (targets.Count > 0 && allPlayers) {
player.Message("{0}: Cannot mix player names and \"*\".", cmdName);
return null;
}
// undoing everyone ('*' in place of player name) requires UndoAll permission
if ((not || allPlayers) && !player.Can(Permission.UndoAll)) {
player.MessageNoAccess(Permission.UndoAll);
return null;
}
// Queue UndoPlayerCallback to run
return new BlockDBUndoArgs {
Player = player,
AgeLimit = ageLimit,
CountLimit = countLimit,
Area = player.WorldMap.Bounds,
World = playerWorld,
Targets = targets.ToArray(),
Not = not
};
}