forked from mirrors/NBTExplorer
Exposed access to storage timestamp data.
This commit is contained in:
parent
ac9c88773c
commit
fa804da8a6
5 changed files with 160 additions and 7 deletions
|
@ -218,6 +218,22 @@ namespace Substrate
|
|||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets the (last modified) timestamp of the underlying chunk file.
|
||||
/// </summary>
|
||||
/// <param name="cx">The global X-coordinate of a chunk.</param>
|
||||
/// <param name="cz">The global Z-coordinate of a chunk.</param>
|
||||
/// <returns>The last modified timestamp of the underlying chunk file.</returns>
|
||||
public int GetChunkTimestamp (int cx, int cz)
|
||||
{
|
||||
ChunkFile cf = GetChunkFile(cx, cz);
|
||||
if (cf == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cf.GetModifiedTime();
|
||||
}
|
||||
|
||||
#region IEnumerable<ChunkRef> Members
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -284,6 +284,41 @@ namespace Substrate
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the timestamp of the chunk from its underlying region file.
|
||||
/// </summary>
|
||||
/// <param name="cx">The global X-coordinate of a chunk.</param>
|
||||
/// <param name="cz">The global Z-coordinate of a chunk.</param>
|
||||
/// <returns>The timestamp of the chunk from its underlying region file.</returns>
|
||||
/// <remarks>The value returned may differ from any timestamp stored in the chunk data itself.</remarks>
|
||||
public int GetChunkTimestamp (int cx, int cz)
|
||||
{
|
||||
Region r = GetRegion(cx, cz);
|
||||
if (r == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return r.GetChunkTimestamp(cx & REGION_XMASK, cz & REGION_ZMASK);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the timestamp of the chunk in its underlying region file.
|
||||
/// </summary>
|
||||
/// <param name="cx">The global X-coordinate of a chunk.</param>
|
||||
/// <param name="cz">The global Z-coordinate of a chunk.</param>
|
||||
/// <param name="timestamp">The new timestamp value.</param>
|
||||
/// <remarks>This function will only update the timestamp of the chunk slot in the underlying region file. It will not update
|
||||
/// any timestamp information in the chunk data itself.</remarks>
|
||||
public void SetChunkTimestamp (int cx, int cz, int timestamp)
|
||||
{
|
||||
Region r = GetRegion(cx, cz);
|
||||
if (r == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
r.SetChunkTimestamp(cx & REGION_XMASK, cz & REGION_ZMASK, timestamp);
|
||||
}
|
||||
|
||||
private ChunkRef GetChunkRefInRegion (Region r, int lcx, int lcz)
|
||||
{
|
||||
int cx = r.X * REGION_XLEN + lcx;
|
||||
|
|
|
@ -32,6 +32,11 @@ namespace Substrate.Core
|
|||
File.Delete(_filename);
|
||||
}
|
||||
|
||||
public int GetModifiedTime ()
|
||||
{
|
||||
return Timestamp(File.GetLastWriteTime(_filename));
|
||||
}
|
||||
|
||||
public virtual Stream GetDataInputStream ()
|
||||
{
|
||||
try {
|
||||
|
@ -92,5 +97,10 @@ namespace Substrate.Core
|
|||
}
|
||||
}
|
||||
|
||||
private int Timestamp (DateTime time)
|
||||
{
|
||||
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
||||
return (int)((time - epoch).Ticks / (10000L * 1000L));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -274,6 +274,13 @@ namespace Substrate.Core
|
|||
return new ZlibStream(new ChunkBuffer(this, x, z), CompressionMode.Compress);
|
||||
}
|
||||
|
||||
public Stream GetChunkDataOutputStream (int x, int z, int timestamp)
|
||||
{
|
||||
if (OutOfBounds(x, z)) return null;
|
||||
|
||||
return new ZlibStream(new ChunkBuffer(this, x, z, timestamp), CompressionMode.Compress);
|
||||
}
|
||||
|
||||
/*
|
||||
* lets chunk writing be multithreaded by not locking the whole file as a
|
||||
* chunk is serializing -- only writes when serialization is over
|
||||
|
@ -282,20 +289,39 @@ namespace Substrate.Core
|
|||
private int x, z;
|
||||
private RegionFile region;
|
||||
|
||||
public ChunkBuffer(RegionFile r, int x, int z) : base(8096) {
|
||||
// super(8096); // initialize to 8KB
|
||||
private int? _timestamp;
|
||||
|
||||
public ChunkBuffer(RegionFile r, int x, int z)
|
||||
: base(8096)
|
||||
{
|
||||
this.region = r;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public ChunkBuffer (RegionFile r, int x, int z, int timestamp)
|
||||
: this(r, x, z)
|
||||
{
|
||||
_timestamp = timestamp;
|
||||
}
|
||||
|
||||
public override void Close() {
|
||||
region.Write(x, z, this.GetBuffer(), (int)this.Length);
|
||||
if (_timestamp == null) {
|
||||
region.Write(x, z, this.GetBuffer(), (int)this.Length);
|
||||
}
|
||||
else {
|
||||
region.Write(x, z, this.GetBuffer(), (int)this.Length, (int)_timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void Write (int x, int z, byte[] data, int length)
|
||||
{
|
||||
Write(x, z, data, length, Timestamp());
|
||||
}
|
||||
|
||||
/* write a chunk at (x,z) with length bytes of data to disk */
|
||||
protected void Write(int x, int z, byte[] data, int length) {
|
||||
protected void Write(int x, int z, byte[] data, int length, int timestamp) {
|
||||
try {
|
||||
int offset = GetOffset(x, z);
|
||||
int sectorNumber = offset >> 8;
|
||||
|
@ -364,7 +390,7 @@ namespace Substrate.Core
|
|||
SetOffset(x, z, (sectorNumber << 8) | sectorsNeeded);
|
||||
}
|
||||
}
|
||||
SetTimestamp(x, z, Timestamp());
|
||||
SetTimestamp(x, z, timestamp);
|
||||
} catch (IOException e) {
|
||||
Console.WriteLine(e.StackTrace);
|
||||
}
|
||||
|
@ -436,7 +462,12 @@ namespace Substrate.Core
|
|||
return (int)((time - epoch).Ticks / (10000L * 1000L));
|
||||
}
|
||||
|
||||
private void SetTimestamp(int x, int z, int value) {
|
||||
public int GetTimestamp (int x, int z)
|
||||
{
|
||||
return chunkTimestamps[x + z * 32];
|
||||
}
|
||||
|
||||
public void SetTimestamp(int x, int z, int value) {
|
||||
chunkTimestamps[x + z * 32] = value;
|
||||
file.Seek(SECTOR_BYTES + (x + z * 32) * 4, SeekOrigin.Begin);
|
||||
|
||||
|
|
|
@ -254,6 +254,26 @@ namespace Substrate
|
|||
/// <remarks>It is up to the programmer to ensure that the global coordinates defined within the chunk's tree
|
||||
/// are consistent with the local coordinates of the region being written into.</remarks>
|
||||
public bool SaveChunkTree (int lcx, int lcz, NbtTree tree)
|
||||
{
|
||||
return SaveChunkTree(lcx, lcz, tree, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves an <see cref="NbtTree"/> for a chunk back to the region's data store at the given local coordinates and with the given timestamp.
|
||||
/// </summary>
|
||||
/// <param name="lcx">The local X-coordinate of the chunk within the region.</param>
|
||||
/// <param name="lcz">The local Z-coordinate of the chunk within the region.</param>
|
||||
/// <param name="tree">The <see cref="NbtTree"/> of a chunk to write back to the region.</param>
|
||||
/// <param name="timestamp">The timestamp to write to the underlying region file for this chunk.</param>
|
||||
/// <returns>True if the save succeeded.</returns>
|
||||
/// <remarks>It is up to the programmer to ensure that the global coordinates defined within the chunk's tree
|
||||
/// are consistent with the local coordinates of the region being written into.</remarks>
|
||||
public bool SaveChunkTree (int lcx, int lcz, NbtTree tree, int timestamp)
|
||||
{
|
||||
return SaveChunkTree(lcx, lcz, tree, timestamp);
|
||||
}
|
||||
|
||||
private bool SaveChunkTree (int lcx, int lcz, NbtTree tree, int? timestamp)
|
||||
{
|
||||
if (!LocalBoundsCheck(lcx, lcz)) {
|
||||
Region alt = GetForeignRegion(lcx, lcz);
|
||||
|
@ -261,7 +281,10 @@ namespace Substrate
|
|||
}
|
||||
|
||||
RegionFile rf = GetRegionFile();
|
||||
Stream zipstr = rf.GetChunkDataOutputStream(lcx, lcz);
|
||||
Stream zipstr = (timestamp == null)
|
||||
? rf.GetChunkDataOutputStream(lcx, lcz)
|
||||
: rf.GetChunkDataOutputStream(lcx, lcz, (int)timestamp);
|
||||
|
||||
if (zipstr == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -563,6 +586,44 @@ namespace Substrate
|
|||
get { return true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the timestamp of a chunk from the underlying region file.
|
||||
/// </summary>
|
||||
/// <param name="lcx">The local X-coordinate of a chunk relative to this region.</param>
|
||||
/// <param name="lcz">The local Z-coordinate of a chunk relative to this region.</param>
|
||||
/// <returns>The timestamp of the chunk slot in the region.</returns>
|
||||
/// <remarks>The value returned may differ from any timestamp stored in the chunk data itself.</remarks>
|
||||
public int GetChunkTimestamp (int lcx, int lcz)
|
||||
{
|
||||
if (!LocalBoundsCheck(lcx, lcz)) {
|
||||
Region alt = GetForeignRegion(lcx, lcz);
|
||||
return (alt == null) ? 0 : alt.GetChunkTimestamp(ForeignX(lcx), ForeignZ(lcz));
|
||||
}
|
||||
|
||||
RegionFile rf = GetRegionFile();
|
||||
return rf.GetTimestamp(lcx, lcz);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the timestamp of a chunk in the underlying region file.
|
||||
/// </summary>
|
||||
/// <param name="lcx">The local X-coordinate of a chunk relative to this region.</param>
|
||||
/// <param name="lcz">The local Z-coordinate of a chunk relative to this region.</param>
|
||||
/// <param name="timestamp">The new timestamp value.</param>
|
||||
/// <remarks>This function will only update the timestamp of the chunk slot in the underlying region file. It will not update
|
||||
/// any timestamp information in the chunk data itself.</remarks>
|
||||
public void SetChunkTimestamp (int lcx, int lcz, int timestamp)
|
||||
{
|
||||
if (!LocalBoundsCheck(lcx, lcz)) {
|
||||
Region alt = GetForeignRegion(lcx, lcz);
|
||||
if (alt != null)
|
||||
alt.SetChunkTimestamp(ForeignX(lcx), ForeignZ(lcz), timestamp);
|
||||
}
|
||||
|
||||
RegionFile rf = GetRegionFile();
|
||||
rf.SetTimestamp(lcx, lcz, timestamp);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private bool LocalBoundsCheck (int lcx, int lcz)
|
||||
|
|
Loading…
Reference in a new issue