1using System.IO.Compression;
2using System.Runtime.CompilerServices;
9 void Open(
string directoryName,
string suffix);
57 public virtual void Open(
string directoryName,
string suffix) {
80 throw new InvalidOperationException(
"Invalid chunks file header magic.");
85 throw new InvalidOperationException(
"Invalid chunks file header node size.");
106 int nextNode = value.StartNode;
108 while (nextNode >= 0) {
109 num +=
ReadNode(nextNode, buffer, num, out nextNode);
114 public virtual void Save(
Point2 p,
byte[] buffer,
int size) {
117 ReadNode(freeNodes.Last(),
null, 0, out
int nextNode);
119 for (
int i = 0; i < freeNodes.Count; i++) {
121 WriteNode(freeNodes[i], buffer, num, num2, i < freeNodes.Count - 1 ? freeNodes[i + 1] : -1);
127 chunkDescriptor.Coords = p;
128 chunkDescriptor.StartNode = freeNodes.First();
129 value = chunkDescriptor;
136 value.StartNode = freeNodes.First();
146 && list.Count < count) {
148 ReadNode(nextNode,
null, 0, out nextNode);
150 if (list.Count < count) {
151 int num = count - list.Count;
153 int num3 = num2 + num - 1;
156 if (list.Count > 0) {
157 WriteNode(list.Last(),
null, 0, 0, num2);
162 for (
int i = num2; i <= num3; i++) {
172 ReadNode(num,
null, 0, out
int nextNode);
191 result.Coords.X =
Reader.ReadInt32();
192 result.Coords.Y =
Reader.ReadInt32();
193 result.StartNode =
Reader.ReadInt32();
204 public virtual int ReadNode(
int node,
byte[] data,
int offset, out
int nextNode) {
207 throw new InvalidOperationException(
"Invalid node.");
211 throw new InvalidOperationException(
"Invalid node magic.");
213 int nodeHeader =
Reader.ReadInt32();
216 &&
Stream.Read(data, offset, dataSize) != dataSize) {
217 throw new InvalidOperationException(
"Truncated ChunksFile.");
222 public virtual void WriteNode(
int node,
byte[] data,
int offset,
int size,
int nextNode) {
225 throw new InvalidOperationException(
"Invalid node.");
232 Stream.Write(data, offset, size);
238 return (dataSize << 1) | 1;
240 return (nextNode - (node + 1)) << 1;
243 public virtual void ParseNodeHeader(
int node,
int nodeHeader, out
int dataSize, out
int nextNode) {
244 if (((uint)nodeHeader & 1u) != 0) {
245 dataSize = nodeHeader >> 1;
250 nextNode = node + 1 + (nodeHeader >> 1);
261 foreach (KeyValuePair<Point2, ChunkDescriptor> chunkDescriptor
in ChunkDescriptors) {
263 " Chunk {0}: p=({1}), startNode={2}",
264 chunkDescriptor.Value.Index,
266 chunkDescriptor.Value.StartNode
271 for (
int i = 0; i < num; i++) {
272 int num2 =
ReadNode(i,
null, 0, out
int nextNode);
273 Log.
Information(
" Node {0:0}: next={1:0}, dataSize={2}", i, nextNode, num2);
323 public virtual void Open(
string directoryName,
string suffix) {
343 Point2 region =
new(coords.X >> 4, coords.Y >> 4);
344 Point2 chunk =
new(coords.X & 0xF, coords.Y & 0xF);
346 if (regionStream !=
null) {
347 using (BinaryReader reader =
new(regionStream, Encoding.UTF8,
true)) {
349 if (directoryEntry.
Offset > 0) {
351 return directoryEntry.
Size;
358 public virtual void Save(
Point2 coords,
byte[] buffer,
int size) {
359 Point2 region =
new(coords.X >> 4, coords.Y >> 4);
360 Point2 point =
new(coords.X & 0xF, coords.Y & 0xF);
363 using (BinaryReader reader =
new(regionStream, Encoding.UTF8,
true)) {
364 using (BinaryWriter writer =
new(regionStream, Encoding.UTF8,
true)) {
369 if (directoryEntry.
Offset > 0) {
372 int num3 = array[num2].
Offset - directoryEntry.Offset - 4;
378 regionStream.Flush();
383 using (BinaryWriter binaryWriter =
new(stream)) {
386 for (
int i = 0; i < array.Length; i++) {
389 array2[i].
Size = size;
392 else if (array[i].Offset > 0) {
401 byte[] buffer2 =
new byte[array.Max(e => e.Size)];
402 for (
int j = 0; j < array.Length; j++) {
404 WriteData(binaryWriter, array2[j].Offset, buffer, size);
406 else if (array[j].Offset > 0) {
407 ReadData(reader, array[j].Offset, buffer2, array[j].Size);
408 WriteData(binaryWriter, array2[j].Offset, buffer2, array2[j].Size);
416 if (directoryEntry.
Offset + 4 + size > regionStream.Length) {
423 regionStream.Flush();
427 int num5 = (int)regionStream.Length;
433 regionStream.Flush();
438 regionStream.Dispose();
439 string text2 = $
"{text}.new";
445 public virtual string GetRegionPath(
Point2 region) => $
"{RegionsDirectoryName}/Region {region.X},{region.Y}.dat";
454 using (BinaryReader binaryReader =
new(value, Encoding.UTF8,
true)) {
456 throw new InvalidOperationException($
"Invalid region file {region} magic.");
461 else if (createNew) {
464 using (BinaryWriter binaryWriter =
new(value, Encoding.UTF8,
true)) {
480 public static void ReadData(BinaryReader reader,
int offset,
byte[] buffer,
int size) {
481 reader.BaseStream.Position = offset;
483 throw new InvalidOperationException(
"Invalid region file chunk magic.");
485 if (reader.BaseStream.Read(buffer, 0, size) != size) {
486 throw new InvalidOperationException(
"Region file is truncated.");
492 result.Offset = reader.ReadInt32();
493 result.Size = reader.ReadInt32();
495 || result.
Size > 1048576) {
496 throw new InvalidOperationException(
"Region file entry size out of bounds, likely corrupt region file.");
508 reader.BaseStream.Position = 4L;
510 for (
int i = 0; i < 256; i++) {
516 public static void WriteData(BinaryWriter writer,
int offset,
byte[] buffer,
int size) {
517 writer.BaseStream.Position = offset;
519 writer.BaseStream.Write(buffer, 0, size);
523 writer.Write(entry.
Offset);
524 writer.Write(entry.
Size);
528 int num = chunk.X + 16 * chunk.
Y;
534 writer.BaseStream.Position = 4L;
535 for (
int i = 0; i < 256; i++) {
541 if (size > 268435456) {
542 throw new InvalidOperationException(
"Region file too large.");
544 stream.SetLength(size);
549 int num =
int.MaxValue;
550 for (
int i = 0; i < entries.Length; i++) {
563 public static uint
MakeFourCC(
string s) => ((uint)s[3] << 24) | ((uint)s[2] << 16) | ((uint)s[1] << 8) | s[0];
597 chunk.ModificationCounter = 0;
611 catch (IOException) {
626 catch (Exception e) {
641 catch (Exception e) {
706 for (
int k = 0; k < count; k++) {
722 throw new InvalidOperationException(
"Corrupt chunk data.");
726 [MethodImpl(MethodImplOptions.AggressiveInlining)]
727 public static int ReadIntFromBuffer(
byte[] buffer,
int i) => buffer[i] + (buffer[i + 1] << 8) + (buffer[i + 2] << 16) + (buffer[i + 3] << 24);
729 [MethodImpl(MethodImplOptions.AggressiveInlining)]
738 count = buffer[i + 4] + 16;
742 [MethodImpl(MethodImplOptions.AggressiveInlining)]
744 buffer[i] = (byte)data;
745 buffer[i + 1] = (byte)(data >> 8);
746 buffer[i + 2] = (byte)(data >> 16);
747 buffer[i + 3] = (byte)(data >> 24);
750 [MethodImpl(MethodImplOptions.AggressiveInlining)]
760 buffer[i + 4] = (byte)(count - 16);
763 throw new InvalidOperationException(
"Count too large.");
766 public static int Deflate(
byte[] input,
int offset,
int length,
byte[] output) {
767 MemoryStream memoryStream =
new(input, offset, length);
768 MemoryStream memoryStream2 =
new(output);
769 using (DeflateStream destination =
new(memoryStream2, CompressionLevel.Fastest,
true)) {
770 memoryStream.CopyTo(destination);
772 return (
int)memoryStream2.Position;
775 public static int UnDeflate(
byte[] input,
int offset,
int length,
byte[] output) {
776 MemoryStream stream =
new(input, offset, length);
777 MemoryStream memoryStream =
new(output);
778 using (DeflateStream deflateStream =
new(stream, CompressionMode.Decompress)) {
779 deflateStream.CopyTo(memoryStream);
781 return (
int)memoryStream.Position;
static void Dispatch(Action action, bool waitUntilCompleted=false)
static void Error(object message)
static void Information(object message)
static void MoveFile(string sourcePath, string destinationPath)
static void CreateDirectory(string path)
static IEnumerable< string > ListFileNames(string path)
static string ChangeExtension(string path, string extension)
static Stream OpenFile(string path, OpenFileMode openFileMode)
static string GetExtension(string path)
static bool FileExists(string path)
static void DeleteFile(string path)
static string CombinePaths(params string[] paths)
static void ShowDialog(ContainerWidget parentWidget, Dialog dialog)
static string MakeFullErrorMessage(Exception e)
static void DisposeProject()
static void SwitchScreen(string name, params object[] parameters)
virtual void SetShaftValueFast(int x, int z, int value)
virtual int GetCellValueFast(int index)
virtual void SetCellValueFast(int x, int y, int z, int value)
virtual int GetShaftValueFast(int x, int z)
static int ExtractTemperature(int value)
static int ReplaceHumidity(int value, int humidity)
static int ExtractLight(int value)
static int ExtractHumidity(int value)
static int ReplaceTemperature(int value, int temperature)
static int ReplaceLight(int value, int light)
static void WriteData(BinaryWriter writer, int offset, byte[] buffer, int size)
virtual void Save(Point2 coords, byte[] buffer, int size)
const int MaxOpenedStreams
static DirectoryEntry ReadDirectoryEntry(BinaryReader reader, Point2 chunk)
virtual Stream GetRegionStream(Point2 region, bool createNew)
const int RegionDataOffset
const int RegionChunksBits
string RegionsDirectoryName
static DirectoryEntry[] ReadDirectoryEntries(BinaryReader reader)
static void WriteDirectoryEntry(BinaryWriter writer, Point2 chunk, DirectoryEntry entry)
static void ResizeStream(Stream stream, int size)
static int CalculateIdealEntrySpace(int size)
const int RegionDirectoryEntrySize
const int RegionChunkDataOffset
static void WriteDirectoryEntry(BinaryWriter writer, DirectoryEntry entry)
Queue< Stream > OpenedStreams
virtual void Open(string directoryName, string suffix)
const int RegionChunksCountMinusOne
virtual string GetRegionPath(Point2 region)
virtual int Load(Point2 coords, byte[] buffer)
const int ExtraSpaceBytes
static uint RegionChunkMagic
static DirectoryEntry ReadDirectoryEntry(BinaryReader reader)
static void WriteDirectoryEntries(BinaryWriter writer, DirectoryEntry[] entries)
static uint MakeFourCC(string s)
static int FindNextEntryIndex(DirectoryEntry[] entries, int index)
const int RegionDirectoryOffset
static void ReadData(BinaryReader reader, int offset, byte[] buffer, int size)
Dictionary< Point2, Stream > StreamsByRegion
const int RegionChunksCount
virtual void WriteChunkDescriptor(ChunkDescriptor desc)
virtual void WriteNode(int node, byte[] data, int offset, int size, int nextNode)
virtual void SetAndWriteFreeNode(int freeNode)
virtual void ParseNodeHeader(int node, int nodeHeader, out int dataSize, out int nextNode)
const uint FileHeaderMagic
virtual int FindLastNode(int startNode)
Dictionary< Point2, ChunkDescriptor > ChunkDescriptors
virtual void LogDebugInfo()
virtual int MakeNodeHeader(int node, int dataSize, int nextNode)
virtual List< int > GetFreeNodes(int count)
const int FileHeaderChunkDescriptorsOffset
virtual int ReadNode(int node, byte[] data, int offset, out int nextNode)
virtual void Open(string directoryName, string suffix)
static uint ReverseEndianness(uint n)
virtual void Save(Point2 p, byte[] buffer, int size)
virtual ChunkDescriptor ReadChunkDescriptor(int i)
const int FileHeaderChunkDescriptorsCount
const int FileHeaderChunkDescriptorSize
virtual int Load(Point2 p, byte[] buffer)
const uint NodeHeaderMagic
const int FileHeaderFreeNodeOffset
static void WriteIntToBuffer(byte[] buffer, int i, int data)
static int WriteRleValueToBuffer(byte[] buffer, int i, int value, int count)
static int UnDeflate(byte[] input, int offset, int length, byte[] output)
const int WorstCaseChunkDataSize
virtual bool LoadChunkData(TerrainChunk chunk)
static int ReadIntFromBuffer(byte[] buffer, int i)
virtual void SaveChunk(TerrainChunk chunk)
static int ReadRleValueFromBuffer(byte[] buffer, int i, out int value, out int count)
virtual bool LoadChunk(TerrainChunk chunk)
virtual void DecompressChunkData(TerrainChunk chunk, byte[] buffer, int size)
TerrainSerializer23(string directoryName, string suffix="")
virtual int CompressChunkData(TerrainChunk chunk, byte[] buffer)
static int Deflate(byte[] input, int offset, int length, byte[] output)
virtual void SaveChunkData(TerrainChunk chunk)
void SetErrorHead(int headLangIndex, int adviceLangIndex)
int Load(Point2 coords, byte[] buffer)
void Save(Point2 coords, byte[] buffer, int size)
void Open(string directoryName, string suffix)