diff --git a/GUI/Settings/LevelProperties.cs b/GUI/Settings/LevelProperties.cs index 3eaf4ce3c..9a15a7091 100644 --- a/GUI/Settings/LevelProperties.cs +++ b/GUI/Settings/LevelProperties.cs @@ -126,15 +126,16 @@ namespace MCGalaxy.Gui { bool GetAutoload() { - foreach (string line in Server.AutoloadMaps.Find(lvl.name + "=")) - return true; - return false; + return Server.AutoloadMaps.Find(lvl.name) != null; } void SetAutoload(bool value) { - Server.AutoloadMaps.DeleteStartsWith(lvl.name + "="); - if (value) - Server.AutoloadMaps.Append(lvl.name + "=" + lvl.physics); + if (value) { + Server.AutoloadMaps.AddOrReplace(lvl.name, lvl.physics.ToString()); + } else { + Server.AutoloadMaps.Remove(lvl.name); + } + Server.AutoloadMaps.Save(); } } } diff --git a/MCGalaxy/Commands/Information/CmdAbout.cs b/MCGalaxy/Commands/Information/CmdAbout.cs index efae1e8e8..03eb893da 100644 --- a/MCGalaxy/Commands/Information/CmdAbout.cs +++ b/MCGalaxy/Commands/Information/CmdAbout.cs @@ -70,8 +70,7 @@ namespace MCGalaxy.Commands { BlockDBChange.OutputMessageBlock(p, b, id, x, y, z); BlockDBChange.OutputPortal(p, b, id, x, y, z); - GC.Collect(); - GC.WaitForPendingFinalizers(); + Server.DoGC(); } static void ListFromDatabase(Player p, ref bool foundAny, Dictionary names, diff --git a/MCGalaxy/Commands/Information/CmdRankInfo.cs b/MCGalaxy/Commands/Information/CmdRankInfo.cs index 9636a383c..5859a00f7 100644 --- a/MCGalaxy/Commands/Information/CmdRankInfo.cs +++ b/MCGalaxy/Commands/Information/CmdRankInfo.cs @@ -16,6 +16,7 @@ permissions and limitations under the Licenses. */ using System; +using System.Collections.Generic; using System.IO; namespace MCGalaxy.Commands { @@ -28,19 +29,17 @@ namespace MCGalaxy.Commands { public CmdRankInfo() { } public override void Use(Player p, string message) { - if (message == "") { - if (Player.IsSuper(p)) { SuperRequiresArgs(p, "player name"); return; } - message = p.name; - } - Player who = PlayerInfo.Find(message); - string target = who == null ? message : who.name; - - Player.Message(p, " Rank information for {0}:", - PlayerInfo.GetColoredName(p, target)); - bool found = false; + if (CheckSuper(p, message, "player name")) return; + if (message == "") message = p.name; + + List rankings = Server.RankInfo.FindMatches(p, message, "rankings"); + if (rankings == null) return; + + string target = PlayerMetaList.GetName(rankings[0]); + Player.Message(p, " Rankings for {0}:", PlayerInfo.GetColoredName(p, target)); DateTime now = DateTime.Now; - foreach (string line in Server.RankInfo.Find(target)) { + foreach (string line in rankings) { string[] parts = line.Split(' '); string newRank = Group.GetColoredName(parts[7]); string oldRank = Group.GetColoredName(parts[8]); @@ -55,10 +54,7 @@ namespace MCGalaxy.Commands { Player.Message(p, "&aFrom {0} &ato {1} &a{2} ago", oldRank, newRank, delta.Shorten(true, false)); Player.Message(p, "&aBy %S{0}&a, reason: %S{1}", parts[1], reason); - found = true; } - if (!found) - Player.Message(p, "&cPlayer has not been ranked yet."); } public override void Help(Player p) { diff --git a/MCGalaxy/Commands/Maintenance/CmdGarbage.cs b/MCGalaxy/Commands/Maintenance/CmdGarbage.cs index 93baae701..a7d1260cd 100644 --- a/MCGalaxy/Commands/Maintenance/CmdGarbage.cs +++ b/MCGalaxy/Commands/Maintenance/CmdGarbage.cs @@ -28,8 +28,7 @@ namespace MCGalaxy.Commands { public override void Use(Player p, string message) { Player.Message(p, "Forcing garbage collection..."); - GC.Collect(); - GC.WaitForPendingFinalizers(); + Server.DoGC(); Player.Message(p, "Garbage collection completed!"); } diff --git a/MCGalaxy/Commands/Moderation/CmdNotes.cs b/MCGalaxy/Commands/Moderation/CmdNotes.cs index 008a943b4..5950fcae9 100644 --- a/MCGalaxy/Commands/Moderation/CmdNotes.cs +++ b/MCGalaxy/Commands/Moderation/CmdNotes.cs @@ -16,6 +16,7 @@ permissions and limitations under the Licenses. */ using System; +using System.Collections.Generic; namespace MCGalaxy.Commands { public class CmdNotes : Command { @@ -32,15 +33,13 @@ namespace MCGalaxy.Commands { if (CheckSuper(p, message, "player name")) return; if (message == "") message = p.name; - int matches = 1; - Player who = message == "" ? p : PlayerInfo.FindMatches(p, message, out matches); - if (matches > 1) return; - if (who != null) message = who.name; + List notes = Server.Notes.FindMatches(p, message, "notes"); + if (notes == null) return; - Player.Message(p, "Notes for " + message + ":"); - bool foundAny = false; - foreach (string line in Server.Notes.Find(message)) { - foundAny = true; + string target = PlayerMetaList.GetName(notes[0]); + Player.Message(p, " Notes for {0}:", PlayerInfo.GetColoredName(p, target)); + + foreach (string line in notes) { string[] args = line.Split(' '); if (args.Length <= 3) continue; @@ -50,8 +49,6 @@ namespace MCGalaxy.Commands { Player.Message(p, Action(args[1]) + " by " + args[2] + " on " + args[3] + " - " + args[4].Replace("%20", " ")); } - if (!foundAny) - Player.Message(p, "No notes found."); } static string Action(string arg) { diff --git a/MCGalaxy/Commands/World/CmdImport.cs b/MCGalaxy/Commands/World/CmdImport.cs index 3f5b0482b..06b0ed236 100644 --- a/MCGalaxy/Commands/World/CmdImport.cs +++ b/MCGalaxy/Commands/World/CmdImport.cs @@ -52,8 +52,7 @@ namespace MCGalaxy.Commands.World { lvl.Save(true); } finally { lvl.Dispose(); - GC.Collect(); - GC.WaitForPendingFinalizers(); + Server.DoGC(); } } catch (Exception ex) { Server.ErrorLog(ex); @@ -61,7 +60,6 @@ namespace MCGalaxy.Commands.World { return; } Player.Message(p, "Converted map!"); - //CmdLoad.LoadLevel(p, name); pls } enum FileType { Mcf, Fcm, Dat, Cw }; diff --git a/MCGalaxy/Commands/World/CmdLoad.cs b/MCGalaxy/Commands/World/CmdLoad.cs index c4bd45c0d..657d0aadc 100644 --- a/MCGalaxy/Commands/World/CmdLoad.cs +++ b/MCGalaxy/Commands/World/CmdLoad.cs @@ -45,8 +45,7 @@ namespace MCGalaxy.Commands.World { try { return LoadLevelCore(p, name, phys, autoLoaded); } finally { - GC.Collect(); - GC.WaitForPendingFinalizers(); + Server.DoGC(); } } diff --git a/MCGalaxy/Commands/World/CmdNewLvl.cs b/MCGalaxy/Commands/World/CmdNewLvl.cs index fcc6567c2..e24562c8b 100644 --- a/MCGalaxy/Commands/World/CmdNewLvl.cs +++ b/MCGalaxy/Commands/World/CmdNewLvl.cs @@ -79,8 +79,7 @@ namespace MCGalaxy.Commands.World { Chat.MessageAll(format, pName, name, seed); } finally { if (p != null) Interlocked.Exchange(ref p.GeneratingMap, 0); - GC.Collect(); - GC.WaitForPendingFinalizers(); + Server.DoGC(); } return true; } diff --git a/MCGalaxy/Commands/World/CmdReload.cs b/MCGalaxy/Commands/World/CmdReload.cs index 216a91b1d..13eff9daa 100644 --- a/MCGalaxy/Commands/World/CmdReload.cs +++ b/MCGalaxy/Commands/World/CmdReload.cs @@ -46,8 +46,7 @@ namespace MCGalaxy.Commands { } LevelActions.ReloadMap(p, who, true); } - GC.Collect(); - GC.WaitForPendingFinalizers(); + Server.DoGC(); } bool ReloadAll(Player p, string[] parts) { diff --git a/MCGalaxy/Commands/World/CmdResizeLvl.cs b/MCGalaxy/Commands/World/CmdResizeLvl.cs index 592bbfbf5..beb0690a6 100644 --- a/MCGalaxy/Commands/World/CmdResizeLvl.cs +++ b/MCGalaxy/Commands/World/CmdResizeLvl.cs @@ -85,8 +85,7 @@ namespace MCGalaxy.Commands.World { } } - GC.Collect(); - GC.WaitForPendingFinalizers(); + Server.DoGC(); return Level.Load(lvl.name); } diff --git a/MCGalaxy/Commands/World/CmdUnload.cs b/MCGalaxy/Commands/World/CmdUnload.cs index bfbb09ab0..246d536a8 100644 --- a/MCGalaxy/Commands/World/CmdUnload.cs +++ b/MCGalaxy/Commands/World/CmdUnload.cs @@ -26,7 +26,7 @@ namespace MCGalaxy.Commands.World { public override void Use(Player p, string message) { string name = message.ToLower(); - if (name == "" && Player.IsSuper(p)) { SuperRequiresArgs(p, "level name"); return; } + if (CheckSuper(p, message, "level name")) return; if (name == "") { if (!p.level.Unload()) { diff --git a/MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs b/MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs index 4d12beb0e..e014694d9 100644 --- a/MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs +++ b/MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs @@ -158,8 +158,7 @@ namespace MCGalaxy.Drawing.Ops { if (pl.level.name.CaselessEq(lvl.name)) LevelActions.ReloadMap(p, pl, true); } - GC.Collect(); - GC.WaitForPendingFinalizers(); + Server.DoGC(); } diff --git a/MCGalaxy/Levels/IO/fNbt.cs b/MCGalaxy/Levels/IO/fNbt.cs index 4531dc3db..42203a45d 100644 --- a/MCGalaxy/Levels/IO/fNbt.cs +++ b/MCGalaxy/Levels/IO/fNbt.cs @@ -56,11 +56,6 @@ namespace fNbt { } byte[] bytes = ZeroArray; - public byte this[int tagIndex] { - get { return Value[tagIndex]; } - set { Value[tagIndex] = value; } - } - internal override void ReadTag(NbtBinaryReader readStream) { int length = readStream.ReadInt32(); if (length < 0) @@ -233,16 +228,14 @@ namespace fNbt { public byte ByteValue { get { - if (TagType == NbtTagType.Byte) - return ((NbtByte)this).Value; + if (TagType == NbtTagType.Byte) return ((NbtByte)this).Value; throw new InvalidCastException("Cannot get ByteValue from " + TagType); } } public float FloatValue { get { - if (TagType == NbtTagType.Float) - return ((NbtFloat)this).Value; + if (TagType == NbtTagType.Float) return ((NbtFloat)this).Value; throw new InvalidCastException("Cannot get FloatValue from " + TagType); } } @@ -250,10 +243,8 @@ namespace fNbt { public short ShortValue { get { switch (TagType) { - case NbtTagType.Byte: - return ((NbtByte)this).Value; - case NbtTagType.Short: - return ((NbtShort)this).Value; + case NbtTagType.Byte: return ((NbtByte)this).Value; + case NbtTagType.Short: return ((NbtShort)this).Value; default: throw new InvalidCastException("Cannot get ShortValue from " + TagType); } @@ -263,12 +254,9 @@ namespace fNbt { public int IntValue { get { switch (TagType) { - case NbtTagType.Byte: - return ((NbtByte)this).Value; - case NbtTagType.Short: - return ((NbtShort)this).Value; - case NbtTagType.Int: - return ((NbtInt)this).Value; + case NbtTagType.Byte: return ((NbtByte)this).Value; + case NbtTagType.Short: return ((NbtShort)this).Value; + case NbtTagType.Int: return ((NbtInt)this).Value; default: throw new InvalidCastException("Cannot get IntValue from " + TagType); } @@ -277,16 +265,14 @@ namespace fNbt { public byte[] ByteArrayValue { get { - if (TagType == NbtTagType.ByteArray) - return ((NbtByteArray)this).Value; + if (TagType == NbtTagType.ByteArray) return ((NbtByteArray)this).Value; throw new InvalidCastException("Cannot get ByteArrayValue from " + TagType); } } public string StringValue { get { - if (TagType == NbtTagType.String) - return ((NbtString)this).Value; + if (TagType == NbtTagType.String) return ((NbtString)this).Value; throw new InvalidCastException("Cannot get StringValue from " + TagType); } } @@ -331,25 +317,22 @@ namespace fNbt { public override short ReadInt16() { if (swapNeeded) { return Swap(base.ReadInt16()); - } else { - return base.ReadInt16(); } + return base.ReadInt16(); } public override int ReadInt32() { if (swapNeeded) { return Swap(base.ReadInt32()); - } else { - return base.ReadInt32(); } + return base.ReadInt32(); } public override long ReadInt64() { if (swapNeeded) { return Swap(base.ReadInt64()); - } else { - return base.ReadInt64(); } + return base.ReadInt64(); } public override float ReadSingle() { @@ -357,9 +340,8 @@ namespace fNbt { FillBuffer(sizeof(float)); Array.Reverse(buffer, 0, sizeof(float)); return BitConverter.ToSingle(buffer, 0); - } else { - return base.ReadSingle(); } + return base.ReadSingle(); } public override double ReadDouble() { @@ -405,25 +387,19 @@ namespace fNbt { } static short Swap(short v) { - unchecked { - return (short)((v >> 8) & 0x00FF | (v << 8) & 0xFF00); - } + return (short)((v >> 8) & 0x00FF | (v << 8) & 0xFF00); } static int Swap(int v) { - unchecked { - uint v2 = (uint)v; - return - (int) - ((v2 >> 24) & 0x000000FF | (v2 >> 8) & 0x0000FF00 | (v2 << 8) & 0x00FF0000 | - (v2 << 24) & 0xFF000000); - } + uint v2 = (uint)v; + return + (int) + ((v2 >> 24) & 0x000000FF | (v2 >> 8) & 0x0000FF00 | (v2 << 8) & 0x00FF0000 | + (v2 << 24) & 0xFF000000); } static long Swap(long v) { - unchecked { - return (Swap((int)v) & uint.MaxValue) << 32 | Swap((int)(v >> 32)) & uint.MaxValue; - } + return (Swap((int)v) & uint.MaxValue) << 32 | Swap((int)(v >> 32)) & uint.MaxValue; } } diff --git a/MCGalaxy/Levels/Level.cs b/MCGalaxy/Levels/Level.cs index ab34437d1..cadfe3e31 100644 --- a/MCGalaxy/Levels/Level.cs +++ b/MCGalaxy/Levels/Level.cs @@ -204,8 +204,7 @@ namespace MCGalaxy { } catch { } finally { Dispose(); - GC.Collect(); - GC.WaitForPendingFinalizers(); + Server.DoGC(); if (!silent) Chat.MessageOps(ColoredName + " %Swas unloaded."); Server.s.Log(name + " was unloaded."); @@ -271,8 +270,7 @@ namespace MCGalaxy { Chat.MessageAll("FAILED TO SAVE {0}", ColoredName); Server.ErrorLog(e); } - GC.Collect(); - GC.WaitForPendingFinalizers(); + Server.DoGC(); } void SaveCore(string path) { diff --git a/MCGalaxy/Network/Player.Networking.cs b/MCGalaxy/Network/Player.Networking.cs index 0e9c89d3f..7c433d11e 100644 --- a/MCGalaxy/Network/Player.Networking.cs +++ b/MCGalaxy/Network/Player.Networking.cs @@ -332,8 +332,7 @@ namespace MCGalaxy { SendMessage("There was an error sending the map data, you have been sent to the main level."); Server.ErrorLog(ex); } finally { - GC.Collect(); - GC.WaitForPendingFinalizers(); + Server.DoGC(); } return success; } diff --git a/MCGalaxy/Player/List/PlayerExtList.cs b/MCGalaxy/Player/List/PlayerExtList.cs index fec186abe..b94c0bcb3 100644 --- a/MCGalaxy/Player/List/PlayerExtList.cs +++ b/MCGalaxy/Player/List/PlayerExtList.cs @@ -23,49 +23,50 @@ using System.Text; namespace MCGalaxy { public sealed class PlayerExtList { + char separator = ' '; string path; - List players = new List(); + List names = new List(); public List lines = new List(); readonly object locker = new object(), saveLocker = new object(); - public void Add(string p, string data) { - p = p.ToLower(); + public void Add(string name, string data) { + name = name.ToLower(); lock (locker) { - players.Add(p); lines.Add(p + " " + data); + names.Add(name); lines.Add(name + separator + data); } } - public bool Remove(string p) { + public bool Remove(string name) { lock (locker) { - int idx = players.IndexOf(p.ToLower()); + int idx = names.IndexOf(name.ToLower()); if (idx == -1) return false; - players.RemoveAt(idx); + names.RemoveAt(idx); lines.RemoveAt(idx); return true; } } - public void AddOrReplace(string p, string data) { - p = p.ToLower(); + public void AddOrReplace(string name, string data) { + name = name.ToLower(); lock (locker) { - int idx = players.IndexOf(p); + int idx = names.IndexOf(name); if (idx == -1) { - players.Add(p); lines.Add(p + " " + data); + names.Add(name); lines.Add(name + separator + data); } else { - lines[idx] = p + " " + data; + lines[idx] = name + separator + data; } } } - public string Find(string p) { + public string Find(string name) { lock (locker) { - int idx = players.IndexOf(p.ToLower()); + int idx = names.IndexOf(name.ToLower()); return idx == -1 ? null : lines[idx]; } } - public int Count { get { lock (locker) return players.Count; } } + public int Count { get { lock (locker) return names.Count; } } public void Save() { Save(true); } @@ -84,9 +85,10 @@ namespace MCGalaxy { } } - public static PlayerExtList Load(string path) { + public static PlayerExtList Load(string path, char separator = ' ') { PlayerExtList list = new PlayerExtList(); list.path = path; + list.separator = separator; if (!File.Exists(path)) { File.Create(path).Close(); @@ -98,8 +100,8 @@ namespace MCGalaxy { string line = null; while ((line = r.ReadLine()) != null) { list.lines.Add(line); - int space = line.IndexOf(' '); - string name = space >= 0 ? line.Substring(0, space) : line; + int sepIndex = line.IndexOf(separator); + string name = sepIndex >= 0 ? line.Substring(0, sepIndex) : line; // Need to convert uppercase to lowercase, in case user added in entries. bool anyUpper = false; @@ -108,7 +110,7 @@ namespace MCGalaxy { anyUpper |= (c >= 'A' && c <= 'Z'); } if (anyUpper) name = name.ToLower(); - list.players.Add(name); + list.names.Add(name); } } return list; diff --git a/MCGalaxy/Player/List/PlayerList.cs b/MCGalaxy/Player/List/PlayerList.cs index 60ef47729..bf9faeda4 100644 --- a/MCGalaxy/Player/List/PlayerList.cs +++ b/MCGalaxy/Player/List/PlayerList.cs @@ -67,7 +67,7 @@ namespace MCGalaxy { public string FindMatches(Player p, string name, string type, out int matches) { lock (locker) { return Matcher.Find(p, name, out matches, players, - n => true, n => n, type, 20); + null, n => n, type, 20); } } diff --git a/MCGalaxy/Player/List/PlayerMetaList.cs b/MCGalaxy/Player/List/PlayerMetaList.cs index 6b8ce3b0a..d40e3d7b2 100644 --- a/MCGalaxy/Player/List/PlayerMetaList.cs +++ b/MCGalaxy/Player/List/PlayerMetaList.cs @@ -33,9 +33,18 @@ namespace MCGalaxy { } public void EnsureExists() { - if (!File.Exists(file)) + if (!File.Exists(file)) File.Create(file).Dispose(); } + + /// Adds the given line to the end of the file. + public void Append(string data) { + lock (locker) { + using (StreamWriter w = new StreamWriter(file, true)) + w.WriteLine(data); + } + } + /// Finds all lines which caselessly start with the given name. public IEnumerable Find(string name) { @@ -50,36 +59,28 @@ namespace MCGalaxy { } yield break; } + + public List FindMatches(Player p, string name, string group) { + int matches = 0; + return Matcher.FindMulti(p, name, out matches, AllLines(), + null, GetName, group); + } - /// Deletes all lines which start with the given value. - public void DeleteStartsWith(string value) { - if (!File.Exists(file)) return; - List lines = new List(); + IEnumerable AllLines() { + if (!File.Exists(file)) yield break; + using (StreamReader r = new StreamReader(file)) { string line; while ((line = r.ReadLine()) != null) { - if (line.StartsWith(value)) continue; - lines.Add(line); + yield return line; } } - WriteLines(lines); + yield break; } - void WriteLines(List lines) { - lock (locker) { - using (StreamWriter w = new StreamWriter(file, false)) { - foreach (string line in lines) - w.WriteLine(line); - } - } - } - - /// Adds the given line to the end of the file. - public void Append(string data) { - lock (locker) { - using (StreamWriter w = new StreamWriter(file, true)) - w.WriteLine(data); - } + public static string GetName(string line) { + int index = line.IndexOf(' '); + return index == -1 ? line : line.Substring(0, index); } } } diff --git a/MCGalaxy/Player/PlayerActions.cs b/MCGalaxy/Player/PlayerActions.cs index 688bfcf43..b33e105bf 100644 --- a/MCGalaxy/Player/PlayerActions.cs +++ b/MCGalaxy/Player/PlayerActions.cs @@ -59,8 +59,7 @@ namespace MCGalaxy { GotoLevel(p, lvl, ignorePerms) : GotoMap(p, name, ignorePerms); } finally { Interlocked.Exchange(ref p.UsingGoto, 0); - GC.Collect(); - GC.WaitForPendingFinalizers(); + Server.DoGC(); } if (!didJoin) return false; diff --git a/MCGalaxy/Server/Server.Fields.cs b/MCGalaxy/Server/Server.Fields.cs index 0eeb582c7..62443310f 100644 --- a/MCGalaxy/Server/Server.Fields.cs +++ b/MCGalaxy/Server/Server.Fields.cs @@ -52,7 +52,7 @@ namespace MCGalaxy { public static Thread locationChecker; public static DateTime StartTime, StartTimeLocal; - public static PlayerMetaList AutoloadMaps = new PlayerMetaList("text/autoload.txt"); + 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"); diff --git a/MCGalaxy/Server/Server.Init.cs b/MCGalaxy/Server/Server.Init.cs index d91268f5a..857da3f8c 100644 --- a/MCGalaxy/Server/Server.Init.cs +++ b/MCGalaxy/Server/Server.Init.cs @@ -94,17 +94,17 @@ namespace MCGalaxy { whiteList = PlayerList.Load("whitelist.txt"); } - void LoadAutoloadCommands() { - if (File.Exists("text/autoload.txt")) { - PropertiesFile.Read("text/autoload.txt", AutoLoadLineProcessor); - GC.Collect(); - GC.WaitForPendingFinalizers(); - } else { - Log("autoload.txt does not exist"); + void LoadAutoloadMaps() { + AutoloadMaps = PlayerExtList.Load("text/autoload.txt", '='); + foreach (string line in AutoloadMaps.lines) { + int sepIndex = line.IndexOf('='); + string name = sepIndex >= 0 ? line.Substring(0, sepIndex) : line; + string value = sepIndex >= 0 ? line.Substring(sepIndex + 1) : ""; + AutoLoadMap(name, value); } } - static void AutoLoadLineProcessor(string name, string phys) { + static void AutoLoadMap(string name, string phys) { name = name.ToLower(); if (phys == "") phys = "0"; diff --git a/MCGalaxy/Server/Server.cs b/MCGalaxy/Server/Server.cs index c9fdf3b2f..d90ef4935 100644 --- a/MCGalaxy/Server/Server.cs +++ b/MCGalaxy/Server/Server.cs @@ -108,7 +108,7 @@ namespace MCGalaxy { Plugin.Load(); Background.QueueOnce(UpgradeTasks.UpgradeOldBlacklist); Background.QueueOnce(LoadPlayerLists); - Background.QueueOnce(LoadAutoloadCommands); + Background.QueueOnce(LoadAutoloadMaps); Background.QueueOnce(UpgradeTasks.MovePreviousLevelFiles); Background.QueueOnce(UpgradeTasks.UpgradeOldLockdown); @@ -366,5 +366,15 @@ namespace MCGalaxy { level = mapName; return true; } + + public static void DoGC() { + long start = GC.GetTotalMemory(false); + GC.Collect(); + GC.WaitForPendingFinalizers(); + + long end = GC.GetTotalMemory(false); + double delta = (start - end) / 1024.0; + Server.s.Log("GC performed (freed " + delta.ToString("F2") + " KB)", true); + } } } \ No newline at end of file diff --git a/MCGalaxy/util/Formatting/Matcher.cs b/MCGalaxy/util/Formatting/Matcher.cs index 68e0ede65..66a507ff7 100644 --- a/MCGalaxy/util/Formatting/Matcher.cs +++ b/MCGalaxy/util/Formatting/Matcher.cs @@ -17,6 +17,7 @@ */ using System; using System.Collections; +using System.Collections.Generic; using System.IO; using System.Text; @@ -82,16 +83,8 @@ namespace MCGalaxy { /// Finds partial matches of 'name' against the names of the items in the 'items' enumerable. - /// The player to output messages to. - /// The name to perform partial matching against. - /// The number of found/outputted matches. - /// Enumerable of items that may be matched with. - /// Selects which items from 'items' are actually matched. - /// Gets the name of a particular item. - /// The group/type of the items. (e.g. 'players', 'commands') - /// The maximum number of matches that are outputted. /// If exactly one match, the matching item. - public static T Find(Player pl, string name, out int matches, IEnumerable items, + public static T Find(Player p, string name, out int matches, IEnumerable items, Predicate filter, Func nameGetter, string group, int limit = 5) { T match = default(T); matches = 0; StringBuilder nameMatches = new StringBuilder(); @@ -110,19 +103,76 @@ namespace MCGalaxy { } } + if (matches == 1) return match; if (matches == 0) { - Player.Message(pl, "No " + group + " match \"" + name + "\"."); - return default(T); - } else if (matches == 1) { - return match; + Player.Message(p, "No " + group + " match \"" + name + "\"."); } else { - string count = matches > limit ? limit + "+ " : matches + " "; - string names = nameMatches.ToString(0, nameMatches.Length - 2); - - Player.Message(pl, count + group + " match \"" + name + "\":"); - Player.Message(pl, names); - return default(T); + OutputMulti(p, name, nameMatches, matches, group, limit); } + return default(T); + } + + /// Finds partial matches of 'name' against the names of the items in the 'items' enumerable. + /// Outputs multiple matching entries, as 'items' enumerable may have multiple entries. + /// If exactly one match, the matching list of items. + public static List FindMulti(Player p, string name, out int matches, IEnumerable items, + Predicate filter, Func nameGetter, string group, int limit = 5) { + List matchItems = null; matches = 0; + StringBuilder nameMatches = new StringBuilder(); + List outputtedNames = new List(limit); + string match = null; + + foreach (T item in items) { + if (filter != null && !filter(item)) continue; + string itemName = nameGetter(item); + + // Found an exact name match - only output items now which exactly match + if (itemName.Equals(name, comp)) { + if (match == null || !name.Equals(match, comp)) + matchItems = new List(); + matchItems.Add(item); + + matches = 1; match = name; + continue; + } + + if (itemName.IndexOf(name, comp) < 0) continue; + if (matches == 0) { // Found our first partial match - init the list + matchItems = new List(); + matchItems.Add(item); + match = itemName; + } else if (match != null && itemName.Equals(match, comp)) { // Found same partial match + matchItems.Add(item); + } + + // We do not want to output the same name multiple times + if (outputtedNames.CaselessContains(itemName) || matches > (limit + 1)) continue; + matches++; + + if (matches <= limit) { + nameMatches.Append(itemName).Append(", "); + } else if (matches == limit + 1) { + nameMatches.Append("(and more)").Append(", "); + } + outputtedNames.Add(itemName); + } + + if (matches == 1) return matchItems; + if (matches == 0) { + Player.Message(p, "No " + group + " found for \"" + name + "\"."); + } else { + OutputMulti(p, name, nameMatches, matches, "players", limit); + } + return null; + } + + static void OutputMulti(Player p, string name, StringBuilder nameMatches, + int matches, string group, int limit = 5) { + string count = matches > limit ? limit + "+ " : matches + " "; + string names = nameMatches.ToString(0, nameMatches.Length - 2); + + Player.Message(p, count + group + " match \"" + name + "\":"); + Player.Message(p, names); } } }