mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-13 09:35:23 -04:00
Created Classic BlockDB draft (markdown)
parent
7bbc648cc3
commit
fbf95d2eac
157
Classic-BlockDB-draft.md
Normal file
157
Classic-BlockDB-draft.md
Normal file
@ -0,0 +1,157 @@
|
||||
```CSharp
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ClassicBlockDB {
|
||||
|
||||
public unsafe sealed class BlockDB {
|
||||
|
||||
public ushort Width, Height, Length;
|
||||
sbyte referenceOffset = 30;
|
||||
public DateTime ReferenceTime;
|
||||
int padding = 0;
|
||||
const byte formatVersion = 1;
|
||||
const int bufferSize = 64 * 1024;
|
||||
|
||||
public void WriteHeader(BinaryWriter w) {
|
||||
w.Write((byte)'c'); w.Write((byte)'b'); w.Write((byte)'d'); w.Write((byte)'b');
|
||||
w.Write(formatVersion);
|
||||
w.Write(referenceOffset);
|
||||
w.Write(Width); w.Write(Height); w.Write(Length);
|
||||
w.Write(padding);
|
||||
}
|
||||
|
||||
public void ReadHeader(BinaryReader r) {
|
||||
if (r.ReadByte() != 'c' || r.ReadByte() != 'b' || r.ReadByte() != 'd' || r.ReadByte() != 'b')
|
||||
throw new InvalidDataException("Expected 'cbdb' for the header.");
|
||||
if (r.ReadByte() > formatVersion)
|
||||
throw new NotSupportedException("Only version 1 of the format is currently supported.");
|
||||
|
||||
referenceOffset = r.ReadSByte();
|
||||
Width = r.ReadUInt16(); Height = r.ReadUInt16(); Length = r.ReadUInt16();
|
||||
padding = r.ReadInt32();
|
||||
ReferenceTime = new DateTime(1970 + referenceOffset, 1, 1, 1, 1, 1, DateTimeKind.Utc);
|
||||
}
|
||||
|
||||
public void WriteEntries(Stream s, BlockDBEntry[] entries) {
|
||||
byte[] chunk = new byte[bufferSize];
|
||||
for (int i = 0; i < entries.Length; i += bufferSize / BlockDBEntry.Size) {
|
||||
int count = Math.Min(bufferSize / BlockDBEntry.Size, entries.Length - i);
|
||||
for (int j = 0; j < count; j++) {
|
||||
BlockDBEntry entry = entries[i + j];
|
||||
int chunkIndex = j * BlockDBEntry.Size;
|
||||
WriteInt32(chunk, chunkIndex, entry.PlayerID);
|
||||
WriteInt32(chunk, chunkIndex + 4, entry.Index);
|
||||
WriteInt32(chunk, chunkIndex + 8, entry.TimeDelta);
|
||||
|
||||
chunk[chunkIndex + 12] = entry.OldBlock;
|
||||
chunk[chunkIndex + 13] = entry.NewBlock;
|
||||
chunk[chunkIndex + 14] = entry.Context;
|
||||
chunk[chunkIndex + 15] = entry.Flags;
|
||||
}
|
||||
s.Write(chunk, 0, count * BlockDBEntry.Size);
|
||||
}
|
||||
}
|
||||
|
||||
public BlockDBEntry[] ReadEntries(Stream s) {
|
||||
int count = (int)((s.Length - s.Position) / BlockDBEntry.Size);
|
||||
BlockDBEntry[] entries = new BlockDBEntry[count];
|
||||
byte[] chunk = new byte[bufferSize];
|
||||
|
||||
for (int i = 0; i < entries.Length; i += bufferSize / BlockDBEntry.Size) {
|
||||
int read = s.Read(chunk, 0, chunk.Length);
|
||||
for (int j = 0; j < read; j += BlockDBEntry.Size) {
|
||||
BlockDBEntry entry = default(BlockDBEntry);
|
||||
entry.PlayerID = ReadInt32(chunk, j);
|
||||
entry.Index = ReadInt32(chunk, j + 4);
|
||||
entry.TimeDelta = ReadInt32(chunk, j + 8);
|
||||
|
||||
entry.OldBlock = chunk[j + 12];
|
||||
entry.NewBlock = chunk[j + 13];
|
||||
entry.Context = chunk[j + 14];
|
||||
entry.Flags = chunk[j + 15];
|
||||
entries[i + (j / BlockDBEntry.Size)] = entry;
|
||||
}
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
public void AdjustDimensions(Stream s, ushort width, ushort height, ushort length) {
|
||||
// If the new BlockDB dimensions are smaller than old, there is no point recalculating the indices.
|
||||
bool updateIndices = width > Width || height > Height || length > Length;
|
||||
Swap(ref width, ref Width); Swap(ref height, ref Height); Swap(ref length, ref Length);
|
||||
WriteHeader(new BinaryWriter(s));
|
||||
if (!updateIndices) return;
|
||||
|
||||
byte[] chunk = new byte[bufferSize];
|
||||
while (s.Position < s.Length) {
|
||||
long pos = s.Position;
|
||||
int read = s.Read(chunk, 0, chunk.Length);
|
||||
for (int i = 0; i < read; i += BlockDBEntry.Size) {
|
||||
int index = ReadInt32(chunk, i + 4);
|
||||
int x = index % width;
|
||||
int y = (index / width) / length;
|
||||
int z = (index / width) % length;
|
||||
index = x + Width * (z + y * Length);
|
||||
WriteInt32(chunk, i + 4, index);
|
||||
}
|
||||
s.Seek(pos, SeekOrigin.Begin);
|
||||
s.Write(chunk, 0, read);
|
||||
}
|
||||
}
|
||||
|
||||
static int ReadInt32(byte[] chunk, int i) {
|
||||
return chunk[i] | chunk[i + 1] << 8 | chunk[i + 2] << 16 | chunk[i + 3] << 24;
|
||||
}
|
||||
|
||||
static void WriteInt32(byte[] chunk, int i, int value) {
|
||||
chunk[i] = (byte)value;
|
||||
chunk[i + 1] = (byte)(value >> 8);
|
||||
chunk[i + 2] = (byte)(value >> 16);
|
||||
chunk[i + 3] = (byte)(value >> 24);
|
||||
}
|
||||
|
||||
static void Swap(ref ushort a, ref ushort b) {
|
||||
ushort c = a; a = b; b = c;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct BlockDBEntry {
|
||||
public int PlayerID; // numerical player id unique for each player
|
||||
public int Index; // packed index according to (width, height, length)
|
||||
public int TimeDelta; // seconds since the reference point
|
||||
public byte OldBlock, NewBlock;
|
||||
public byte Context, Flags;
|
||||
|
||||
// MCGalaxy specific flags:
|
||||
// bit 0 set: old block is a physics block, not an ext tile.
|
||||
// bit 1 set: new block is a physics block, not an ext tile.
|
||||
|
||||
// TODO: should we be using uint16 bitflags for context, with 4 bits leftover for the software?
|
||||
|
||||
public const int Size = 16;
|
||||
}
|
||||
|
||||
public static class BlockDBContext {
|
||||
public const byte Place = 0;
|
||||
public const byte Delete = 1;
|
||||
public const byte Drawn = 2;
|
||||
public const byte Paint = 3;
|
||||
public const byte Replace = 4;
|
||||
public const byte Paste = 5;
|
||||
public const byte Cut = 6;
|
||||
public const byte Fill = 7;
|
||||
public const byte Restore = 8;
|
||||
public const byte PhysicsChange = 9;
|
||||
public const byte Undo = 10;
|
||||
public const byte Redo = 11;
|
||||
public const byte UndoPlayer = 12;
|
||||
|
||||
// ProCraft specific contexts
|
||||
// Portal = 127
|
||||
// Door = 128
|
||||
}
|
||||
}
|
||||
```
|
Loading…
x
Reference in New Issue
Block a user