Merge branch 'UndoCleanup'

This commit is contained in:
UnknownShadow200 2016-02-25 22:45:13 +11:00
commit f8e83786c2
10 changed files with 268 additions and 86 deletions

View File

@ -16,6 +16,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 MCGalaxy.Util; using MCGalaxy.Util;
@ -52,7 +53,7 @@ namespace MCGalaxy.Commands {
Player who = PlayerInfo.Find(name); Player who = PlayerInfo.Find(name);
if (who != null) { if (who != null) {
FoundUser = true; FoundUser = true;
HighlightOnline(p, seconds, who); PerformHighlight(p, seconds, who.UndoBuffer);
} }
UndoFile.HighlightPlayer(p, name.ToLower(), seconds, ref FoundUser); UndoFile.HighlightPlayer(p, name.ToLower(), seconds, ref FoundUser);
@ -64,24 +65,31 @@ namespace MCGalaxy.Commands {
} }
} }
static void HighlightOnline(Player p, long seconds, Player who) { static void PerformHighlight(Player p, long seconds, UndoCache cache) {
for (int i = who.UndoBuffer.Count - 1; i >= 0; --i) { UndoCacheNode node = cache.Tail;
try { if (node == null) return;
Player.UndoPos undo = who.UndoBuffer[i];
Level foundLevel = LevelInfo.FindExact(undo.mapName);
if (foundLevel != p.level) continue;
byte b = foundLevel.GetTile(undo.x, undo.y, undo.z); while (node != null) {
DateTime time = Server.StartTime.AddSeconds(undo.timeDelta + seconds); Level lvl = LevelInfo.FindExact(node.MapName);
if (time < DateTime.UtcNow) break; if (lvl != p.level) continue;
List<UndoCacheItem> items = node.Items;
if (b == undo.newtype || Block.Convert(b) == Block.water || Block.Convert(b) == Block.lava) { for (int i = items.Count - 1; i >= 0; i--) {
UndoCacheItem item = items[i];
ushort x, y, z;
node.Unpack(item.Index, out x, out y, out z);
DateTime time = node.BaseTime.AddSeconds(item.TimeDelta + seconds);
if (time < DateTime.UtcNow) return;
byte b = lvl.GetTile(x, y, z);
if (b == item.NewType || Block.Convert(b) == Block.water || Block.Convert(b) == Block.lava) {
if (b == Block.air || Block.Convert(b) == Block.water || Block.Convert(b) == Block.lava) if (b == Block.air || Block.Convert(b) == Block.water || Block.Convert(b) == Block.lava)
p.SendBlockchange(undo.x, undo.y, undo.z, Block.red); p.SendBlockchange(x, y, z, Block.red);
else else
p.SendBlockchange(undo.x, undo.y, undo.z, Block.green); p.SendBlockchange(x, y, z, Block.green);
} }
} catch { } }
node = node.Prev;
} }
} }

View File

@ -16,6 +16,8 @@
permissions and limitations under the Licenses. permissions and limitations under the Licenses.
*/ */
using System; using System;
using System.Collections.Generic;
using MCGalaxy.Util;
namespace MCGalaxy.Commands { namespace MCGalaxy.Commands {
@ -30,22 +32,33 @@ namespace MCGalaxy.Commands {
public override void Use(Player p, string message) { public override void Use(Player p, string message) {
if (message != "") { Help(p); return; } if (message != "") { Help(p); return; }
PerformRedo(p, p.RedoBuffer);
for (int i = p.RedoBuffer.Count - 1; i >= 0; i--) {
Player.UndoPos Pos = p.RedoBuffer[i];
Level lvl = LevelInfo.FindExact(Pos.mapName);
if (lvl == null)
continue;
byte type = lvl.GetTile(Pos.x, Pos.y, Pos.z), extType = 0;
if (type == Block.custom_block)
extType = lvl.GetExtTile(Pos.x, Pos.y, Pos.z);
lvl.Blockchange(p, Pos.x, Pos.y, Pos.z, Pos.type, Pos.extType);
}
Player.SendMessage(p, "Redo performed."); Player.SendMessage(p, "Redo performed.");
} }
static void PerformRedo(Player p, UndoCache cache) {
UndoCacheNode node = cache.Tail;
if (node == null) return;
while (node != null) {
Level lvl = LevelInfo.FindExact(node.MapName);
if (lvl == null) continue;
List<UndoCacheItem> items = node.Items;
for (int i = items.Count - 1; i >= 0; i--) {
UndoCacheItem item = items[i];
ushort x, y, z;
node.Unpack(item.Index, out x, out y, out z);
byte type = lvl.GetTile(x, y, z), extType = 0;
if (type == Block.custom_block)
extType = lvl.GetExtTile(x, y, z);
lvl.Blockchange(p, x, y, z, item.Type, item.ExtType);
}
node = node.Prev;
}
}
public override void Help(Player p) { public override void Help(Player p) {
Player.SendMessage(p, "/redo - Redoes the Undo you just performed."); Player.SendMessage(p, "/redo - Redoes the Undo you just performed.");
} }

View File

@ -1,7 +1,7 @@
/* /*
Copyright 2011 MCGalaxy Copyright 2011 MCGalaxy
Dual-licensed under the Educational Community License, Version 2.0 and Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at obtain a copy of the Licenses at
@ -16,8 +16,7 @@
permissions and limitations under the Licenses. permissions and limitations under the Licenses.
*/ */
using System; using System;
using System.Globalization; using System.Collections.Generic;
using System.IO;
using MCGalaxy.Util; using MCGalaxy.Util;
namespace MCGalaxy.Commands namespace MCGalaxy.Commands
@ -89,12 +88,7 @@ namespace MCGalaxy.Commands
} }
Level saveLevel = null; Level saveLevel = null;
for (int i = who.UndoBuffer.Count - 1; i >= 0; --i) { PerformUndo(p, seconds, who.UndoBuffer, ref saveLevel);
try {
Player.UndoPos Pos = who.UndoBuffer[i];
if (!CheckBlockPlayer(p, seconds, Pos, ref saveLevel)) break;
} catch { }
}
bool foundUser = false; bool foundUser = false;
UndoFile.UndoPlayer(p, whoName.ToLower(), seconds, ref foundUser); UndoFile.UndoPlayer(p, whoName.ToLower(), seconds, ref foundUser);
@ -159,24 +153,41 @@ namespace MCGalaxy.Commands
p.level.Save(true); p.level.Save(true);
} }
bool CheckBlockPlayer(Player p, long seconds, Player.UndoPos undo, ref Level saveLevel) { static void PerformUndo(Player p, long seconds, UndoCache cache, ref Level saveLvl) {
Level lvl = LevelInfo.FindExact(undo.mapName); UndoCacheNode node = cache.Tail;
saveLevel = lvl; if (node == null) return;
byte b = lvl.GetTile(undo.x, undo.y, undo.z);
DateTime time = Server.StartTime.AddSeconds(undo.timeDelta + seconds);
if (time < DateTime.UtcNow) return false;
if (b == undo.newtype || Block.Convert(b) == Block.water || Block.Convert(b) == Block.lava) { while (node != null) {
undo.newtype = undo.type; undo.newExtType = undo.extType; Level lvl = LevelInfo.FindExact(node.MapName);
byte extType = 0; if (lvl == null) continue;
if (b == Block.custom_block) saveLvl = lvl;
extType = lvl.GetExtTile(undo.x, undo.y, undo.z); List<UndoCacheItem> items = node.Items;
lvl.Blockchange(p, undo.x, undo.y, undo.z, undo.type, undo.extType); for (int i = items.Count - 1; i >= 0; i--) {
undo.type = b; undo.extType = extType; UndoCacheItem item = items[i];
if (p != null) p.RedoBuffer.Add(undo); ushort x, y, z;
node.Unpack(item.Index, out x, out y, out z);
DateTime time = node.BaseTime.AddSeconds(item.TimeDelta + seconds);
if (time < DateTime.UtcNow) return;
byte b = lvl.GetTile(x, y, z);
if (b == item.NewType || Block.Convert(b) == Block.water || Block.Convert(b) == Block.lava) {
Player.UndoPos uP = default(Player.UndoPos);
uP.newtype = item.Type; uP.newExtType = item.ExtType;
byte extType = 0;
if (b == Block.custom_block) extType = lvl.GetExtTile(x, y, z);
lvl.Blockchange(p, x, y, z, item.Type, item.ExtType);
uP.type = b; uP.extType = extType;
uP.x = x; uP.y = y; uP.z = z;
uP.mapName = node.MapName;
time = node.BaseTime.AddSeconds(item.TimeDelta);
uP.timeDelta = (int)time.Subtract(Server.StartTime).TotalSeconds;
if (p != null) p.RedoBuffer.Add(lvl, uP);
}
}
node = node.Prev;
} }
return true;
} }
bool CheckBlockPhysics(Player p, long seconds, int i, Level.UndoPos undo) { bool CheckBlockPhysics(Player p, long seconds, int i, Level.UndoPos undo) {

View File

@ -160,7 +160,7 @@ namespace MCGalaxy {
Pos.type = oldType; Pos.extType = oldExtType; Pos.type = oldType; Pos.extType = oldExtType;
Pos.newtype = type; Pos.newExtType = extType; Pos.newtype = type; Pos.newExtType = extType;
Pos.timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds; Pos.timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds;
p.UndoBuffer.Add(Pos); p.UndoBuffer.Add(this, Pos);
} }
bool CheckTNTWarsChange(Player p, ushort x, ushort y, ushort z, ref byte type) { bool CheckTNTWarsChange(Player p, ushort x, ushort y, ushort z, ref byte type) {
@ -328,7 +328,7 @@ namespace MCGalaxy {
Pos.type = b; Pos.extType = extB; Pos.type = b; Pos.extType = extB;
Pos.newtype = type; Pos.newExtType = extType; Pos.newtype = type; Pos.newExtType = extType;
Pos.timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds; Pos.timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds;
p.UndoBuffer.Add(Pos); p.UndoBuffer.Add(this, Pos);
errorLocation = "Setting tile"; errorLocation = "Setting tile";
p.loginBlocks++; p.loginBlocks++;

View File

@ -443,6 +443,7 @@
<Compile Include="Player\Group\GroupProperties.cs" /> <Compile Include="Player\Group\GroupProperties.cs" />
<Compile Include="Player\Player.Handlers.cs" /> <Compile Include="Player\Player.Handlers.cs" />
<Compile Include="Player\PlayerInfo.cs" /> <Compile Include="Player\PlayerInfo.cs" />
<Compile Include="Player\Undo\UndoCache.cs" />
<Compile Include="Player\Waypoint.cs" /> <Compile Include="Player\Waypoint.cs" />
<Compile Include="Player\Player.Timers.cs" /> <Compile Include="Player\Player.Timers.cs" />
<Compile Include="Player\Undo\UndoFile.cs" /> <Compile Include="Player\Undo\UndoFile.cs" />

View File

@ -235,8 +235,8 @@ namespace MCGalaxy {
//Undo //Undo
public struct UndoPos { public ushort x, y, z; public byte type, extType, newtype, newExtType; public string mapName; public int timeDelta; } public struct UndoPos { public ushort x, y, z; public byte type, extType, newtype, newExtType; public string mapName; public int timeDelta; }
public List<UndoPos> UndoBuffer = new List<UndoPos>(); public UndoCache UndoBuffer = new UndoCache();
public List<UndoPos> RedoBuffer = new List<UndoPos>(); public UndoCache RedoBuffer = new UndoCache();
public bool showPortals = false; public bool showPortals = false;

111
Player/Undo/UndoCache.cs Normal file
View File

@ -0,0 +1,111 @@
/*
Copyright 2015 MCGalaxy
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
namespace MCGalaxy.Util {
public sealed class UndoCache {
/// <summary> The oldest/first node in the cache. </summary>
public UndoCacheNode Head;
/// <summary> The newest/last node in the cache. </summary>
public UndoCacheNode Tail;
/// <summary> Total number of items in the cache. </summary>
public volatile int Count;
/// <summary> Appends an item to the cache. </summary>
public void Add(Level lvl, Player.UndoPos item) {
DateTime time = Server.StartTime.AddSeconds(item.timeDelta);
if (Head == null) {
Head = UndoCacheNode.Make(lvl, time);
Tail = Head;
}
if (lvl.name != Tail.MapName || lvl.Width != Tail.Width || lvl.Height != Tail.Height ||
lvl.Length != Tail.Length || Math.Abs((time - Tail.BaseTime).TotalSeconds) > 32767) {
UndoCacheNode node = UndoCacheNode.Make(lvl, time);
Tail.Next = node; node.Prev = Tail;
Tail = node;
}
short timeDiff = (short)(time - Tail.BaseTime).TotalSeconds;
Tail.Items.Add(UndoCacheItem.Make(Tail, timeDiff, ref item));
Count++;
}
/// <summary> Removes all items from the cache and resets the state to default. </summary>
public void Clear() {
Count = 0;
if( Head == null ) return;
UndoCacheNode node = Head;
while( node != null ) {
node.Items.Clear();
node = node.Next;
}
Head = null; Tail = null;
}
}
public sealed class UndoCacheNode {
public string MapName;
public int Width, Height, Length;
public DateTime BaseTime;
public UndoCacheNode Prev, Next;
public List<UndoCacheItem> Items = new List<UndoCacheItem>();
public static UndoCacheNode Make(Level lvl, DateTime time) {
UndoCacheNode node = new UndoCacheNode();
node.MapName = lvl.name;
node.Width = lvl.Width; node.Height = lvl.Height; node.Length = lvl.Length;
node.BaseTime = time;
return node;
}
public void Unpack(int index, out ushort x, out ushort y, out ushort z) {
x = (ushort)(index % Width);
y = (ushort)(index / (Width * Length));
z = (ushort)((index / Width) % Length);
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct UndoCacheItem {
public int Index;
public byte Type, ExtType;
public byte NewType, NewExtType;
public short TimeDelta;
public static UndoCacheItem Make(UndoCacheNode node, short timeDelta, ref Player.UndoPos pos) {
UndoCacheItem item = default(UndoCacheItem);
item.Index = pos.x + node.Width * (pos.z + node.Length * pos.y);
item.Type = pos.type; item.ExtType = pos.extType;
item.NewType = pos.newtype; item.NewExtType = pos.newExtType;
item.TimeDelta = timeDelta;
return item;
}
}
}

View File

@ -30,6 +30,8 @@ namespace MCGalaxy.Util {
protected abstract void SaveUndoData(List<Player.UndoPos> buffer, string path); protected abstract void SaveUndoData(List<Player.UndoPos> buffer, string path);
protected abstract void SaveUndoData(UndoCache buffer, string path);
protected abstract void ReadUndoData(List<Player.UndoPos> buffer, string path); protected abstract void ReadUndoData(List<Player.UndoPos> buffer, string path);
protected abstract bool UndoEntry(Player p, string path, ref byte[] temp, long seconds); protected abstract bool UndoEntry(Player p, string path, ref byte[] temp, long seconds);
@ -39,7 +41,7 @@ namespace MCGalaxy.Util {
protected abstract string Extension { get; } protected abstract string Extension { get; }
public static void SaveUndo(Player p) { public static void SaveUndo(Player p) {
if( p == null || p.UndoBuffer == null || p.UndoBuffer.Count < 1) return; if( p == null || p.UndoBuffer.Count < 1) return;
CreateDefaultDirectories(); CreateDefaultDirectories();
if (Directory.GetDirectories(undoDir).Length >= Server.totalUndo) { if (Directory.GetDirectories(undoDir).Length >= Server.totalUndo) {
@ -54,7 +56,7 @@ namespace MCGalaxy.Util {
int numFiles = Directory.GetFiles(playerDir).Length; int numFiles = Directory.GetFiles(playerDir).Length;
string path = Path.Combine(playerDir, numFiles + NewFormat.Extension); string path = Path.Combine(playerDir, numFiles + NewFormat.Extension);
NewFormat.SaveUndoData(p.UndoBuffer.ToList(), path); NewFormat.SaveUndoData(p.UndoBuffer, path);
} }
public static void UndoPlayer(Player p, string targetName, long seconds, ref bool FoundUser) { public static void UndoPlayer(Player p, string targetName, long seconds, ref bool FoundUser) {
@ -96,11 +98,11 @@ namespace MCGalaxy.Util {
} }
static int CompareFiles(string a, string b) { static int CompareFiles(string a, string b) {
int aNumStart = a.LastIndexOf('\\'), bNumStart = b.LastIndexOf('\\'); int aNumStart = a.LastIndexOf('\\'), bNumStart = b.LastIndexOf('\\');
int aNumEnd = a.LastIndexOf('.'), bNumEnd = b.LastIndexOf('.'); int aNumEnd = a.LastIndexOf('.'), bNumEnd = b.LastIndexOf('.');
if (aNumStart < 0 || bNumStart < 0 || aNumEnd < 0 || if (aNumStart < 0 || bNumStart < 0 || aNumEnd < 0 ||
bNumEnd < 0 || aNumStart >= aNumEnd || bNumStart >= bNumEnd) bNumEnd < 0 || aNumStart >= aNumEnd || bNumStart >= bNumEnd)
return a.CompareTo(b); return a.CompareTo(b);
int aNum, bNum; int aNum, bNum;
if (!int.TryParse(a.Substring(aNumStart + 1, aNumEnd - aNumStart - 1), out aNum) || if (!int.TryParse(a.Substring(aNumStart + 1, aNumEnd - aNumStart - 1), out aNum) ||

View File

@ -32,24 +32,57 @@ namespace MCGalaxy.Util {
using (FileStream fs = File.Create(path)) { using (FileStream fs = File.Create(path)) {
BinaryWriter w = new BinaryWriter(fs); BinaryWriter w = new BinaryWriter(fs);
long entriesPos = 0; long entriesPos = 0;
ChunkHeader lastChunk = default(ChunkHeader); ChunkHeader last = default(ChunkHeader);
foreach (Player.UndoPos uP in buffer) { foreach (Player.UndoPos uP in buffer) {
DateTime time = Server.StartTime.AddSeconds(uP.timeDelta); DateTime time = Server.StartTime.AddSeconds(uP.timeDelta);
int timeDiff = (int)(time - lastChunk.BaseTime).TotalSeconds; int timeDiff = (int)(time - last.BaseTime).TotalSeconds;
if (lastChunk.LevelName != uP.mapName || timeDiff > 65535 || lastChunk.Entries == ushort.MaxValue) { if (last.LevelName != uP.mapName || timeDiff > 65535 || last.Entries == ushort.MaxValue) {
WriteChunkEntries(w, lastChunk.Entries, entriesPos); WriteChunkEntries(w, last.Entries, entriesPos);
lastChunk = WriteEmptyChunk(w, uP, ref entriesPos); last = WriteEmptyChunk(w, uP.mapName, time, ref entriesPos);
} }
w.Write((ushort)timeDiff); w.Write((ushort)timeDiff);
w.Write(uP.x); w.Write(uP.y); w.Write(uP.z); w.Write(uP.x); w.Write(uP.y); w.Write(uP.z);
w.Write(uP.type); w.Write(uP.extType); w.Write(uP.type); w.Write(uP.extType);
w.Write(uP.newtype); w.Write(uP.newExtType); w.Write(uP.newtype); w.Write(uP.newExtType);
lastChunk.Entries++; last.Entries++;
}
if (last.Entries > 0)
WriteChunkEntries(w, last.Entries, entriesPos);
}
}
protected override void SaveUndoData(UndoCache buffer, string path) {
using (FileStream fs = File.Create(path)) {
BinaryWriter w = new BinaryWriter(fs);
long entriesPos = 0;
ChunkHeader last = default(ChunkHeader);
UndoCacheNode node = buffer.Tail;
while (node != null) {
List<UndoCacheItem> items = node.Items;
for (int i = 0; i < items.Count; i++) {
UndoCacheItem uP = items[i];
DateTime time = node.BaseTime.AddSeconds(uP.TimeDelta);
int timeDiff = (int)(time - last.BaseTime).TotalSeconds;
if (last.LevelName != node.MapName || timeDiff > 65535 || last.Entries == ushort.MaxValue) {
WriteChunkEntries(w, last.Entries, entriesPos);
last = WriteEmptyChunk(w, node.MapName, time, ref entriesPos);
}
ushort x, y, z;
node.Unpack(uP.Index, out x, out y, out z);
w.Write((ushort)timeDiff);
w.Write(x); w.Write(y); w.Write(z);
w.Write(uP.Type); w.Write(uP.ExtType);
w.Write(uP.NewType); w.Write(uP.NewExtType);
last.Entries++;
}
if (last.Entries > 0)
WriteChunkEntries(w, last.Entries, entriesPos);
node = node.Prev;
} }
if (lastChunk.Entries > 0)
WriteChunkEntries(w, lastChunk.Entries, entriesPos);
} }
} }
@ -102,8 +135,8 @@ namespace MCGalaxy.Util {
fs.Read(temp, 0, chunk.Entries * entrySize); fs.Read(temp, 0, chunk.Entries * entrySize);
for (int j = chunk.Entries - 1; j >= 0; j-- ) { for (int j = chunk.Entries - 1; j >= 0; j-- ) {
int offset = j * entrySize; int offset = j * entrySize;
DateTime time = chunk.BaseTime.AddSeconds(U16(temp, offset + 0)); DateTime time = chunk.BaseTime.AddSeconds(U16(temp, offset + 0));
if (time.AddSeconds(seconds) < now) return false; if (time.AddSeconds(seconds) < now) return false;
Pos.x = U16(temp, offset + 2); Pos.y = U16(temp, offset + 4); Pos.z = U16(temp, offset + 6); Pos.x = U16(temp, offset + 2); Pos.y = U16(temp, offset + 4); Pos.z = U16(temp, offset + 6);
@ -117,7 +150,7 @@ namespace MCGalaxy.Util {
Pos.newtype = oldType; Pos.newExtType = oldExtType; Pos.newtype = oldType; Pos.newExtType = oldExtType;
Pos.extType = newExtType; Pos.timeDelta = timeDelta; Pos.extType = newExtType; Pos.timeDelta = timeDelta;
lvl.Blockchange(p, Pos.x, Pos.y, Pos.z, Pos.newtype, Pos.newExtType); lvl.Blockchange(p, Pos.x, Pos.y, Pos.z, Pos.newtype, Pos.newExtType);
if (p != null) p.RedoBuffer.Add(Pos); if (p != null) p.RedoBuffer.Add(lvl, Pos);
} }
} }
} }
@ -145,8 +178,8 @@ namespace MCGalaxy.Util {
fs.Read(temp, 0, chunk.Entries * entrySize); fs.Read(temp, 0, chunk.Entries * entrySize);
for (int j = chunk.Entries - 1; j >= 0; j-- ) { for (int j = chunk.Entries - 1; j >= 0; j-- ) {
int offset = j * entrySize; int offset = j * entrySize;
DateTime time = chunk.BaseTime.AddSeconds(U16(temp, offset + 0)); DateTime time = chunk.BaseTime.AddSeconds(U16(temp, offset + 0));
if (time.AddSeconds(seconds) < now) return false; if (time.AddSeconds(seconds) < now) return false;
ushort x = U16(temp, offset + 2), y = U16(temp, offset + 4), z = U16(temp, offset + 6); ushort x = U16(temp, offset + 2), y = U16(temp, offset + 4), z = U16(temp, offset + 6);
@ -167,7 +200,7 @@ namespace MCGalaxy.Util {
} }
static ushort U16(byte[] buffer, int offset) { static ushort U16(byte[] buffer, int offset) {
return (ushort)(buffer[offset + 0] | buffer[offset + 1] << 8); return (ushort)(buffer[offset + 0] | buffer[offset + 1] << 8);
} }
static bool CheckChunk(ChunkHeader chunk, DateTime now, long seconds, Player p, out Level lvl) { static bool CheckChunk(ChunkHeader chunk, DateTime now, long seconds, Player p, out Level lvl) {
@ -216,9 +249,8 @@ namespace MCGalaxy.Util {
w.BaseStream.Seek(curPos, SeekOrigin.Begin); w.BaseStream.Seek(curPos, SeekOrigin.Begin);
} }
static ChunkHeader WriteEmptyChunk(BinaryWriter w, Player.UndoPos uP, ref long entriesPos) { static ChunkHeader WriteEmptyChunk(BinaryWriter w, string mapName, DateTime time, ref long entriesPos) {
DateTime time = Server.StartTime.AddSeconds(uP.timeDelta); byte[] mapBytes = Encoding.UTF8.GetBytes(mapName);
byte[] mapBytes = Encoding.UTF8.GetBytes(uP.mapName);
w.Write((ushort)mapBytes.Length); w.Write((ushort)mapBytes.Length);
w.Write(mapBytes); w.Write(mapBytes);
w.Write(time.ToLocalTime().Ticks); w.Write(time.ToLocalTime().Ticks);
@ -226,7 +258,7 @@ namespace MCGalaxy.Util {
entriesPos = w.BaseStream.Position; entriesPos = w.BaseStream.Position;
w.Write((ushort)0); w.Write((ushort)0);
ChunkHeader header = default(ChunkHeader); ChunkHeader header = default(ChunkHeader);
header.LevelName = uP.mapName; header.BaseTime = time; header.LevelName = mapName; header.BaseTime = time;
return header; return header;
} }
} }

View File

@ -30,7 +30,7 @@ namespace MCGalaxy.Util {
protected override void SaveUndoData(List<Player.UndoPos> buffer, string path) { protected override void SaveUndoData(List<Player.UndoPos> buffer, string path) {
using (StreamWriter w = File.CreateText(path)) { using (StreamWriter w = File.CreateText(path)) {
foreach (Player.UndoPos uP in buffer) { foreach (Player.UndoPos uP in buffer) {
DateTime time = Server.StartTimeLocal.AddSeconds(uP.timeDelta); DateTime time = Server.StartTimeLocal.AddSeconds(uP.timeDelta);
w.Write( w.Write(
uP.mapName + " " + uP.x + " " + uP.y + " " + uP.z + " " + uP.mapName + " " + uP.x + " " + uP.y + " " + uP.z + " " +
time.ToString(CultureInfo.InvariantCulture).Replace(' ', '&') + " " + time.ToString(CultureInfo.InvariantCulture).Replace(' ', '&') + " " +
@ -39,6 +39,10 @@ namespace MCGalaxy.Util {
} }
} }
protected override void SaveUndoData(UndoCache buffer, string path) {
throw new NotImplementedException("The .txt based undo files are deprecated.");
}
protected override void ReadUndoData(List<Player.UndoPos> buffer, string path) { protected override void ReadUndoData(List<Player.UndoPos> buffer, string path) {
Player.UndoPos Pos; Player.UndoPos Pos;
Pos.extType = 0; Pos.newExtType = 0; Pos.extType = 0; Pos.newExtType = 0;
@ -74,14 +78,14 @@ namespace MCGalaxy.Util {
try { try {
// line format: mapName x y z date oldblock newblock // line format: mapName x y z date oldblock newblock
if (!InTime(lines[(i * 7) - 3], seconds)) return false; if (!InTime(lines[(i * 7) - 3], seconds)) return false;
Level foundLevel = LevelInfo.FindExact(lines[(i * 7) - 7]); Level lvl = LevelInfo.FindExact(lines[(i * 7) - 7]);
if (foundLevel == null) continue; if (lvl == null) continue;
Pos.mapName = foundLevel.name; Pos.mapName = lvl.name;
Pos.x = Convert.ToUInt16(lines[(i * 7) - 6]); Pos.x = Convert.ToUInt16(lines[(i * 7) - 6]);
Pos.y = Convert.ToUInt16(lines[(i * 7) - 5]); Pos.y = Convert.ToUInt16(lines[(i * 7) - 5]);
Pos.z = Convert.ToUInt16(lines[(i * 7) - 4]); Pos.z = Convert.ToUInt16(lines[(i * 7) - 4]);
Pos.type = foundLevel.GetTile(Pos.x, Pos.y, Pos.z); Pos.type = lvl.GetTile(Pos.x, Pos.y, Pos.z);
if (Pos.type == Convert.ToByte(lines[(i * 7) - 1]) || Block.Convert(Pos.type) == Block.water || if (Pos.type == Convert.ToByte(lines[(i * 7) - 1]) || Block.Convert(Pos.type) == Block.water ||
Block.Convert(Pos.type) == Block.lava || Pos.type == Block.grass) { Block.Convert(Pos.type) == Block.lava || Pos.type == Block.grass) {
@ -89,8 +93,8 @@ namespace MCGalaxy.Util {
Pos.newtype = Convert.ToByte(lines[(i * 7) - 2]); Pos.newtype = Convert.ToByte(lines[(i * 7) - 2]);
Pos.timeDelta = timeDelta; Pos.timeDelta = timeDelta;
foundLevel.Blockchange(p, Pos.x, Pos.y, Pos.z, Pos.newtype, 0); lvl.Blockchange(p, Pos.x, Pos.y, Pos.z, Pos.newtype, 0);
if (p != null) p.RedoBuffer.Add(Pos); if (p != null) p.RedoBuffer.Add(lvl, Pos);
} }
} catch { } catch {
} }