From 36465e8f2e6491485a0952f24ade22674c712ba9 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Fri, 19 Aug 2016 19:54:59 +1000 Subject: [PATCH] Start using read locks. --- Bots/BotsFile.cs | 2 +- Commands/Moderation/CmdHighlight.cs | 7 +++++-- Drawing/DrawOps/RedoDrawOp.cs | 21 ++++++++++++++------- Drawing/DrawOps/UndoDrawOp.cs | 8 ++++++-- GUI/Window.cs | 2 +- Levels/IO/fNbt.cs | 4 ++-- Player/Undo/UndoCache.cs | 25 ++++++++++++++----------- Player/Undo/UndoFile.cs | 6 +++++- Player/Undo/UndoFileCBin.cs | 1 + 9 files changed, 49 insertions(+), 27 deletions(-) diff --git a/Bots/BotsFile.cs b/Bots/BotsFile.cs index 5ed664ad1..8e7de0097 100644 --- a/Bots/BotsFile.cs +++ b/Bots/BotsFile.cs @@ -44,7 +44,7 @@ namespace MCGalaxy.Bots { } static void Save() { - var bots = SavedBots.ToArray(); + BotProperties[] bots = SavedBots.ToArray(); string json = JsonConvert.SerializeObject(bots); try { File.WriteAllText("extra/bots.json", json); diff --git a/Commands/Moderation/CmdHighlight.cs b/Commands/Moderation/CmdHighlight.cs index 2870d58df..aaabe02fd 100644 --- a/Commands/Moderation/CmdHighlight.cs +++ b/Commands/Moderation/CmdHighlight.cs @@ -53,7 +53,10 @@ namespace MCGalaxy.Commands { Player who = PlayerInfo.Find(name); if (who != null) { FoundUser = true; - PerformHighlight(p, seconds, who.UndoBuffer); + UndoCache cache = who.UndoBuffer; + using (IDisposable locker = cache.ClearLock.AccquireReadLock()) { + HighlightBlocks(p, seconds, cache); + } } DateTime start = DateTime.UtcNow.AddTicks(-seconds * TimeSpan.TicksPerSecond); @@ -66,7 +69,7 @@ namespace MCGalaxy.Commands { } } - static void PerformHighlight(Player p, long seconds, UndoCache cache) { + static void HighlightBlocks(Player p, long seconds, UndoCache cache) { UndoCacheNode node = cache.Tail; if (node == null) return; diff --git a/Drawing/DrawOps/RedoDrawOp.cs b/Drawing/DrawOps/RedoDrawOp.cs index 778801c9d..e36e33215 100644 --- a/Drawing/DrawOps/RedoDrawOp.cs +++ b/Drawing/DrawOps/RedoDrawOp.cs @@ -23,7 +23,7 @@ using MCGalaxy.Util; namespace MCGalaxy.Drawing.Ops { - public class RedoSelfDrawOp : DrawOp { + public class RedoSelfDrawOp : DrawOp { public override string Name { get { return "RedoSelf"; } } /// Point in time that the /undo should go backwards up to. @@ -36,12 +36,19 @@ namespace MCGalaxy.Drawing.Ops { public override IEnumerable Perform(Vec3S32[] marks, Player p, Level lvl, Brush brush) { UndoCache cache = p.UndoBuffer; - UndoCacheNode node = cache.Tail; - if (node == null) yield break; - int timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds; + using (IDisposable locker = cache.ClearLock.AccquireReadLock()) { + RedoBlocks(p); + } + yield break; + } + + void RedoBlocks(Player p) { + UndoCache cache = p.UndoBuffer; + UndoCacheNode node = p.UndoBuffer.Tail; + if (node == null) return; while (node != null) { - lvl = LevelInfo.FindExact(node.MapName); + Level lvl = LevelInfo.FindExact(node.MapName); if (lvl == null || (p.level != null && !p.level.name.CaselessEq(lvl.name))) { node = node.Prev; continue; } @@ -55,7 +62,7 @@ namespace MCGalaxy.Drawing.Ops { DateTime time = node.BaseTime.AddTicks(item.TimeDelta * TimeSpan.TicksPerSecond); if (time > End) continue; - if (time < Start) { buffer.CheckIfSend(true); yield break; } + if (time < Start) { buffer.CheckIfSend(true); return; } byte tile, extTile; item.GetBlock(out tile, out extTile); @@ -67,7 +74,7 @@ namespace MCGalaxy.Drawing.Ops { buffer.CheckIfSend(true); node = node.Prev; } - yield break; + return; } } } diff --git a/Drawing/DrawOps/UndoDrawOp.cs b/Drawing/DrawOps/UndoDrawOp.cs index b4f413b93..97eaf661b 100644 --- a/Drawing/DrawOps/UndoDrawOp.cs +++ b/Drawing/DrawOps/UndoDrawOp.cs @@ -42,14 +42,18 @@ namespace MCGalaxy.Drawing.Ops { public override long GetBlocksAffected(Level lvl, Vec3S32[] marks) { return -1; } public override IEnumerable Perform(Vec3S32[] marks, Player p, Level lvl, Brush brush) { - PerformUndo(p, ref saveLevel); + UndoCache cache = p.UndoBuffer; + using (IDisposable locker = cache.ClearLock.AccquireReadLock()) { + UndoBlocks(p, ref saveLevel); + } + bool foundUser = false; Vec3S32[] bounds = { Min, Max }; UndoFile.UndoPlayer(p, who.name.ToLower(), bounds, Start, ref foundUser); yield break; } - void PerformUndo(Player p, ref Level saveLvl) { + void UndoBlocks(Player p, ref Level saveLvl) { UndoCache cache = who.UndoBuffer; UndoCacheNode node = cache.Tail; if (node == null) return; diff --git a/GUI/Window.cs b/GUI/Window.cs index 69daa187d..7129b1087 100644 --- a/GUI/Window.cs +++ b/GUI/Window.cs @@ -68,7 +68,7 @@ namespace MCGalaxy.Gui { UpdateListTimer.Elapsed += delegate { try { - UpdateClientList(Player.players); + UpdateClientList(null); UpdateMapList(); } catch { } // needed for slower computers diff --git a/Levels/IO/fNbt.cs b/Levels/IO/fNbt.cs index 9ded76302..a4796481d 100644 --- a/Levels/IO/fNbt.cs +++ b/Levels/IO/fNbt.cs @@ -56,7 +56,7 @@ namespace fNbt { } byte[] bytes = ZeroArray; - public new byte this[int tagIndex] { + public byte this[int tagIndex] { get { return Value[tagIndex]; } set { Value[tagIndex] = value; } } @@ -153,7 +153,7 @@ namespace fNbt { public override NbtTagType TagType { get { return NbtTagType.IntArray; } } public int[] Value { get; set; } - public new int this[int tagIndex] { + public int this[int tagIndex] { get { return Value[tagIndex]; } set { Value[tagIndex] = value; } } diff --git a/Player/Undo/UndoCache.cs b/Player/Undo/UndoCache.cs index 476450f08..fa483310d 100644 --- a/Player/Undo/UndoCache.cs +++ b/Player/Undo/UndoCache.cs @@ -18,12 +18,13 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; +using System.Threading; namespace MCGalaxy.Util { public sealed class UndoCache { - - /// The oldest/first node in the cache. + + /// The olded/first node in the cache. public UndoCacheNode Head; /// The newest/last node in the cache. @@ -35,14 +36,16 @@ namespace MCGalaxy.Util { /// Last time this undo buffer was cleared. public DateTime LastClear; + /// Used to sychronise clearing an undo cache. + public ReaderWriterLockSlim ClearLock = new ReaderWriterLockSlim(); + public const int TimeDeltaMax = (1 << 13) - 1; /// Appends an item to the cache. public void Add(Level lvl, Player.UndoPos item) { DateTime time = Server.StartTime.AddTicks(item.timeDelta * TimeSpan.TicksPerSecond); - if (Head == null) { - Head = UndoCacheNode.Make(lvl, time); - Tail = Head; + if (Tail == null) { + Tail = UndoCacheNode.Make(lvl, time); Head = Tail; } if (lvl.name != Tail.MapName || lvl.Width != Tail.Width || lvl.Height != Tail.Height || @@ -60,15 +63,15 @@ namespace MCGalaxy.Util { /// Removes all items from the cache and resets the state to default. public void Clear() { Count = 0; - if( Head == null ) return; + if (Tail == null) return; LastClear = DateTime.UtcNow; - UndoCacheNode node = Head; - while( node != null ) { + UndoCacheNode node = Tail; + while (node != null) { node.Items = null; - node = node.Next; + node = node.Prev; } - Head = null; Tail = null; + Tail = null; Head = null; } } @@ -78,7 +81,7 @@ namespace MCGalaxy.Util { public int Width, Height, Length; public DateTime BaseTime; - public UndoCacheNode Prev, Next; + public UndoCacheNode Prev; public List Items = new List(); public static UndoCacheNode Make(Level lvl, DateTime time) { diff --git a/Player/Undo/UndoFile.cs b/Player/Undo/UndoFile.cs index 3a061a358..317b2850b 100644 --- a/Player/Undo/UndoFile.cs +++ b/Player/Undo/UndoFile.cs @@ -59,7 +59,11 @@ namespace MCGalaxy.Util { int numFiles = Directory.GetFiles(playerDir).Length; string path = Path.Combine(playerDir, numFiles + NewFormat.Extension); - NewFormat.SaveUndoData(p.UndoBuffer, path); + + UndoCache cache = p.UndoBuffer; + using (IDisposable locker = cache.ClearLock.AccquireReadLock()) { + NewFormat.SaveUndoData(cache, path); + } } public static void UndoPlayer(Player p, string target, Vec3S32[] marks, DateTime start, ref bool FoundUser) { diff --git a/Player/Undo/UndoFileCBin.cs b/Player/Undo/UndoFileCBin.cs index a1ebde824..99aff2c0d 100644 --- a/Player/Undo/UndoFileCBin.cs +++ b/Player/Undo/UndoFileCBin.cs @@ -70,6 +70,7 @@ namespace MCGalaxy.Util { } protected override void SaveUndoData(UndoCache buffer, string path) { + // TODO: should be writing Head first?? using (FileStream fs = File.Create(path)) { BinaryWriter w = new BinaryWriter(fs); long entriesPos = 0;