mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-22 03:55:18 -04:00
Start using read locks.
This commit is contained in:
parent
35c4e324b7
commit
36465e8f2e
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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"; } }
|
||||
|
||||
/// <summary> Point in time that the /undo should go backwards up to. </summary>
|
||||
@ -36,12 +36,19 @@ namespace MCGalaxy.Drawing.Ops {
|
||||
|
||||
public override IEnumerable<DrawOpBlock> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,14 +42,18 @@ namespace MCGalaxy.Drawing.Ops {
|
||||
public override long GetBlocksAffected(Level lvl, Vec3S32[] marks) { return -1; }
|
||||
|
||||
public override IEnumerable<DrawOpBlock> 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;
|
||||
|
@ -68,7 +68,7 @@ namespace MCGalaxy.Gui {
|
||||
|
||||
UpdateListTimer.Elapsed += delegate {
|
||||
try {
|
||||
UpdateClientList(Player.players);
|
||||
UpdateClientList(null);
|
||||
UpdateMapList();
|
||||
}
|
||||
catch { } // needed for slower computers
|
||||
|
@ -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; }
|
||||
}
|
||||
|
@ -18,12 +18,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace MCGalaxy.Util {
|
||||
|
||||
public sealed class UndoCache {
|
||||
|
||||
/// <summary> The oldest/first node in the cache. </summary>
|
||||
|
||||
/// <summary> The olded/first node in the cache. </summary>
|
||||
public UndoCacheNode Head;
|
||||
|
||||
/// <summary> The newest/last node in the cache. </summary>
|
||||
@ -35,14 +36,16 @@ namespace MCGalaxy.Util {
|
||||
/// <summary> Last time this undo buffer was cleared. </summary>
|
||||
public DateTime LastClear;
|
||||
|
||||
/// <summary> Used to sychronise clearing an undo cache. </summary>
|
||||
public ReaderWriterLockSlim ClearLock = new ReaderWriterLockSlim();
|
||||
|
||||
public const int TimeDeltaMax = (1 << 13) - 1;
|
||||
|
||||
/// <summary> Appends an item to the cache. </summary>
|
||||
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 {
|
||||
/// <summary> Removes all items from the cache and resets the state to default. </summary>
|
||||
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<UndoCacheItem> Items = new List<UndoCacheItem>();
|
||||
|
||||
public static UndoCacheNode Make(Level lvl, DateTime time) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user