Merge with master.

This commit is contained in:
UnknownShadow200 2016-01-05 20:41:59 +11:00
commit e12ca9a116
7 changed files with 595 additions and 197 deletions

View File

@ -18,6 +18,8 @@
using System;
using System.Globalization;
using System.IO;
using MCGalaxy.Util;
namespace MCGalaxy.Commands
{
public sealed class CmdUndo : Command
@ -36,29 +38,21 @@ namespace MCGalaxy.Commands
byte b; long seconds = -2; Player who = null; Player.UndoPos Pos; int CurrentPos = 0; bool undoPhysics = false; string whoName = String.Empty;
if (p != null)
p.RedoBuffer.Clear();
if (message == "")
{
if (p == null)
{
Player.SendMessage(null, "Console doesn't have an undo buffer.");
return;
if (message == "") {
if (p == null) {
Player.SendMessage(null, "Console doesn't have an undo buffer."); return;
}
message = p.name.ToLower() + " 30";
}
string[] parts = message.Split(' ');
try
{
if (message.Split(' ').Length > 1)
{
whoName = message.Split(' ')[0];
who = message.Split(' ')[0].ToLower() == "physics" ? null : Player.Find(message.Split(' ')[0]);
undoPhysics = message.Split(' ')[0].ToLower() == "physics";
message = message.Split(' ')[1].ToLower();
}
else
{
try {
if (parts.Length > 1) {
whoName = parts[0];
who = parts[0].ToLower() == "physics" ? null : Player.Find(parts[0]);
undoPhysics = parts[0].ToLower() == "physics";
message = parts[1].ToLower();
} else {
who = (p == null || message.ToLower() == "physics") ? null : p;
undoPhysics = message.ToLower() == "physics";
}
@ -68,9 +62,12 @@ namespace MCGalaxy.Commands
seconds = ((message.ToLower() != "all") ? long.Parse(message) : int.MaxValue);
else
seconds = getAllowed(p, message.ToLower());
}
catch
{
} catch {
if (parts.Length > 1 && parts[1].ToLower() == "update") {
UndoFile.UpgradePlayerUndoFiles(whoName);
Player.SendMessage(p, "Updated undo files for " + whoName + " to the new binary format.");
return;
}
Player.SendMessage(p, "Invalid seconds, or you're unable to use /xundo. Using 30 seconds."); //only run if seconds is an invalid number
seconds = 30;
}
@ -202,10 +199,9 @@ namespace MCGalaxy.Commands
}
bool FoundUser = false;
try
{
undoOfflineHelper(p, whoName, seconds, ref FoundUser);
UndoFile.UndoPlayer(p, whoName.ToLower(), seconds, ref FoundUser);
if (FoundUser)
{
@ -241,85 +237,9 @@ namespace MCGalaxy.Commands
}
return secs;
}
//Fixed by QuantumHive
public bool undoOffline(string[] fileContent, long seconds, Player p)
{
Player.UndoPos Pos;
//-1 because the last element in the array is an empty string "" go check Player.SaveUndo() if you wanna know why
for (int i = (fileContent.Length - 1) / 7; i >= 0; i--)
{
try
{
string datetime = fileContent[(i * 7) - 3];
datetime = datetime.Replace('&', ' ');
DateTime time = DateTime.Parse(datetime, CultureInfo.InvariantCulture);
time = time.AddSeconds(seconds);
if (time < DateTime.Now)
//if (Convert.ToDateTime(fileContent[(i * 7) - 3].Replace('&', ' ')).AddSeconds(seconds) < DateTime.Now)
return false;
Level foundLevel = Level.FindExact(fileContent[(i * 7) - 7]);
if (foundLevel != null)
{
Pos.mapName = foundLevel.name;
Pos.x = Convert.ToUInt16(fileContent[(i * 7) - 6]);
Pos.y = Convert.ToUInt16(fileContent[(i * 7) - 5]);
Pos.z = Convert.ToUInt16(fileContent[(i * 7) - 4]);
Pos.type = foundLevel.GetTile(Pos.x, Pos.y, Pos.z);
if (Pos.type == Convert.ToByte(fileContent[(i * 7) - 1]) ||
Block.Convert(Pos.type) == Block.water || Block.Convert(Pos.type) == Block.lava ||
Pos.type == Block.grass)
{
Pos.newtype = Convert.ToByte(fileContent[(i * 7) - 2]);
Pos.timePlaced = DateTime.Now;
foundLevel.Blockchange(Pos.x, Pos.y, Pos.z, Pos.newtype, true);
if (p != null)
p.RedoBuffer.Add(Pos);
}
}
}
catch (Exception e) { }
}
return true;
}
private void undoOfflineHelper(Player p, string whoName, long seconds, ref bool FoundUser)
{
DirectoryInfo di;
string[] fileContent;
if (p != null)
p.RedoBuffer.Clear();
if (Directory.Exists("extra/undo/" + whoName.ToLower()))
{
di = new DirectoryInfo("extra/undo/" + whoName.ToLower());
for (int i = di.GetFiles("*.undo").Length - 1; i >= 0; i--)
{
fileContent = File.ReadAllText("extra/undo/" + whoName.ToLower() + "/" + i + ".undo").Split();
if (!undoOffline(fileContent, seconds, p)) break;
}
FoundUser = true;
}
if (Directory.Exists("extra/undoPrevious/" + whoName.ToLower()))
{
di = new DirectoryInfo("extra/undoPrevious/" + whoName.ToLower());
for (int i = di.GetFiles("*.undo").Length - 1; i >= 0; i--)
{
fileContent = File.ReadAllText("extra/undoPrevious/" + whoName.ToLower() + "/" + i + ".undo").Split();
if (!undoOffline(fileContent, seconds, p)) break;
}
FoundUser = true;
}
private void undoOfflineHelper(Player p, string whoName, long seconds, ref bool FoundUser) {
UndoFile.UndoPlayer(p, whoName.ToLower(), seconds, ref FoundUser);
}
public override void Help(Player p)

View File

@ -443,8 +443,11 @@
<Compile Include="Levels\Physics\TntPhysics.cs" />
<Compile Include="Levels\Physics\ZombiePhysics.cs" />
<Compile Include="Player\Chat.cs" />
<Compile Include="Player\Player.Timers.cs" />
<Compile Include="Player\Waypoint.cs" />
<Compile Include="Player\Player.Timers.cs" />
<Compile Include="Player\Undo\UndoFile.cs" />
<Compile Include="Player\Undo\UndoFileBin.cs" />
<Compile Include="Player\Undo\UndoFileText.cs" />
<Compile Include="Plugins\Enums.cs" />
<Compile Include="Plugins\Events\GroupEvents.cs" />
<Compile Include="Plugins\Events\LevelEvents.cs" />
@ -727,6 +730,7 @@
<Folder Include="Drawing\DrawOps" />
<Folder Include="Levels\IO" />
<Folder Include="Levels\Physics" />
<Folder Include="Player\Undo" />
<Folder Include="Plugins" />
<Folder Include="Plugins\Events" />
<Folder Include="Plugins\Manager" />

View File

@ -26,6 +26,7 @@ using System.Text.RegularExpressions;
using System.Threading;
using MCGalaxy.Drawing;
using MCGalaxy.SQL;
using MCGalaxy.Util;
namespace MCGalaxy {
public sealed partial class Player : IDisposable {
@ -2752,35 +2753,14 @@ level.Unload();
}
}
public void SaveUndo() {
SaveUndo(this);
}
public void SaveUndo() { SaveUndo(this); }
public static void SaveUndo(Player p) {
if ( p == null || p.UndoBuffer == null || p.UndoBuffer.Count < 1 ) return;
try {
if ( !Directory.Exists("extra/undo") ) Directory.CreateDirectory("extra/undo");
if ( !Directory.Exists("extra/undoPrevious") ) Directory.CreateDirectory("extra/undoPrevious");
DirectoryInfo di = new DirectoryInfo("extra/undo");
if ( di.GetDirectories("*").Length >= Server.totalUndo ) {
Directory.Delete("extra/undoPrevious", true);
Directory.Move("extra/undo", "extra/undoPrevious");
Directory.CreateDirectory("extra/undo");
}
if ( !Directory.Exists("extra/undo/" + p.name.ToLower()) ) Directory.CreateDirectory("extra/undo/" + p.name.ToLower());
di = new DirectoryInfo("extra/undo/" + p.name.ToLower());
int number = di.GetFiles("*.undo").Length;
File.Create("extra/undo/" + p.name.ToLower() + "/" + number + ".undo").Dispose();
using ( StreamWriter w = File.CreateText("extra/undo/" + p.name.ToLower() + "/" + number + ".undo") ) {
foreach ( UndoPos uP in p.UndoBuffer.ToList() ) {
w.Write(uP.mapName + " " +
uP.x + " " + uP.y + " " + uP.z + " " +
uP.timePlaced.ToString(CultureInfo.InvariantCulture).Replace(' ', '&') + " " +
uP.type + " " + uP.newtype + " ");
}
}
UndoFile.SaveUndo(p);
} catch (Exception e) {
Server.s.Log("Error saving undo data for " + p.name + "!"); Server.ErrorLog(e);
}
catch ( Exception e ) { Server.s.Log("Error saving undo data for " + p.name + "!"); Server.ErrorLog(e); }
}
public void Dispose() {

142
Player/Undo/UndoFile.cs Normal file
View File

@ -0,0 +1,142 @@
/*
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;
using System.Linq;
namespace MCGalaxy.Util {
public abstract class UndoFile {
protected const string undoDir = "extra/undo", prevUndoDir = "extra/undoPrevious";
public static UndoFile OldFormat = new UndoFileText();
public static UndoFile NewFormat = new UndoFileBin();
protected abstract void SaveUndoData(List<Player.UndoPos> buffer, string path);
protected abstract void ReadUndoData(List<Player.UndoPos> buffer, string path);
protected abstract bool UndoEntry(Player p, string path, long seconds);
protected abstract bool HighlightEntry(Player p, string path, long seconds);
protected abstract string Extension { get; }
public static void SaveUndo(Player p) {
if( p == null || p.UndoBuffer == 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.Extension);
NewFormat.SaveUndoData(p.UndoBuffer, path);
}
public static void UndoPlayer(Player p, string targetName, long seconds, ref bool FoundUser) {
if (p != null)
p.RedoBuffer.Clear();
FilterEntries(p, undoDir, targetName, seconds, false, ref FoundUser);
FilterEntries(p, prevUndoDir, targetName, seconds, false, ref FoundUser);
}
public static void HighlightPlayer(Player p, string targetName, long seconds, ref bool FoundUser) {
FilterEntries(p, undoDir, targetName, seconds, true, ref FoundUser);
FilterEntries(p, prevUndoDir, targetName, seconds, true, ref FoundUser);
}
static void FilterEntries(Player p, string dir, string name, long seconds, bool highlight, ref bool FoundUser) {
string path = Path.Combine(dir, name);
if (!Directory.Exists(path))
return;
string[] files = Directory.GetFiles(path);
Array.Sort<string>(files, CompareFiles);
for (int i = files.Length - 1; i >= 0; i--) {
path = files[i];
string file = Path.GetFileName(path);
if (file.Length == 0 || file[0] < '0' || file[0] > '9')
continue;
UndoFile format = null;
if (path.EndsWith(OldFormat.Extension)) format = OldFormat;
if (path.EndsWith(NewFormat.Extension)) format = NewFormat;
if (format == null) continue;
if (highlight) {
if (!format.HighlightEntry(p, path, seconds)) break;
} else {
if (!format.UndoEntry(p, path, seconds)) break;
}
}
FoundUser = true;
}
static int CompareFiles(string a, string b) {
int aNumEnd = a.IndexOf('.'), bNumEnd = b.IndexOf('.');
if (aNumEnd < 0 || bNumEnd < 0) return a.CompareTo(b);
int aNum, bNum;
if (!int.TryParse(a.Substring(0, aNumEnd), out aNum) ||
!int.TryParse(b.Substring(0, bNumEnd), out bNum))
return a.CompareTo(b);
return aNum.CompareTo(bNum);
}
public static void CreateDefaultDirectories() {
if (!Directory.Exists(undoDir))
Directory.CreateDirectory(undoDir);
if (!Directory.Exists(prevUndoDir))
Directory.CreateDirectory(prevUndoDir);
}
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>();
for (int i = 0; i < files.Length; i++) {
path = files[i];
if (!path.EndsWith(OldFormat.Extension))
continue;
buffer.Clear();
OldFormat.ReadUndoData(buffer, path);
string newPath = Path.ChangeExtension(path, NewFormat.Extension);
NewFormat.SaveUndoData(buffer, newPath);
File.Delete(path);
}
}
}
}

218
Player/Undo/UndoFileBin.cs Normal file
View File

@ -0,0 +1,218 @@
/*
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;
using System.Linq;
using System.Text;
namespace MCGalaxy.Util {
public sealed class UndoFileBin : UndoFile {
protected override string Extension { get { return ".unbin"; } }
protected override void SaveUndoData(List<Player.UndoPos> buffer, string path) {
using (FileStream fs = File.Create(path)) {
BinaryWriter w = new BinaryWriter(fs);
long entriesPos = 0;
ChunkHeader lastChunk = default(ChunkHeader);
foreach (Player.UndoPos uP in buffer) {
int timeDiff = (int)(uP.timePlaced.ToUniversalTime() - lastChunk.BaseTime).TotalSeconds;
if (lastChunk.LevelName != uP.mapName || timeDiff > 65535 || lastChunk.Entries == ushort.MaxValue) {
WriteChunkEntries(w, lastChunk.Entries, entriesPos);
lastChunk = WriteEmptyChunk(w, uP, ref entriesPos);
}
w.Write((ushort)timeDiff);
w.Write(uP.x); w.Write(uP.y); w.Write(uP.z);
w.Write(uP.type);
w.Write((byte)0); // block definitions placeholder
w.Write(uP.newtype);
w.Write((byte)0); // block definitions placeholder
lastChunk.Entries++;
}
if (lastChunk.Entries > 0)
WriteChunkEntries(w, lastChunk.Entries, entriesPos);
}
}
protected override void ReadUndoData(List<Player.UndoPos> buffer, string path) {
DateTime now = DateTime.Now;
Player.UndoPos Pos;
using (Stream fs = File.OpenRead(path))
using (BinaryReader r = new BinaryReader(fs))
{
int approxEntries = (int)(fs.Length / 12);
if (buffer.Capacity < approxEntries)
buffer.Capacity = approxEntries;
while (fs.Position < fs.Length) {
ChunkHeader chunk = ReadHeader(fs, r);
Pos.mapName = chunk.LevelName;
for (int j = 0; j < chunk.Entries; j++ ) {
Pos.timePlaced = chunk.BaseTime.AddSeconds(r.ReadUInt16());
Pos.x = r.ReadUInt16(); Pos.y = r.ReadUInt16(); Pos.z = r.ReadUInt16();
Pos.type = r.ReadByte(); r.ReadByte(); // block definitions placeholder
Pos.newtype = r.ReadByte(); r.ReadByte(); // block definitions placeholder
buffer.Add(Pos);
}
}
}
}
protected override bool UndoEntry(Player p, string path, long seconds) {
List<ChunkHeader> list = new List<ChunkHeader>();
DateTime now = DateTime.Now;
Player.UndoPos Pos;
using (Stream fs = File.OpenRead(path))
using (BinaryReader r = new BinaryReader(fs))
{
ReadHeaders(list, r);
for (int i = list.Count - 1; i >= 0; i--) {
ChunkHeader chunk = list[i];
Level lvl;
if (!CheckChunk(chunk, now, seconds, p, out lvl))
return false;
if (lvl == null || lvl != p.level) continue;
Pos.mapName = chunk.LevelName;
fs.Seek(chunk.DataPosition, SeekOrigin.Begin);
for (int j = 0; j < chunk.Entries; j++ ) {
DateTime time = chunk.BaseTime.AddSeconds(r.ReadUInt16());
if (time.AddSeconds(seconds) < now) return false;
Pos.x = r.ReadUInt16(); Pos.y = r.ReadUInt16(); Pos.z = r.ReadUInt16();
Pos.type = lvl.GetTile(Pos.x, Pos.y, Pos.z);
byte oldType = r.ReadByte(); r.ReadByte(); // block definitions placeholder
byte newType = r.ReadByte(); r.ReadByte(); // block definitions placeholder
if (Pos.type == newType || Block.Convert(Pos.type) == Block.water
|| Block.Convert(Pos.type) == Block.lava || Pos.type == Block.grass) {
Pos.newtype = oldType;
Pos.timePlaced = now;
lvl.Blockchange(Pos.x, Pos.y, Pos.z, Pos.newtype, true);
if (p != null)
p.RedoBuffer.Add(Pos);
}
}
}
}
return true;
}
protected override bool HighlightEntry(Player p, string path, long seconds) {
List<ChunkHeader> list = new List<ChunkHeader>();
DateTime now = DateTime.Now;
using (Stream fs = File.OpenRead(path))
using (BinaryReader r = new BinaryReader(fs))
{
ReadHeaders(list, r);
for (int i = list.Count - 1; i >= 0; i--) {
ChunkHeader chunk = list[i];
Level lvl;
if (!CheckChunk(chunk, now, seconds, p, out lvl))
return false;
if (lvl == null || lvl != p.level) continue;
fs.Seek(chunk.DataPosition, SeekOrigin.Begin);
for (int j = 0; j < chunk.Entries; j++ ) {
DateTime time = chunk.BaseTime.AddSeconds(r.ReadUInt16());
if (time.AddSeconds(seconds) < now) return false;
ushort x = r.ReadUInt16(), y = r.ReadUInt16(), z = r.ReadUInt16();
byte lvlTile = lvl.GetTile(x, y, z);
byte oldType = r.ReadByte(); r.ReadByte(); // block definitions placeholder
byte newType = r.ReadByte(); r.ReadByte(); // block definitions placeholder
if (lvlTile == newType || Block.Convert(lvlTile) == Block.water || Block.Convert(lvlTile) == Block.lava) {
byte block = (lvlTile == Block.air || Block.Convert(lvlTile) == Block.water
|| Block.Convert(lvlTile) == Block.lava) ? Block.red : Block.green;
p.SendBlockchange(x, y, z, block);
}
}
}
}
return true;
}
static bool CheckChunk(ChunkHeader chunk, DateTime now, long seconds, Player p, out Level lvl) {
DateTime time = chunk.BaseTime;
lvl = null;
if (time.AddSeconds(65536).AddSeconds(seconds) < now)
return false; // we can safely discard the entire chunk
lvl = Level.FindExact(chunk.LevelName);
return true;
}
struct ChunkHeader {
public string LevelName;
public DateTime BaseTime;
public ushort Entries;
public long DataPosition;
}
static void ReadHeaders(List<ChunkHeader> list, BinaryReader r) {
Stream s = r.BaseStream;
long len = s.Length;
while (s.Position < len) {
ChunkHeader header = ReadHeader(s, r);
s.Seek(header.Entries * 12, SeekOrigin.Current);
list.Add(header);
}
}
static ChunkHeader ReadHeader(Stream s, BinaryReader r) {
ChunkHeader header = default(ChunkHeader);
byte[] mapNameData = r.ReadBytes(r.ReadUInt16());
header.LevelName = Encoding.UTF8.GetString(mapNameData);
header.BaseTime = new DateTime(r.ReadInt64(), DateTimeKind.Local);
header.Entries = r.ReadUInt16();
header.DataPosition = s.Position;
return header;
}
static void WriteChunkEntries(BinaryWriter w, ushort entries, long entriesPos) {
long curPos = w.BaseStream.Position;
w.BaseStream.Seek(entriesPos, SeekOrigin.Begin);
w.Write(entries);
w.BaseStream.Seek(curPos, SeekOrigin.Begin);
}
static ChunkHeader WriteEmptyChunk(BinaryWriter w, Player.UndoPos uP, ref long entriesPos) {
byte[] mapBytes = Encoding.UTF8.GetBytes(uP.mapName);
w.Write((ushort)mapBytes.Length);
w.Write(mapBytes);
w.Write(uP.timePlaced.ToLocalTime().Ticks);
entriesPos = w.BaseStream.Position;
w.Write((ushort)0);
ChunkHeader header = default(ChunkHeader);
header.LevelName = uP.mapName; header.BaseTime = uP.timePlaced;
return header;
}
}
}

134
Player/Undo/UndoFileText.cs Normal file
View File

@ -0,0 +1,134 @@
/*
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.Globalization;
using System.IO;
using System.Linq;
namespace MCGalaxy.Util {
public sealed class UndoFileText : UndoFile {
protected override string Extension { get { return ".undo"; } }
protected override void SaveUndoData(List<Player.UndoPos> buffer, string path) {
using (StreamWriter w = File.CreateText(path)) {
foreach (Player.UndoPos uP in buffer) {
w.Write(
uP.mapName + " " + uP.x + " " + uP.y + " " + uP.z + " " +
uP.timePlaced.ToString(CultureInfo.InvariantCulture).Replace(' ', '&') + " " +
uP.type + " " + uP.newtype + " ");
}
}
}
protected override void ReadUndoData(List<Player.UndoPos> buffer, string path) {
Player.UndoPos Pos;
string[] lines = File.ReadAllText(path).Split(' ');
int approxEntries = (int)(lines.Length / 7);
if (buffer.Capacity < approxEntries)
buffer.Capacity = approxEntries;
for (int i = 0; i < lines.Length; i += 7) {
if (lines[i].Length == 0) continue;
Pos.mapName = lines[i];
Pos.x = ushort.Parse(lines[i + 1]);
Pos.y = ushort.Parse(lines[i + 2]);
Pos.z = ushort.Parse(lines[i + 3]);
string time = lines[i + 4].Replace('&', ' ');
Pos.timePlaced = DateTime.Parse(time, CultureInfo.InvariantCulture);
Pos.type = byte.Parse(lines[i + 5]);
Pos.newtype = byte.Parse(lines[i + 6]);
buffer.Add(Pos);
}
}
protected override bool UndoEntry(Player p, string path, long seconds) {
Player.UndoPos Pos;
string[] lines = File.ReadAllText(path).Split(' ');
// because we have space to end of each entry, need to subtract one otherwise we'll start at a "".
for (int i = (lines.Length - 1) / 7; i >= 0; i--) {
try {
// line format: mapName x y z date oldblock newblock
if (!InTime(lines[(i * 7) - 3], seconds)) return false;
Level foundLevel = Level.FindExact(lines[(i * 7) - 7]);
if (foundLevel == null) continue;
Pos.mapName = foundLevel.name;
Pos.x = Convert.ToUInt16(lines[(i * 7) - 6]);
Pos.y = Convert.ToUInt16(lines[(i * 7) - 5]);
Pos.z = Convert.ToUInt16(lines[(i * 7) - 4]);
Pos.type = foundLevel.GetTile(Pos.x, Pos.y, Pos.z);
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) {
Pos.newtype = Convert.ToByte(lines[(i * 7) - 2]);
Pos.timePlaced = DateTime.Now;
foundLevel.Blockchange(Pos.x, Pos.y, Pos.z, Pos.newtype, true);
if (p != null)
p.RedoBuffer.Add(Pos);
}
} catch {
}
}
return true;
}
protected override bool HighlightEntry(Player p, string path, long seconds) {
Player.UndoPos Pos;
string[] lines = File.ReadAllText(path).Split(' ');
// because we have space to end of each entry, need to subtract one otherwise we'll start at a "".
for (int i = (lines.Length - 1) / 7; i >= 0; i--) {
try {
// line format: mapName x y z date oldblock newblock
if (!InTime(lines[(i * 7) - 3], seconds)) return false;
Level foundLevel = Level.FindExact(lines[(i * 7) - 7]);
if (foundLevel == null || foundLevel != p.level) continue;
Pos.mapName = foundLevel.name;
Pos.x = Convert.ToUInt16(lines[(i * 7) - 6]);
Pos.y = Convert.ToUInt16(lines[(i * 7) - 5]);
Pos.z = Convert.ToUInt16(lines[(i * 7) - 4]);
Pos.type = foundLevel.GetTile(Pos.x, Pos.y, Pos.z);
if (Pos.type == Convert.ToByte(lines[(i * 7) - 1]) ||
Block.Convert(Pos.type) == Block.water || Block.Convert(Pos.type) == Block.lava) {
if (Pos.type == Block.air || Block.Convert(Pos.type) == Block.water || Block.Convert(Pos.type) == Block.lava)
p.SendBlockchange(Pos.x, Pos.y, Pos.z, Block.red);
else
p.SendBlockchange(Pos.x, Pos.y, Pos.z, Block.green);
}
} catch { }
}
return true;
}
static bool InTime(string line, long seconds) {
line = line.Replace('&', ' ');
DateTime time = DateTime.Parse(line, CultureInfo.InvariantCulture)
.AddSeconds(seconds);
return time >= DateTime.Now;
}
}
}

View File

@ -1,74 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{63DCBB31-92CD-4464-A86C-A7E51A5FE9FE}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Starter</RootNamespace>
<AssemblyName>MCGalaxy</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject>Starter.Program</StartupObject>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Galaxy.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="MCGalaxy_.csproj">
<Project>{12597DB0-7C34-4DE1-88EA-9250FF3372EB}</Project>
<Name>MCGalaxy_</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="Galaxy.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{63DCBB31-92CD-4464-A86C-A7E51A5FE9FE}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Starter</RootNamespace>
<AssemblyName>MCGalaxy</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject>Starter.Program</StartupObject>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Galaxy.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="MCGalaxy_.csproj">
<Project>{12597DB0-7C34-4DE1-88EA-9250FF3372EB}</Project>
<Name>MCGalaxy_</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="Galaxy.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
-->
</Project>