Upgrade tempranks to new format. Allows temp ranking accurately to exact secons (addresses #277), also ranking deletes temprank, fixes #349

This commit is contained in:
UnknownShadow200 2017-06-04 18:35:26 +10:00
parent 67503ef02a
commit 4b08765c49
13 changed files with 189 additions and 103 deletions

View File

@ -89,10 +89,11 @@ namespace MCGalaxy.Commands.Moderation {
MessageTooHighRank(p, "change the rank of", false); return false;
}
if (p != null && newRank.Permission >= p.Rank) {
Player.Message(p, "Can only rank up to below {0}", newRank.ColoredName); return false;
Player.Message(p, "Cannot rank a player to a rank equal to or higher than yours."); return false;
}
if (p != null && newRank.Permission >= p.Rank) {
Player.Message(p, "Cannot change the rank of a player to a rank equal or higher to yours."); return false;
if (newRank.Permission == curRank.Permission) {
Player.Message(p, "{0} %Sis already ranked {1}.",
PlayerInfo.GetColoredName(p, name), curRank.ColoredName); return false;
}
if (who == null) return true;

View File

@ -60,7 +60,7 @@ namespace MCGalaxy.Commands.Moderation {
TimeSpan duration = TimeSpan.Zero;
if (!CommandParser.GetTimespan(p, args[2], ref duration, "temp rank for", 'h')) return;
foreach (string line in Server.TempRanks.Find(target)) {
if (Server.tempRanks.Contains(target)) {
Player.Message(p, "&cThe player already has a temporary rank assigned!"); return;
}
@ -78,72 +78,70 @@ namespace MCGalaxy.Commands.Moderation {
}
static void Delete(Player p, string target) {
bool assigned = false;
StringBuilder all = new StringBuilder();
Player who = PlayerInfo.FindExact(target);
Group curRank = who != null ? who.group : Group.findPlayerGroup(target);
string reason = "temp rank unassigned";
foreach (string line in File.ReadAllLines(Paths.TempRanksFile)) {
if (!line.CaselessStarts(target)) { all.AppendLine(line); continue; }
string line = Server.tempRanks.FindData(target);
if (line == null) {
Player.Message(p, "{0}&c has not been assigned a temp rank.",
PlayerInfo.GetColoredName(p, target));
return;
}
string[] parts = line.SplitSpaces();
Group newRank = Group.Find(parts[2]);
if (!CmdSetRank.CanChangeRank(target, curRank, newRank, who, p, ref reason)) return;
Player who = PlayerInfo.FindExact(target);
Group curRank = who != null ? who.group : Group.findPlayerGroup(target);
Group oldRank = Group.Find(parts[4 - 1]); // -1 because data, not whole line
// Old rank was deleted, can't revert rank
if (oldRank == null) {
Server.tempRanks.Remove(target);
return;
}
string reason = "temp rank unassigned";
if (!CmdSetRank.CanChangeRank(target, curRank, oldRank, who, p, ref reason)) return;
ModAction action = new ModAction(target, p, ModActionType.Rank, reason);
action.Metadata = newRank;
action.Metadata = oldRank;
action.targetGroup = curRank;
OnModActionEvent.Call(action);
assigned = true;
}
if (!assigned) {
Player.Message(p, "&a{0}&c has not been assigned a temp rank.", target); return;
}
File.WriteAllText(Paths.TempRanksFile, all.ToString());
}
static void Info(Player p, string name) {
List<string> rankings = Server.TempRanks.FindMatches(p, name, "temp rank");
if (rankings == null) return;
foreach (string line in rankings) {
PrintTempRankInfo(p, line); return;
static void Info(Player p, string target) {
string line = Server.tempRanks.FindData(target);
if (line == null) {
Player.Message(p, "{0}&c has not been assigned a temp rank.",
PlayerInfo.GetColoredName(p, target));
} else {
PrintTempRankInfo(p, line);
}
}
static void List(Player p) {
int count = 0;
foreach (string line in File.ReadAllLines(Paths.TempRanksFile)) {
if (count == 0)
Player.Message(p, "&ePlayers with a temporary rank assigned:");
PrintTempRankInfo(p, line);
count++;
}
if (count == 0)
List<string> lines = Server.tempRanks.AllLines();
if (lines.Count == 0) {
Player.Message(p, "&cThere are no players with a temporary rank assigned.");
} else {
Player.Message(p, "&ePlayers with a temporary rank assigned:");
foreach (string line in lines) {
PrintTempRankInfo(p, line);
}
}
}
static void PrintTempRankInfo(Player p, string line) {
string[] args = line.SplitSpaces();
string tempRanker = args[9];
string tempRank = Group.GetColoredName(args[1]);
string oldRank = Group.GetColoredName(args[2]);
string assigner = args[1];
DateTime assigned = long.Parse(args[2]).FromUnixTime();
DateTime expiry = long.Parse(args[3]).FromUnixTime();
string oldRank = Group.GetColoredName(args[4]);
string tempRank = Group.GetColoredName(args[5]);
int min = int.Parse(args[4]), hour = int.Parse(args[5]);
int day = int.Parse(args[6]), month = int.Parse(args[7]), year = int.Parse(args[8]);
int periodH = int.Parse(args[3]), periodM = 0;
if (args.Length > 10) periodM = int.Parse(args[10]);
DateTime assigned = new DateTime(year, month, day, hour, min, 0);
DateTime expiry = assigned.AddHours(periodH).AddMinutes(periodM);
TimeSpan delta = DateTime.Now - assigned;
TimeSpan expireDelta = expiry - DateTime.Now;
Player.Message(p, "Temp rank information for {0}:", PlayerInfo.GetColoredName(p, args[0]));
TimeSpan assignDelta = DateTime.UtcNow - assigned;
TimeSpan expireDelta = expiry - DateTime.UtcNow;
Player.Message(p, "Temp rank information for {0}:",
PlayerInfo.GetColoredName(p, args[0]));
Player.Message(p, " From {0} %Sto {1}%S, by {2} &a{3} %Sago, expires in &a{4}",
oldRank, tempRank, tempRanker,
delta.Shorten(), expireDelta.Shorten());
oldRank, tempRank, assigner,
assignDelta.Shorten(), expireDelta.Shorten());
}
public override void Help(Player p) {

View File

@ -20,6 +20,7 @@ using System;
using MCGalaxy.Commands;
using MCGalaxy.Commands.Moderation;
using MCGalaxy.Events;
using MCGalaxy.Tasks;
namespace MCGalaxy.Core {
internal static class ModActionHandler {
@ -213,6 +214,10 @@ namespace MCGalaxy.Core {
if (who != null) {
who.SendMessage("You are now ranked " + newRank.ColoredName + "%S, type /help for your new set of commands.");
}
if (Server.tempRanks.Remove(e.Target)) {
ServerTasks.TemprankCalcNextRun();
Server.tempRanks.Save();
}
WriteRankInfo(e, newRank);
if (e.Duration != TimeSpan.Zero) AddTempRank(e, newRank);
@ -233,13 +238,14 @@ namespace MCGalaxy.Core {
}
static void AddTempRank(ModAction e, Group newRank) {
DateTime now = DateTime.Now;
long assign = DateTime.UtcNow.ToUnixTime();
long expiry = DateTime.UtcNow.Add(e.Duration).ToUnixTime();
string assigner = e.Actor == null ? "(console)" : e.Actor.name;
int hours = (int)e.Duration.TotalHours;
string data = e.Target + " " + newRank.name + " " + e.TargetGroup.name + " " + hours + " " + now.Minute + " " +
now.Hour + " " + now.Day + " " + now.Month + " " + now.Year + " " + assigner + " " + e.Duration.Minutes;
Server.TempRanks.Append(data);
string data = assigner + " " + assign + " " + expiry + " " + e.TargetGroup.name + " " + newRank.name;
Server.tempRanks.AddOrReplace(e.Target, data);
ServerTasks.TemprankCalcNextRun();
Server.tempRanks.Save();
}
}
}

View File

@ -32,7 +32,8 @@ namespace MCGalaxy {
public string Path;
List<string> names = new List<string>(), lines = new List<string>();
readonly object locker = new object(), saveLocker = new object();
internal readonly object locker = new object();
readonly object saveLocker = new object();
/// <summary> Returns a copy of all names in the list. </summary>
public List<string> AllNames() {

View File

@ -29,7 +29,8 @@ namespace MCGalaxy {
public string Path;
List<string> names = new List<string>();
readonly object locker = new object(), saveLocker = new object();
internal readonly object locker = new object();
readonly object saveLocker = new object();
public PlayerList() { }
public PlayerList(string path) { Path = path; }

View File

@ -58,7 +58,6 @@ namespace MCGalaxy {
public static PlayerExtList AutoloadMaps;
public static PlayerMetaList RankInfo = new PlayerMetaList("text/rankinfo.txt");
public static PlayerMetaList TempRanks = new PlayerMetaList("text/tempranks.txt");
public static PlayerMetaList Notes = new PlayerMetaList("text/notes.txt");
/// <summary> *** DO NOT USE THIS! *** Use VersionString, as this field is a constant and is inlined if used. </summary>
@ -81,7 +80,7 @@ namespace MCGalaxy {
public static CTFGame ctf = null;
public static PlayerList bannedIP, whiteList, ircControllers, muted, invalidIds;
public static PlayerList ignored, frozen, hidden, agreed, vip, noEmotes, lockdown;
public static PlayerExtList jailed, models, skins, reach, tempBans, rotations;
public static PlayerExtList jailed, models, skins, reach, tempBans, tempRanks, rotations;
public static readonly List<string> Devs = new List<string>(), Mods = new List<string>();

View File

@ -72,9 +72,12 @@ namespace MCGalaxy {
skins = PlayerExtList.Load("extra/skins.txt");
reach = PlayerExtList.Load("extra/reach.txt");
invalidIds = PlayerList.Load("extra/invalidids.txt");
tempBans = PlayerExtList.Load("text/tempbans.txt");
tempBans = PlayerExtList.Load(Paths.TempBansFile);
rotations = PlayerExtList.Load("extra/rotations.txt");
tempRanks = PlayerExtList.Load(Paths.TempRanksFile);
ServerTasks.TemprankCalcNextRun();
if (useWhitelist)
whiteList = PlayerList.Load("whitelist.txt");
}

View File

@ -116,11 +116,12 @@ namespace MCGalaxy {
Background.QueueOnce(LoadMainLevel);
Plugin.Load();
Background.QueueOnce(UpgradeTasks.UpgradeOldBlacklist);
Background.QueueOnce(LoadPlayerLists);
Background.QueueOnce(LoadAutoloadMaps);
Background.QueueOnce(UpgradeTasks.MovePreviousLevelFiles);
Background.QueueOnce(UpgradeTasks.UpgradeOldLockdown);
Background.QueueOnce(UpgradeTasks.UpgradeOldTempranks);
Background.QueueOnce(UpgradeTasks.UpgradeDBTimeSpent);
Background.QueueOnce(LoadPlayerLists);
Background.QueueOnce(SetupSocket);
Background.QueueOnce(InitTimers);
@ -131,15 +132,7 @@ namespace MCGalaxy {
Mods.Clear();
Background.QueueOnce(InitTasks.UpdateStaffList);
MainScheduler.QueueRepeat(ServerTasks.TemprankExpiry,
null, TimeSpan.FromMinutes(1));
MainScheduler.QueueRepeat(ServerTasks.CheckState,
null, TimeSpan.FromSeconds(3));
Background.QueueRepeat(ServerTasks.AutoSave,
1, TimeSpan.FromSeconds(Server.backupInterval));
Background.QueueRepeat(ServerTasks.BlockUpdates,
null, TimeSpan.FromSeconds(Server.blockInterval));
ServerTasks.QueueTasks();
Background.QueueRepeat(ThreadSafeCache.DBCache.CleanupTask,
null, TimeSpan.FromMinutes(5));
}
@ -159,7 +152,6 @@ namespace MCGalaxy {
if (!Directory.Exists("levels")) Directory.CreateDirectory("levels");
if (!Directory.Exists("bots")) Directory.CreateDirectory("bots");
if (!Directory.Exists("text")) Directory.CreateDirectory("text");
TempRanks.EnsureExists();
RankInfo.EnsureExists();
Ban.EnsureExists();

View File

@ -17,6 +17,7 @@
permissions and limitations under the Licenses.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using MCGalaxy.Commands.Chatting;
@ -26,6 +27,20 @@ using MCGalaxy.Maths;
namespace MCGalaxy.Tasks {
internal static class ServerTasks {
static SchedulerTask temprankTask;
internal static void QueueTasks() {
temprankTask = Server.MainScheduler.QueueRepeat(TemprankExpiry,
null, TimeSpan.FromHours(1));
Server.MainScheduler.QueueRepeat(CheckState,
null, TimeSpan.FromSeconds(3));
Server.Background.QueueRepeat(AutoSave,
1, TimeSpan.FromSeconds(Server.backupInterval));
Server.Background.QueueRepeat(BlockUpdates,
null, TimeSpan.FromSeconds(Server.blockInterval));
}
internal static void LocationChecks(SchedulerTask task) {
Player[] players = PlayerInfo.Online.Items;
players = PlayerInfo.Online.Items;
@ -159,27 +174,48 @@ namespace MCGalaxy.Tasks {
}
internal static void TemprankExpiry(SchedulerTask task) {
Player[] players = PlayerInfo.Online.Items;
foreach (string line in File.ReadAllLines(Paths.TempRanksFile))
foreach (Player p in players)
{
if (!line.CaselessStarts(p.name)) continue;
List<string> lines = Server.tempRanks.AllLines();
foreach (string line in lines) {
string[] args = line.SplitSpaces();
if (args.Length < 4) continue;
int min = int.Parse(args[4]), hour = int.Parse(args[5]);
int day = int.Parse(args[6]), month = int.Parse(args[7]), year = int.Parse(args[8]);
int periodH = int.Parse(args[3]), periodM = 0;
if (args.Length > 10) periodM = int.Parse(args[10]);
long expiry;
if (!long.TryParse(args[3], out expiry)) continue;
DateTime expire = new DateTime(year, month, day, hour, min, 0)
.AddHours(periodH).AddMinutes(periodM);
if (DateTime.Now >= expire)
Command.all.Find("temprank").Use(null, p.name + " delete");
if (DateTime.UtcNow >= expiry.FromUnixTime()) {
Command.all.Find("temprank").Use(null, args[0] + " delete");
Server.tempRanks.Remove(args[0]); // handle case of temp rank being same as current rank
}
}
task.Delay = TemprankNextRun();
}
DateTime now = DateTime.UtcNow;
task.Delay = TimeSpan.FromSeconds(60 - now.Second); // TODO: down to seconds
internal static void TemprankCalcNextRun() {
temprankTask.Delay = TemprankNextRun();
temprankTask.NextRun = DateTime.UtcNow.Add(temprankTask.Delay);
Server.MainScheduler.Recheck();
}
static TimeSpan TemprankNextRun() {
DateTime nextRun = DateTime.MaxValue;
// Lock because we want to ensure list not modified from under us
lock (Server.tempRanks.locker) {
List<string> lines = Server.tempRanks.AllLines();
// Line format: name assigner assigntime expiretime oldRank tempRank
foreach (string line in lines) {
string[] args = line.SplitSpaces();
if (args.Length < 4) continue;
long expiry;
if (!long.TryParse(args[3], out expiry)) continue;
DateTime expireTime = expiry.FromUnixTime();
if (expireTime < nextRun)
nextRun = expireTime;
}
}
return nextRun - DateTime.UtcNow;
}
}
}

View File

@ -151,6 +151,36 @@ namespace MCGalaxy.Tasks {
Directory.Delete("text/lockdown/map");
}
internal static void UpgradeOldTempranks() {
if (!File.Exists(Paths.TempRanksFile)) return;
// Check if empty, or not old form
using (StreamReader reader = new StreamReader(Paths.TempRanksFile)) {
string line = reader.ReadLine();
if (line == null) return;
string[] parts = line.SplitSpaces();
if (parts.Length < 9) return;
}
string[] lines = File.ReadAllLines(Paths.TempRanksFile);
for (int i = 0; i < lines.Length; i++) {
string[] args = lines[i].SplitSpaces();
int min = int.Parse(args[4]), hour = int.Parse(args[5]);
int day = int.Parse(args[6]), month = int.Parse(args[7]), year = int.Parse(args[8]);
int periodH = int.Parse(args[3]), periodM = 0;
if (args.Length > 10) periodM = int.Parse(args[10]);
DateTime assigned = new DateTime(year, month, day, hour, min, 0);
DateTime expiry = assigned.AddHours(periodH).AddMinutes(periodM);
// Line format: name assigner assigntime expiretime oldRank tempRank
lines[i] = args[0] + " " + args[9] + " " + assigned.ToUnixTime() +
" " + expiry.ToUnixTime() + " " + args[2] + " " + args[1];
}
File.WriteAllLines(Paths.TempRanksFile, lines);
}
internal static void UpgradeDBTimeSpent() {
DataTable table = Database.Backend.GetRows(PlayerData.DBTable, "TimeSpent", "LIMIT 1");
if (table.Rows.Count == 0) return; // no players

View File

@ -27,6 +27,16 @@ namespace MCGalaxy {
int.Parse(parts[2]), int.Parse(parts[3]));
}
public static DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static DateTime FromUnixTime(this long offset) {
return UnixEpoch.AddTicks(offset * TimeSpan.TicksPerSecond);
}
public static long ToUnixTime(this DateTime time) {
return (long)(time.ToUniversalTime() - UnixEpoch).TotalSeconds;
}
public static bool AddSpamEntry(this List<DateTime> log, int maxEntries, int checkInterval) {
DateTime now = DateTime.UtcNow;
if (log.Count > 0 && log.Count >= maxEntries)

View File

@ -23,6 +23,7 @@ namespace MCGalaxy {
public const string CustomColorsFile = "text/customcolors.txt";
public const string TempRanksFile = "text/tempranks.txt";
public const string TempBansFile = "text/tempbans.txt";
public const string CustomTokensFile = "text/custom$s.txt";
public const string BadWordsFile = "text/badwords.txt";
public const string EatMessagesFile = "text/eatmessages.txt";

View File

@ -58,6 +58,14 @@ namespace MCGalaxy.Tasks {
}
}
/// <summary> Rechecks minimum delay for next task.
/// Useful for when external code changes the delay of a scheduled task. </summary>
public void Recheck() {
lock (taskLock) {
handle.Set();
}
}
SchedulerTask EnqueueTask(SchedulerTask task) {
lock (taskLock) {