mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-24 05:03:34 -04:00
kill all the obsolete undo code
This commit is contained in:
parent
6838c0964b
commit
b306c81030
@ -54,12 +54,6 @@ namespace MCGalaxy.Commands.Building {
|
||||
|
||||
TimeSpan delta = GetDelta(p, parts[0], parts.Length > 1 ? parts[1] : "30m");
|
||||
if (delta == TimeSpan.MinValue) return;
|
||||
|
||||
if (parts.Length > 1 && parts[1].CaselessEq("update")) {
|
||||
UndoFormat.UpgradePlayerUndoFiles(parts[0]);
|
||||
Player.Message(p, "Updated undo files for " + parts[0] + " to the new binary format.");
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3S32[] marks = new Vec3S32[] { Vec3U16.MaxVal, Vec3U16.MaxVal };
|
||||
if (undoPhysics)
|
||||
|
@ -148,13 +148,6 @@ namespace MCGalaxy {
|
||||
|
||||
BlockDB.Add(p, x, y, z, flags,
|
||||
oldBlock, oldExtBlock, block, ext);
|
||||
Player.UndoPos Pos;
|
||||
Pos.x = x; Pos.y = y; Pos.z = z;
|
||||
Pos.mapName = this.name;
|
||||
Pos.type = oldBlock; Pos.extType = oldExtBlock;
|
||||
Pos.newtype = block; Pos.newExtType = ext;
|
||||
Pos.timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds;
|
||||
p.UndoBuffer.Add(this, Pos);
|
||||
}
|
||||
|
||||
bool CheckTNTWarsChange(Player p, ushort x, ushort y, ushort z, ref byte block) {
|
||||
@ -277,15 +270,6 @@ namespace MCGalaxy {
|
||||
if (old == Block.lava_sponge && physics > 0 && block != Block.lava_sponge)
|
||||
OtherPhysics.DoSpongeRemoved(this, PosToInt(x, y, z), true);
|
||||
|
||||
errorLocation = "Undo buffer filling";
|
||||
Player.UndoPos Pos;
|
||||
Pos.x = x; Pos.y = y; Pos.z = z;
|
||||
Pos.mapName = name;
|
||||
Pos.type = old; Pos.extType = extOld;
|
||||
Pos.newtype = block; Pos.newExtType = extBlock;
|
||||
Pos.timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds;
|
||||
p.UndoBuffer.Add(this, Pos);
|
||||
|
||||
errorLocation = "Setting tile";
|
||||
p.IncrementBlockStats(block, drawn);
|
||||
|
||||
@ -304,17 +288,10 @@ namespace MCGalaxy {
|
||||
bool diffBlock = old == Block.custom_block ? extOld != extBlock :
|
||||
Block.Convert(old) != Block.Convert(block);
|
||||
return diffBlock;
|
||||
} catch (OutOfMemoryException) {
|
||||
Player.Message(p, "Undo buffer too big! Cleared!");
|
||||
p.UndoBuffer.Clear();
|
||||
p.RemoveInvalidUndos();
|
||||
goto retry;
|
||||
} catch (Exception e) {
|
||||
Server.ErrorLog(e);
|
||||
Chat.MessageOps(p.name + " triggered a non-fatal error on " + ColoredName);
|
||||
Chat.MessageOps("Error location: " + errorLocation);
|
||||
Server.s.Log(p.name + " triggered a non-fatal error on " + ColoredName);
|
||||
Server.s.Log("Error location: " + errorLocation);
|
||||
Chat.MessageOps(p.name + " triggered a non-fatal error on " + ColoredName + ", %Sat location: " + errorLocation);
|
||||
Server.s.Log(p.name + " triggered a non-fatal error on " + ColoredName + ", %Sat location: " + errorLocation);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -566,10 +566,8 @@
|
||||
<Compile Include="Player\PlayerInfo.cs" />
|
||||
<Compile Include="Player\SpamChecker.cs" />
|
||||
<Compile Include="Player\TabList.cs" />
|
||||
<Compile Include="Player\Undo\UndoCache.cs" />
|
||||
<Compile Include="Player\Undo\UndoFormat.Helpers.cs" />
|
||||
<Compile Include="Player\Undo\UndoFormatCBin.cs" />
|
||||
<Compile Include="Player\Undo\UndoFormatOnline.cs" />
|
||||
<Compile Include="Player\Warp.cs" />
|
||||
<Compile Include="Player\Player.Timers.cs" />
|
||||
<Compile Include="Player\Undo\UndoFormat.cs" />
|
||||
|
@ -51,7 +51,6 @@ namespace MCGalaxy {
|
||||
} catch ( ObjectDisposedException ) {
|
||||
// Player is no longer connected, socket was closed
|
||||
// Mark this as disconnected and remove them from active connection list
|
||||
Player.SaveUndo(p);
|
||||
connections.Remove(p);
|
||||
p.RemoveFromPending();
|
||||
p.disconnected = true;
|
||||
|
@ -211,8 +211,6 @@ namespace MCGalaxy {
|
||||
public bool Mojangaccount { get { return truename.IndexOf('@') >= 0; } }
|
||||
|
||||
//Undo
|
||||
public struct UndoPos { public ushort x, y, z; public byte type, extType, newtype, newExtType; public string mapName; public int timeDelta; }
|
||||
public UndoCache UndoBuffer = new UndoCache();
|
||||
internal VolatileArray<UndoDrawOpEntry> DrawOps = new VolatileArray<UndoDrawOpEntry>(false);
|
||||
internal readonly object pendingDrawOpsLock = new object();
|
||||
internal List<PendingDrawOp> PendingDrawOps = new List<PendingDrawOp>();
|
||||
|
@ -120,7 +120,6 @@ namespace MCGalaxy {
|
||||
cuboided, totalKicked, time.ToDBTime(), name);
|
||||
|
||||
Server.zombie.SaveZombieStats(this);
|
||||
SaveUndo(this);
|
||||
}
|
||||
|
||||
#region == GLOBAL MESSAGES ==
|
||||
@ -286,7 +285,6 @@ namespace MCGalaxy {
|
||||
if (name == "") {
|
||||
if (socket != null) CloseSocket();
|
||||
connections.Remove(this);
|
||||
SaveUndo(this);
|
||||
disconnected = true;
|
||||
return;
|
||||
}
|
||||
@ -368,13 +366,8 @@ namespace MCGalaxy {
|
||||
}
|
||||
}
|
||||
|
||||
public static void SaveUndo(Player p) {
|
||||
try {
|
||||
UndoFormat.SaveUndo(p);
|
||||
} catch (Exception e) {
|
||||
Server.s.Log("Error saving undo data for " + p.name + "!"); Server.ErrorLog(e);
|
||||
}
|
||||
}
|
||||
[Obsolete]
|
||||
public static void SaveUndo(Player p) { }
|
||||
|
||||
public void Dispose() {
|
||||
connections.Remove(this);
|
||||
@ -383,7 +376,6 @@ namespace MCGalaxy {
|
||||
if (CopyBuffer != null)
|
||||
CopyBuffer.Clear();
|
||||
DrawOps.Clear();
|
||||
UndoBuffer.Clear();
|
||||
spamChecker.Clear();
|
||||
spyChatRooms.Clear();
|
||||
}
|
||||
@ -523,14 +515,6 @@ namespace MCGalaxy {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal void RemoveInvalidUndos() {
|
||||
UndoDrawOpEntry[] items = DrawOps.Items;
|
||||
for (int i = 0; i < items.Length; i++) {
|
||||
if (items[i].End < UndoBuffer.LastClear)
|
||||
DrawOps.Remove(items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void AddNote(string target, Player who, string type) {
|
||||
if (!Server.LogNotes) return;
|
||||
|
@ -1,166 +0,0 @@
|
||||
/*
|
||||
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.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace MCGalaxy.Undo {
|
||||
|
||||
public sealed class UndoCache {
|
||||
|
||||
/// <summary> The olded/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> 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();
|
||||
|
||||
/// <summary> Used to sychronise adding to an undo cache. </summary>
|
||||
public object AddLock = new object();
|
||||
|
||||
public const int TimeDeltaMax = (1 << 13) - 1;
|
||||
|
||||
/// <summary> Appends an item to the cache. </summary>
|
||||
public void Add(Level lvl, Player.UndoPos item) {
|
||||
lock (AddLock) {
|
||||
DateTime time = Server.StartTime.AddTicks(item.timeDelta * TimeSpan.TicksPerSecond);
|
||||
if (Tail == null) {
|
||||
Tail = UndoCacheNode.Make(lvl, time); Head = Tail;
|
||||
}
|
||||
|
||||
if (lvl.name != Tail.MapName || lvl.Width != Tail.Width || lvl.Height != Tail.Height ||
|
||||
lvl.Length != Tail.Length || Math.Abs((time - Tail.BaseTime).TotalSeconds) > TimeDeltaMax) {
|
||||
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 (Tail == null) return;
|
||||
LastClear = DateTime.UtcNow;
|
||||
|
||||
UndoCacheNode node = Tail;
|
||||
while (node != null) {
|
||||
node.Items = null;
|
||||
node = node.Prev;
|
||||
}
|
||||
Tail = null; Head = 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, NewType;
|
||||
public ushort Flags; // upper 2 bits for 'ext' or 'physics' type, lower 14 bits for time delta.
|
||||
|
||||
public short TimeDelta {
|
||||
get {
|
||||
int delta = Flags & 0x3FFF;
|
||||
return delta >= 0x2000 ? (short)(delta - 16384) : (short)delta;
|
||||
}
|
||||
}
|
||||
|
||||
public void GetBlock(out byte type, out byte extType) {
|
||||
if ((Flags & (1 << 14)) != 0) {
|
||||
type = Block.custom_block; extType = Type;
|
||||
} else {
|
||||
type = Type; extType = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void GetNewBlock(out byte type, out byte extType) {
|
||||
if ((Flags & (1 << 15)) != 0) {
|
||||
type = Block.custom_block; extType = NewType;
|
||||
} else {
|
||||
type = NewType; extType = 0;
|
||||
}
|
||||
}
|
||||
|
||||
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.Flags = (ushort)(timeDelta & 0x3FFF);
|
||||
|
||||
if (pos.type == Block.custom_block) {
|
||||
item.Type = pos.extType;
|
||||
item.Flags |= (ushort)(1 << 14);
|
||||
} else {
|
||||
item.Type = pos.type;
|
||||
}
|
||||
if (pos.newtype == Block.custom_block) {
|
||||
item.NewType = pos.newExtType;
|
||||
item.Flags |= (ushort)(1 << 15);
|
||||
} else {
|
||||
item.NewType = pos.newtype;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
public static UndoCacheItem Make(UndoCacheNode node, short timeDelta, Player.UndoPos pos) {
|
||||
return Make(node, timeDelta, ref pos);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class UndoDrawOpEntry {
|
||||
public string DrawOpName;
|
||||
public string LevelName;
|
||||
public DateTime Start, End;
|
||||
}
|
||||
}
|
@ -110,47 +110,6 @@ namespace MCGalaxy.Undo {
|
||||
buffer.Send(true);
|
||||
}
|
||||
|
||||
|
||||
public static void UpgradePlayerUndoFiles(string name) {
|
||||
UpgradeFiles(undoDir, name);
|
||||
UpgradeFiles(prevUndoDir, name);
|
||||
}
|
||||
|
||||
static void UpgradeFiles(string dir, string name) {
|
||||
string path = Path.Combine(dir, name);
|
||||
if (!Directory.Exists(path)) return;
|
||||
string[] files = Directory.GetFiles(path);
|
||||
List<Player.UndoPos> buffer = new List<Player.UndoPos>();
|
||||
UndoFormatArgs args = new UndoFormatArgs(null, DateTime.MinValue, DateTime.MaxValue, null);
|
||||
|
||||
for (int i = 0; i < files.Length; i++) {
|
||||
path = files[i];
|
||||
if (!path.EndsWith(BinFormat.Ext) && !path.EndsWith(TxtFormat.Ext)) continue;
|
||||
IEnumerable<UndoFormatEntry> data = null;
|
||||
Player.UndoPos pos;
|
||||
|
||||
using (FileStream s = File.OpenRead(path)) {
|
||||
data = path.EndsWith(BinFormat.Ext)
|
||||
? BinFormat.GetEntries(s, args) : TxtFormat.GetEntries(s, args);
|
||||
|
||||
foreach (UndoFormatEntry P in data) {
|
||||
pos.x = P.X; pos.y = P.Y; pos.z = P.Z;
|
||||
pos.type = P.Block; pos.extType = P.ExtBlock;
|
||||
pos.newtype = P.NewBlock; pos.newExtType = P.NewExtBlock;
|
||||
|
||||
pos.timeDelta = (int)P.Time.Subtract(Server.StartTimeLocal).TotalSeconds;
|
||||
pos.mapName = P.LevelName;
|
||||
buffer.Add(pos);
|
||||
}
|
||||
|
||||
buffer.Reverse();
|
||||
string newPath = Path.ChangeExtension(path, NewFormat.Ext);
|
||||
NewFormat.Save(buffer, newPath);
|
||||
}
|
||||
File.Delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
static void UndoBlock(UndoFormatArgs args, Level lvl, UndoFormatEntry P) {
|
||||
byte lvlBlock = lvl.GetTile(P.X, P.Y, P.Z);
|
||||
if (lvlBlock == P.NewBlock || Block.Convert(lvlBlock) == Block.water
|
||||
|
@ -20,6 +20,12 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace MCGalaxy.Undo {
|
||||
|
||||
public sealed class UndoDrawOpEntry {
|
||||
public string DrawOpName;
|
||||
public string LevelName;
|
||||
public DateTime Start, End;
|
||||
}
|
||||
|
||||
/// <summary> Retrieves and saves undo data in a particular format. </summary>
|
||||
/// <remarks> Note most formats only support retrieving undo data. </remarks>
|
||||
@ -30,43 +36,8 @@ namespace MCGalaxy.Undo {
|
||||
public static UndoFormat BinFormat = new UndoFormatBin();
|
||||
public static UndoFormat NewFormat = new UndoFormatCBin();
|
||||
|
||||
protected abstract void Save(List<Player.UndoPos> buffer, string path);
|
||||
|
||||
protected abstract void Save(UndoCache buffer, string path);
|
||||
|
||||
protected abstract IEnumerable<UndoFormatEntry> GetEntries(Stream s, UndoFormatArgs args);
|
||||
|
||||
protected abstract string Ext { get; }
|
||||
|
||||
/// <summary> Saves the undo data for the given player to disc. </summary>
|
||||
/// <remarks> Clears the player's in-memory undo buffer on success. </remarks>
|
||||
public static void SaveUndo(Player p) {
|
||||
if (p == null || p.UndoBuffer.Count < 1) return;
|
||||
|
||||
CreateDefaultDirectories();
|
||||
if (Directory.GetDirectories(undoDir).Length >= Server.totalUndo) {
|
||||
Directory.Delete(prevUndoDir, true);
|
||||
Directory.Move(undoDir, prevUndoDir);
|
||||
Directory.CreateDirectory(undoDir);
|
||||
}
|
||||
|
||||
string playerDir = Path.Combine(undoDir, p.name.ToLower());
|
||||
if (!Directory.Exists(playerDir))
|
||||
Directory.CreateDirectory(playerDir);
|
||||
|
||||
int numFiles = Directory.GetFiles(playerDir).Length;
|
||||
string path = Path.Combine(playerDir, numFiles + NewFormat.Ext);
|
||||
|
||||
UndoCache cache = p.UndoBuffer;
|
||||
using (IDisposable locker = cache.ClearLock.AccquireReadLock()) {
|
||||
NewFormat.Save(cache, path);
|
||||
}
|
||||
|
||||
using (IDisposable locker = cache.ClearLock.AccquireWriteLock()) {
|
||||
lock (cache.AddLock)
|
||||
cache.Clear();
|
||||
}
|
||||
}
|
||||
protected abstract IEnumerable<UndoFormatEntry> GetEntries(Stream s, UndoFormatArgs args);
|
||||
protected abstract string Ext { get; }
|
||||
|
||||
/// <summary> Gets a list of all undo file names for the given player. </summary>
|
||||
/// <remarks> This list is sorted, such that the first element is the
|
||||
@ -121,14 +92,6 @@ namespace MCGalaxy.Undo {
|
||||
return a.CompareTo(b);
|
||||
return aNum.CompareTo(bNum);
|
||||
}
|
||||
|
||||
/// <summary> Creates the default base directories used to store undo data on disc. </summary>
|
||||
public static void CreateDefaultDirectories() {
|
||||
if (!Directory.Exists(undoDir))
|
||||
Directory.CreateDirectory(undoDir);
|
||||
if (!Directory.Exists(prevUndoDir))
|
||||
Directory.CreateDirectory(prevUndoDir);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Arguments provided to an UndoFormat for retrieving undo data. </summary>
|
||||
|
@ -26,14 +26,6 @@ namespace MCGalaxy.Undo {
|
||||
|
||||
protected override string Ext { get { return ".unbin"; } }
|
||||
const int entrySize = 12;
|
||||
|
||||
protected override void Save(List<Player.UndoPos> buffer, string path) {
|
||||
throw new NotSupportedException("Non-optimised binary undo files have been deprecated");
|
||||
}
|
||||
|
||||
protected override void Save(UndoCache buffer, string path) {
|
||||
throw new NotSupportedException("Non-optimised binary undo files have been deprecated");
|
||||
}
|
||||
|
||||
protected override IEnumerable<UndoFormatEntry> GetEntries(Stream s, UndoFormatArgs args) {
|
||||
List<ChunkHeader> list = new List<ChunkHeader>();
|
||||
|
@ -28,81 +28,12 @@ namespace MCGalaxy.Undo {
|
||||
protected override string Ext { get { return ".uncbin"; } }
|
||||
const int entrySize = 8;
|
||||
|
||||
protected override void Save(List<Player.UndoPos> buffer, string path) {
|
||||
UndoCacheNode node = new UndoCacheNode();
|
||||
string lastLoggedName = "";
|
||||
|
||||
using (FileStream fs = File.Create(path)) {
|
||||
BinaryWriter w = new BinaryWriter(fs);
|
||||
long entriesPos = 0;
|
||||
ChunkHeader last = default(ChunkHeader);
|
||||
|
||||
foreach (Player.UndoPos uP in buffer) {
|
||||
DateTime time = Server.StartTime.AddSeconds(uP.timeDelta);
|
||||
int timeDiff = (int)(time - last.BaseTime).TotalSeconds;
|
||||
if (last.LevelName != uP.mapName || timeDiff > (65535 >> 2) || last.Entries == ushort.MaxValue) {
|
||||
if (!LevelInfo.ExistsOffline(uP.mapName)) {
|
||||
if (uP.mapName != lastLoggedName) {
|
||||
lastLoggedName = uP.mapName;
|
||||
Server.s.Log("Missing map file \"" + lastLoggedName+ "\", skipping undo entries");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Vec3U16 dims = IMapImporter.Formats[0].ReadDimensions(LevelInfo.LevelPath(uP.mapName));
|
||||
node.Width = dims.X; node.Height = dims.Y; node.Length = dims.Z;
|
||||
WriteChunkEntries(w, last.Entries, entriesPos);
|
||||
node.MapName = uP.mapName;
|
||||
last = WriteEmptyChunk(w, node, time, ref entriesPos);
|
||||
}
|
||||
|
||||
UndoCacheItem item = UndoCacheItem.Make(node, 0, uP);
|
||||
int flags = (item.Flags & 0xC000) | timeDiff;
|
||||
w.Write((ushort)flags); w.Write(item.Index);
|
||||
w.Write(item.Type); w.Write(item.NewType);
|
||||
last.Entries++;
|
||||
}
|
||||
if (last.Entries > 0)
|
||||
WriteChunkEntries(w, last.Entries, entriesPos);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Save(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.Head;
|
||||
|
||||
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 >> 2) || last.Entries == ushort.MaxValue) {
|
||||
WriteChunkEntries(w, last.Entries, entriesPos);
|
||||
last = WriteEmptyChunk(w, node, time, ref entriesPos);
|
||||
}
|
||||
|
||||
int flags = (uP.Flags & 0xC000) | timeDiff;
|
||||
w.Write((ushort)flags); w.Write(uP.Index);
|
||||
w.Write(uP.Type); w.Write(uP.NewType);
|
||||
last.Entries++;
|
||||
}
|
||||
if (last.Entries > 0)
|
||||
WriteChunkEntries(w, last.Entries, entriesPos);
|
||||
node = node.Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<UndoFormatEntry> GetEntries(Stream s, UndoFormatArgs args) {
|
||||
List<ChunkHeader> list = new List<ChunkHeader>();
|
||||
UndoFormatEntry pos;
|
||||
UndoCacheItem item = default(UndoCacheItem);
|
||||
bool super = Player.IsSuper(args.Player);
|
||||
DateTime start = args.Start;
|
||||
DateTime start = args.Start;
|
||||
|
||||
ReadHeaders(list, s);
|
||||
for (int i = list.Count - 1; i >= 0; i--) {
|
||||
@ -158,7 +89,7 @@ namespace MCGalaxy.Undo {
|
||||
|
||||
static void ReadHeaders(List<ChunkHeader> list, Stream s) {
|
||||
BinaryReader r = new BinaryReader(s);
|
||||
long len = s.Length;
|
||||
long len = s.Length;
|
||||
while (s.Position < len) {
|
||||
ChunkHeader header = ReadHeader(s, r);
|
||||
s.Seek(header.Entries * entrySize, SeekOrigin.Current);
|
||||
@ -180,28 +111,33 @@ namespace MCGalaxy.Undo {
|
||||
return header;
|
||||
}
|
||||
|
||||
static void WriteChunkEntries(BinaryWriter w, ushort entries, long entriesPos) {
|
||||
long curPos = w.BaseStream.Position;
|
||||
w.BaseStream.Seek(entriesPos, SeekOrigin.Begin);
|
||||
public struct UndoCacheItem {
|
||||
public int Index;
|
||||
public byte Type, NewType;
|
||||
public ushort Flags; // upper 2 bits for 'ext' or 'physics' type, lower 14 bits for time delta.
|
||||
|
||||
w.Write(entries);
|
||||
w.BaseStream.Seek(curPos, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
static ChunkHeader WriteEmptyChunk(BinaryWriter w, UndoCacheNode node, DateTime time, ref long entriesPos) {
|
||||
ChunkHeader header = default(ChunkHeader);
|
||||
time = time.ToUniversalTime();
|
||||
byte[] mapBytes = Encoding.UTF8.GetBytes(node.MapName);
|
||||
w.Write((ushort)mapBytes.Length);
|
||||
w.Write(mapBytes); header.LevelName = node.MapName;
|
||||
w.Write(time.Ticks); header.BaseTime = time;
|
||||
public short TimeDelta {
|
||||
get {
|
||||
int delta = Flags & 0x3FFF;
|
||||
return delta >= 0x2000 ? (short)(delta - 16384) : (short)delta;
|
||||
}
|
||||
}
|
||||
|
||||
entriesPos = w.BaseStream.Position;
|
||||
w.Write((ushort)0);
|
||||
w.Write((ushort)node.Width); header.Width = (ushort)node.Width;
|
||||
w.Write((ushort)node.Height); header.Height = (ushort)node.Height;
|
||||
w.Write((ushort)node.Length); header.Length = (ushort)node.Length;
|
||||
return header;
|
||||
public void GetBlock(out byte type, out byte extType) {
|
||||
if ((Flags & (1 << 14)) != 0) {
|
||||
type = Block.custom_block; extType = Type;
|
||||
} else {
|
||||
type = Type; extType = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void GetNewBlock(out byte type, out byte extType) {
|
||||
if ((Flags & (1 << 15)) != 0) {
|
||||
type = Block.custom_block; extType = NewType;
|
||||
} else {
|
||||
type = NewType; extType = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
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.IO;
|
||||
|
||||
namespace MCGalaxy.Undo {
|
||||
|
||||
public sealed class UndoFormatOnline : UndoFormat {
|
||||
|
||||
protected override string Ext { get { return null; } }
|
||||
readonly UndoCache cache;
|
||||
public UndoFormatOnline(UndoCache cache) {
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
protected override void Save(List<Player.UndoPos> buffer, string path) {
|
||||
throw new NotSupportedException("UndoFileOnline is read only.");
|
||||
}
|
||||
|
||||
protected override void Save(UndoCache buffer, string path) {
|
||||
throw new NotSupportedException("UndoFileOnline is read only.");
|
||||
}
|
||||
|
||||
protected override IEnumerable<UndoFormatEntry> GetEntries(Stream s, UndoFormatArgs args) {
|
||||
UndoCacheNode node = cache.Tail;
|
||||
if (node == null) yield break;
|
||||
|
||||
UndoFormatEntry pos;
|
||||
bool super = Player.IsSuper(args.Player);
|
||||
DateTime start = args.Start;
|
||||
|
||||
while (node != null) {
|
||||
Level lvl = LevelInfo.FindExact(node.MapName);
|
||||
if (!super && !args.Player.level.name.CaselessEq(node.MapName)) { node = node.Prev; continue; }
|
||||
List<UndoCacheItem> items = node.Items;
|
||||
pos.LevelName = node.MapName;
|
||||
|
||||
for (int i = items.Count - 1; i >= 0; i--) {
|
||||
UndoCacheItem item = items[i];
|
||||
DateTime time = node.BaseTime.AddTicks(item.TimeDelta * TimeSpan.TicksPerSecond);
|
||||
if (time < start) { args.Stop = true; yield break; }
|
||||
pos.Time = time;
|
||||
|
||||
node.Unpack(item.Index, out pos.X, out pos.Y, out pos.Z);
|
||||
item.GetBlock(out pos.Block, out pos.ExtBlock);
|
||||
item.GetNewBlock(out pos.NewBlock, out pos.NewExtBlock);
|
||||
yield return pos;
|
||||
}
|
||||
node = node.Prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -26,14 +26,6 @@ namespace MCGalaxy.Undo {
|
||||
|
||||
protected override string Ext { get { return ".undo"; } }
|
||||
|
||||
protected override void Save(List<Player.UndoPos> buffer, string path) {
|
||||
throw new NotSupportedException("Text undo files have been deprecated");
|
||||
}
|
||||
|
||||
protected override void Save(UndoCache buffer, string path) {
|
||||
throw new NotSupportedException("Text undo files have been deprecated");
|
||||
}
|
||||
|
||||
protected override IEnumerable<UndoFormatEntry> GetEntries(Stream s, UndoFormatArgs args) {
|
||||
UndoFormatEntry pos;
|
||||
pos.NewExtBlock = 0; pos.ExtBlock = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user