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; MessageTooHighRank(p, "change the rank of", false); return false;
} }
if (p != null && newRank.Permission >= p.Rank) { 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) { if (newRank.Permission == curRank.Permission) {
Player.Message(p, "Cannot change the rank of a player to a rank equal or higher to yours."); return false; Player.Message(p, "{0} %Sis already ranked {1}.",
PlayerInfo.GetColoredName(p, name), curRank.ColoredName); return false;
} }
if (who == null) return true; if (who == null) return true;

View File

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

View File

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

View File

@ -32,7 +32,8 @@ namespace MCGalaxy {
public string Path; public string Path;
List<string> names = new List<string>(), lines = new List<string>(); 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> /// <summary> Returns a copy of all names in the list. </summary>
public List<string> AllNames() { public List<string> AllNames() {

View File

@ -29,7 +29,8 @@ namespace MCGalaxy {
public string Path; public string Path;
List<string> names = new List<string>(); 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() { }
public PlayerList(string path) { Path = path; } public PlayerList(string path) { Path = path; }

View File

@ -58,7 +58,6 @@ namespace MCGalaxy {
public static PlayerExtList AutoloadMaps; public static PlayerExtList AutoloadMaps;
public static PlayerMetaList RankInfo = new PlayerMetaList("text/rankinfo.txt"); 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"); 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> /// <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 CTFGame ctf = null;
public static PlayerList bannedIP, whiteList, ircControllers, muted, invalidIds; public static PlayerList bannedIP, whiteList, ircControllers, muted, invalidIds;
public static PlayerList ignored, frozen, hidden, agreed, vip, noEmotes, lockdown; 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>(); 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"); skins = PlayerExtList.Load("extra/skins.txt");
reach = PlayerExtList.Load("extra/reach.txt"); reach = PlayerExtList.Load("extra/reach.txt");
invalidIds = PlayerList.Load("extra/invalidids.txt"); invalidIds = PlayerList.Load("extra/invalidids.txt");
tempBans = PlayerExtList.Load("text/tempbans.txt"); tempBans = PlayerExtList.Load(Paths.TempBansFile);
rotations = PlayerExtList.Load("extra/rotations.txt"); rotations = PlayerExtList.Load("extra/rotations.txt");
tempRanks = PlayerExtList.Load(Paths.TempRanksFile);
ServerTasks.TemprankCalcNextRun();
if (useWhitelist) if (useWhitelist)
whiteList = PlayerList.Load("whitelist.txt"); whiteList = PlayerList.Load("whitelist.txt");
} }

View File

@ -116,11 +116,12 @@ namespace MCGalaxy {
Background.QueueOnce(LoadMainLevel); Background.QueueOnce(LoadMainLevel);
Plugin.Load(); Plugin.Load();
Background.QueueOnce(UpgradeTasks.UpgradeOldBlacklist); Background.QueueOnce(UpgradeTasks.UpgradeOldBlacklist);
Background.QueueOnce(LoadPlayerLists);
Background.QueueOnce(LoadAutoloadMaps); Background.QueueOnce(LoadAutoloadMaps);
Background.QueueOnce(UpgradeTasks.MovePreviousLevelFiles); Background.QueueOnce(UpgradeTasks.MovePreviousLevelFiles);
Background.QueueOnce(UpgradeTasks.UpgradeOldLockdown); Background.QueueOnce(UpgradeTasks.UpgradeOldLockdown);
Background.QueueOnce(UpgradeTasks.UpgradeOldTempranks);
Background.QueueOnce(UpgradeTasks.UpgradeDBTimeSpent); Background.QueueOnce(UpgradeTasks.UpgradeDBTimeSpent);
Background.QueueOnce(LoadPlayerLists);
Background.QueueOnce(SetupSocket); Background.QueueOnce(SetupSocket);
Background.QueueOnce(InitTimers); Background.QueueOnce(InitTimers);
@ -130,16 +131,8 @@ namespace MCGalaxy {
Devs.Clear(); Devs.Clear();
Mods.Clear(); Mods.Clear();
Background.QueueOnce(InitTasks.UpdateStaffList); Background.QueueOnce(InitTasks.UpdateStaffList);
MainScheduler.QueueRepeat(ServerTasks.TemprankExpiry, ServerTasks.QueueTasks();
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));
Background.QueueRepeat(ThreadSafeCache.DBCache.CleanupTask, Background.QueueRepeat(ThreadSafeCache.DBCache.CleanupTask,
null, TimeSpan.FromMinutes(5)); null, TimeSpan.FromMinutes(5));
} }
@ -159,7 +152,6 @@ namespace MCGalaxy {
if (!Directory.Exists("levels")) Directory.CreateDirectory("levels"); if (!Directory.Exists("levels")) Directory.CreateDirectory("levels");
if (!Directory.Exists("bots")) Directory.CreateDirectory("bots"); if (!Directory.Exists("bots")) Directory.CreateDirectory("bots");
if (!Directory.Exists("text")) Directory.CreateDirectory("text"); if (!Directory.Exists("text")) Directory.CreateDirectory("text");
TempRanks.EnsureExists();
RankInfo.EnsureExists(); RankInfo.EnsureExists();
Ban.EnsureExists(); Ban.EnsureExists();

View File

@ -17,6 +17,7 @@
permissions and limitations under the Licenses. permissions and limitations under the Licenses.
*/ */
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using MCGalaxy.Commands.Chatting; using MCGalaxy.Commands.Chatting;
@ -26,6 +27,20 @@ using MCGalaxy.Maths;
namespace MCGalaxy.Tasks { namespace MCGalaxy.Tasks {
internal static class ServerTasks { 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) { internal static void LocationChecks(SchedulerTask task) {
Player[] players = PlayerInfo.Online.Items; Player[] players = PlayerInfo.Online.Items;
players = PlayerInfo.Online.Items; players = PlayerInfo.Online.Items;
@ -159,27 +174,48 @@ namespace MCGalaxy.Tasks {
} }
internal static void TemprankExpiry(SchedulerTask task) { internal static void TemprankExpiry(SchedulerTask task) {
Player[] players = PlayerInfo.Online.Items; List<string> lines = Server.tempRanks.AllLines();
foreach (string line in lines) {
foreach (string line in File.ReadAllLines(Paths.TempRanksFile))
foreach (Player p in players)
{
if (!line.CaselessStarts(p.name)) continue;
string[] args = line.SplitSpaces(); 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]);
DateTime expire = new DateTime(year, month, day, hour, min, 0) long expiry;
.AddHours(periodH).AddMinutes(periodM); if (!long.TryParse(args[3], out expiry)) continue;
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"); 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() { internal static void UpgradeDBTimeSpent() {
DataTable table = Database.Backend.GetRows(PlayerData.DBTable, "TimeSpent", "LIMIT 1"); DataTable table = Database.Backend.GetRows(PlayerData.DBTable, "TimeSpent", "LIMIT 1");
if (table.Rows.Count == 0) return; // no players if (table.Rows.Count == 0) return; // no players

View File

@ -27,6 +27,16 @@ namespace MCGalaxy {
int.Parse(parts[2]), int.Parse(parts[3])); 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) { public static bool AddSpamEntry(this List<DateTime> log, int maxEntries, int checkInterval) {
DateTime now = DateTime.UtcNow; DateTime now = DateTime.UtcNow;
if (log.Count > 0 && log.Count >= maxEntries) if (log.Count > 0 && log.Count >= maxEntries)

View File

@ -21,14 +21,15 @@ namespace MCGalaxy {
public static class Paths { public static class Paths {
public const string CustomColorsFile = "text/customcolors.txt"; public const string CustomColorsFile = "text/customcolors.txt";
public const string TempRanksFile = "text/tempranks.txt"; public const string TempRanksFile = "text/tempranks.txt";
public const string CustomTokensFile = "text/custom$s.txt"; public const string TempBansFile = "text/tempbans.txt";
public const string BadWordsFile = "text/badwords.txt"; public const string CustomTokensFile = "text/custom$s.txt";
public const string EatMessagesFile = "text/eatmessages.txt"; public const string BadWordsFile = "text/badwords.txt";
public const string RulesFile = "text/rules.txt"; public const string EatMessagesFile = "text/eatmessages.txt";
public const string OprulesFile = "text/oprules.txt"; public const string RulesFile = "text/rules.txt";
public const string FaqFile = "text/faq.txt"; public const string OprulesFile = "text/oprules.txt";
public const string FaqFile = "text/faq.txt";
public const string AnnouncementsFile = "text/messages.txt"; public const string AnnouncementsFile = "text/messages.txt";
public const string AliasesFile = "text/aliases.txt"; public const string AliasesFile = "text/aliases.txt";
public const string NewsFile = "text/news.txt"; public const string NewsFile = "text/news.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) { SchedulerTask EnqueueTask(SchedulerTask task) {
lock (taskLock) { lock (taskLock) {