summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--VC2008/MCServer.vcproj8
-rw-r--r--VC2010/MCServer.vcxproj2
-rw-r--r--VC2010/MCServer.vcxproj.filters2
-rw-r--r--makefile4
-rw-r--r--source/cChunkMap.cpp170
-rw-r--r--source/cChunkMap.h5
-rw-r--r--source/cFile.cpp200
-rw-r--r--source/cFile.h99
8 files changed, 404 insertions, 86 deletions
diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj
index 4274c2f5e..d459d51e8 100644
--- a/VC2008/MCServer.vcproj
+++ b/VC2008/MCServer.vcproj
@@ -1443,6 +1443,14 @@
>
</File>
<File
+ RelativePath="..\source\cFile.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\source\cFile.h"
+ >
+ </File>
+ <File
RelativePath="..\source\cSemaphore.cpp"
>
</File>
diff --git a/VC2010/MCServer.vcxproj b/VC2010/MCServer.vcxproj
index 48447f926..c34f8a7ff 100644
--- a/VC2010/MCServer.vcxproj
+++ b/VC2010/MCServer.vcxproj
@@ -318,6 +318,7 @@
<ClCompile Include="..\source\cCuboid.cpp" />
<ClCompile Include="..\source\cEnderman.cpp" />
<ClCompile Include="..\source\cEvent.cpp" />
+ <ClCompile Include="..\source\cFile.cpp" />
<ClCompile Include="..\source\cFileFormatUpdater.cpp" />
<ClCompile Include="..\source\cFireSimulator.cpp" />
<ClCompile Include="..\source\cFluidSimulator.cpp" />
@@ -483,6 +484,7 @@
<ClInclude Include="..\Source\cCriticalSection.h" />
<ClInclude Include="..\source\cEnderman.h" />
<ClInclude Include="..\source\cEvent.h" />
+ <ClInclude Include="..\source\cFile.h" />
<ClInclude Include="..\source\cFileFormatUpdater.h" />
<ClInclude Include="..\source\cFireSimulator.h" />
<ClInclude Include="..\source\cFluidSimulator.h" />
diff --git a/VC2010/MCServer.vcxproj.filters b/VC2010/MCServer.vcxproj.filters
index 0d7e966f9..7a687ce7c 100644
--- a/VC2010/MCServer.vcxproj.filters
+++ b/VC2010/MCServer.vcxproj.filters
@@ -908,6 +908,7 @@
<Filter>cWebAdmin\cWebPlugin\cWebPlugin</Filter>
</ClCompile>
<ClCompile Include="..\source\Globals.cpp" />
+ <ClCompile Include="..\source\cFile.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\source\cServer.h">
@@ -1397,6 +1398,7 @@
<Filter>cWebAdmin\cWebPlugin\cWebPlugin</Filter>
</ClInclude>
<ClInclude Include="..\source\Globals.h" />
+ <ClInclude Include="..\source\cFile.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\source\AllToLua.pkg">
diff --git a/makefile b/makefile
index 84c671bde..db7abd75b 100644
--- a/makefile
+++ b/makefile
@@ -84,6 +84,7 @@ MCServer : \
build/cEntity.o\
build/cEvent.o\
build/cEvents.o\
+ build/cFile.o\
build/cFurnaceEntity.o\
build/cFurnaceRecipe.o\
build/cFurnaceWindow.o\
@@ -293,6 +294,7 @@ MCServer : \
build/cEntity.o\
build/cEvent.o\
build/cEvents.o\
+ build/cFile.o\
build/cFurnaceEntity.o\
build/cFurnaceRecipe.o\
build/cFurnaceWindow.o\
@@ -1522,5 +1524,7 @@ build/cWebPlugin_Lua.o : source/cWebPlugin_Lua.cpp
build/cEvents.o : webserver/cEvents.cpp
$(CC) $(CC_OPTIONS) webserver/cEvents.cpp -c $(INCLUDE) -o build/cEvents.o
+build/cFile.o : source/cFile.cpp
+ $(CC) $(CC_OPTIONS) source/cFile.cpp -c $(INCLUDE) -o build/cFile.o
##### END RUN ####
diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp
index 417b4a98e..b7f1e08a2 100644
--- a/source/cChunkMap.cpp
+++ b/source/cChunkMap.cpp
@@ -16,6 +16,11 @@
#include "zlib.h"
#include <json/json.h>
+
+// TODO: Move this into Globals.h after cFile has been finalized
+#include "cFile.h"
+
+
#define USE_MEMCPY
#define LAYER_SIZE (32)
@@ -24,18 +29,32 @@
-cChunkMap::cChunkMap(cWorld* a_World )
- : m_Layers( 0 )
- , m_NumLayers( 0 )
- , m_World( a_World )
+////////////////////////////////////////////////////////////////////////////////
+// cChunkMap::cChunkLayer:
+
+cChunkMap::cChunkData* cChunkMap::cChunkLayer::GetChunk( int a_X, int a_Z )
{
+ const int LocalX = a_X - m_X * LAYER_SIZE;
+ const int LocalZ = a_Z - m_Z * LAYER_SIZE;
+ //LOG("LocalX:%i LocalZ:%i", LocalX, LocalZ );
+ if ((LocalX < LAYER_SIZE) && (LocalZ < LAYER_SIZE) && (LocalX > -1) && (LocalZ > -1))
+ {
+ return &m_Chunks[ LocalX + LocalZ * LAYER_SIZE ];
+ }
+ return 0;
}
-cChunkMap::~cChunkMap()
+////////////////////////////////////////////////////////////////////////////////
+// cChunkMap:
+
+cChunkMap::cChunkMap(cWorld* a_World )
+ : m_Layers( 0 )
+ , m_NumLayers( 0 )
+ , m_World( a_World )
{
}
@@ -43,14 +62,8 @@ cChunkMap::~cChunkMap()
-cChunkMap::cChunkData* cChunkMap::cChunkLayer::GetChunk( int a_X, int a_Z )
+cChunkMap::~cChunkMap()
{
- const int LocalX = a_X - m_X * LAYER_SIZE;
- const int LocalZ = a_Z - m_Z * LAYER_SIZE;
- //LOG("LocalX:%i LocalZ:%i", LocalX, LocalZ );
- if( LocalX < LAYER_SIZE && LocalZ < LAYER_SIZE && LocalX > -1 && LocalZ > -1 )
- return &m_Chunks[ LocalX + LocalZ * LAYER_SIZE ];
- return 0;
}
@@ -449,14 +462,10 @@ void cChunkMap::SaveLayer( cChunkLayer* a_Layer )
char SourceFile[128];
- sprintf_s(SourceFile, 128, ( WorldName + "/X%i_Z%i.pak").c_str(), a_Layer->m_X, a_Layer->m_Z );
+ sprintf_s(SourceFile, ARRAYCOUNT(SourceFile), ( WorldName + "/X%i_Z%i.pak").c_str(), a_Layer->m_X, a_Layer->m_Z );
- FILE* f = 0;
- #ifdef _WIN32
- if (fopen_s(&f, SourceFile, "wb" ) != 0 ) // no error
- #else
- if( (f = fopen(SourceFile, "wb" )) == 0 ) // no error
- #endif
+ cFile f;
+ if (!f.Open(SourceFile, cFile::fmWrite))
{
LOGERROR("ERROR: Could not write to file %s", SourceFile );
return;
@@ -466,8 +475,8 @@ void cChunkMap::SaveLayer( cChunkLayer* a_Layer )
// Header
char PakVersion = 1;
char ChunkVersion = 1;
- fwrite( &PakVersion, sizeof(PakVersion), 1, f ); // pak version
- fwrite( &ChunkVersion, sizeof(ChunkVersion), 1, f ); // chunk version
+ f.Write(&PakVersion, sizeof(PakVersion)); // pak version
+ f.Write(&ChunkVersion, sizeof(ChunkVersion)); // chunk version
// Count number of chunks in layer
short NumChunks = 0;
@@ -479,120 +488,118 @@ void cChunkMap::SaveLayer( cChunkLayer* a_Layer )
}
}
- fwrite( &NumChunks, sizeof( NumChunks ), 1, f );
- LOG("Num Chunks in layer: %i", NumChunks );
+ f.Write(&NumChunks, sizeof(NumChunks));
+ LOG("Num Chunks in layer [%d, %d]: %i", a_Layer->m_X, a_Layer->m_Z, NumChunks);
- //---------------
// Chunk headers
- for( int z = 0; z < LAYER_SIZE; ++z )
+ for (int z = 0; z < LAYER_SIZE; ++z)
{
- for( int x = 0; x < LAYER_SIZE; ++x )
+ for (int x = 0; x < LAYER_SIZE; ++x)
{
- cChunkData & Data = a_Layer->m_Chunks[x + z*LAYER_SIZE];
- CompressChunk( &Data );
- if( Data.m_Compressed || Data.m_LiveChunk )
+ cChunkData & Data = a_Layer->m_Chunks[x + z * LAYER_SIZE];
+ CompressChunk(&Data);
+ if (Data.m_Compressed != NULL)
{
- int ChunkX = a_Layer->m_X*LAYER_SIZE + x;
- int ChunkZ = a_Layer->m_Z*LAYER_SIZE + z;
+ int ChunkX = a_Layer->m_X * LAYER_SIZE + x;
+ int ChunkZ = a_Layer->m_Z * LAYER_SIZE + z;
unsigned int Size = Data.m_CompressedSize; // Needs to be size of compressed data
unsigned int USize = Data.m_UncompressedSize; // Uncompressed size
- fwrite( &ChunkX, sizeof( ChunkX ), 1, f );
- fwrite( &ChunkZ, sizeof( ChunkZ ), 1, f );
- fwrite( &Size, sizeof( Size ), 1, f );
- fwrite( &USize, sizeof( USize ), 1, f );
+ f.Write(&ChunkX, sizeof(ChunkX));
+ f.Write(&ChunkZ, sizeof(ChunkZ));
+ f.Write(&Size, sizeof(Size));
+ f.Write(&USize, sizeof(USize));
}
- }
- }
+ } // for x - a_Layer->mChunks[x]
+ } // for z - a_Layer->m_Chunks[z]
- //----------------
// Chunk data
- for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i )
+ for (int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i)
{
- char* Compressed = a_Layer->m_Chunks[i].m_Compressed;
- if( Compressed )
+ char * Compressed = a_Layer->m_Chunks[i].m_Compressed;
+ if (Compressed != NULL)
{
- fwrite( Compressed, a_Layer->m_Chunks[i].m_CompressedSize, 1, f );
- if(a_Layer->m_Chunks[i].m_LiveChunk) // If there's a live chunk we have no need for compressed data
+ f.Write(Compressed, a_Layer->m_Chunks[i].m_CompressedSize);
+ if (a_Layer->m_Chunks[i].m_LiveChunk != NULL) // If there's a live chunk we have no need for compressed data
{
delete [] a_Layer->m_Chunks[i].m_Compressed;
a_Layer->m_Chunks[i].m_Compressed = 0;
a_Layer->m_Chunks[i].m_CompressedSize = 0;
}
}
- }
-
- fclose(f);
+ } // for i - a_Layer->m_Chunks[]
}
+#define READ(File, Var) \
+ if (File.Read(&Var, sizeof(Var)) != sizeof(Var)) \
+ { \
+ LOGERROR("ERROR READING %s FROM FILE %s (line %d)", #Var, SourceFile, __LINE__); \
+ return NULL; \
+ }
+
cChunkMap::cChunkLayer* cChunkMap::LoadLayer(int a_LayerX, int a_LayerZ )
{
std::string WorldName = m_World->GetName();
char SourceFile[128];
- sprintf_s(SourceFile, 128, (WorldName + "/X%i_Z%i.pak").c_str(), a_LayerX, a_LayerZ );
+ sprintf_s(SourceFile, ARRAYCOUNT(SourceFile), (WorldName + "/X%i_Z%i.pak").c_str(), a_LayerX, a_LayerZ );
- FILE* f = 0;
- #ifdef _WIN32
- if (fopen_s(&f, SourceFile, "rb" ) != 0 ) // no error
- #else
- if ((f = fopen(SourceFile, "rb" )) == 0 ) // no error
- #endif
+ cFile f(SourceFile, cFile::fmRead);
+ if (!f.IsOpen())
{
return NULL;
}
char PakVersion = 0;
char ChunkVersion = 0;
- if( fread( &PakVersion, sizeof(PakVersion), 1, f) != 1 ) { LOGERROR("ERROR 1 READING FROM FILE %s", SourceFile); fclose(f); return false; }
- if( PakVersion != 1 ) { LOGERROR("WRONG PAK VERSION!"); fclose(f); return 0; }
- if( fread( &ChunkVersion, sizeof(ChunkVersion), 1, f) != 1 ) { LOGERROR("ERROR 2 READING FROM FILE %s", SourceFile); fclose(f); return false; }
- if( ChunkVersion != 1 )
+
+ READ(f, PakVersion);
+ if (PakVersion != 1)
{
- LOGERROR("WRONG CHUNK VERSION!");
- fclose(f);
+ LOGERROR("WRONG PAK VERSION in file \"%s\"!", SourceFile);
return NULL;
}
-
- short NumChunks = 0;
- if( fread( &NumChunks, sizeof(NumChunks), 1, f) != 1 )
+
+ READ(f, ChunkVersion);
+ if (ChunkVersion != 1 )
{
- LOGERROR("ERROR 3 READING FROM FILE %s", SourceFile);
- fclose(f);
+ LOGERROR("WRONG CHUNK VERSION in file \"%s\"!", SourceFile);
return NULL;
}
+
+ short NumChunks = 0;
+ READ(f, NumChunks);
- LOG("Num chunks: %i", NumChunks );
- LOG("Source File: %s", SourceFile );
+ LOG("Num chunks in file \"%s\": %i", SourceFile, NumChunks);
- cChunkLayer* Layer = new cChunkLayer( LAYER_SIZE*LAYER_SIZE );
+ std::auto_ptr<cChunkLayer> Layer(new cChunkLayer(LAYER_SIZE * LAYER_SIZE)); // The auto_ptr deletes the Layer if we exit with an error
Layer->m_X = a_LayerX;
Layer->m_Z = a_LayerZ;
- cChunkData** OrderedData = new cChunkData*[ NumChunks ]; // So we can loop over the chunks in the order they were loaded
+
+ cChunkData * OrderedData[LAYER_SIZE * LAYER_SIZE]; // So we can loop over the chunks in the order they were loaded
// Loop over all chunk headers
for( short i = 0; i < NumChunks; ++i )
{
int ChunkX = 0;
int ChunkZ = 0;
- if( fread( &ChunkX, sizeof(ChunkX), 1, f) != 1 ) { LOGERROR("ERROR 4 READING FROM FILE %s", SourceFile); fclose(f); return false; }
- if( fread( &ChunkZ, sizeof(ChunkZ), 1, f) != 1 ) { LOGERROR("ERROR 5 READING FROM FILE %s", SourceFile); fclose(f); return false; }
+ READ(f, ChunkX);
+ READ(f, ChunkZ);
cChunkData* Data = Layer->GetChunk( ChunkX, ChunkZ );
- if( Data )
+
+ if (Data == NULL)
{
- if( fread( &Data->m_CompressedSize, sizeof(Data->m_CompressedSize), 1, f) != 1 ) { LOGERROR("ERROR 6 READING FROM FILE %s", SourceFile); fclose(f); return false; }
- if( fread( &Data->m_UncompressedSize, sizeof(Data->m_UncompressedSize), 1, f) != 1 ) { LOGERROR("ERROR 7 READING FROM FILE %s", SourceFile); fclose(f); return false; }
+ LOGERROR("Chunk with wrong coordinates in pak file! %i %i", ChunkX, ChunkZ );
+ return NULL;
}
else
{
- LOGERROR("Chunk with wrong coordinates in pak file! %i %i", ChunkX, ChunkZ );
- fclose(f);
- return NULL;
+ READ(f, Data->m_CompressedSize);
+ READ(f, Data->m_UncompressedSize);
}
-
OrderedData[i] = Data;
}
@@ -601,18 +608,13 @@ cChunkMap::cChunkLayer* cChunkMap::LoadLayer(int a_LayerX, int a_LayerZ )
{
cChunkData* Data = OrderedData[i];
Data->m_Compressed = new char[ Data->m_CompressedSize ];
- //printf("Compressed chunk size: %i\n",Data->m_CompressedSize);
- if( fread( Data->m_Compressed, Data->m_CompressedSize, 1, f) != 1 )
+ if (f.Read(Data->m_Compressed, Data->m_CompressedSize) != Data->m_CompressedSize)
{
LOGERROR("ERROR 8 READING FROM FILE %s", SourceFile);
- fclose(f);
return NULL;
}
}
- delete [] OrderedData;
-
- fclose(f);
- return Layer;
+ return Layer.release();
}
diff --git a/source/cChunkMap.h b/source/cChunkMap.h
index e375a0de0..f2d1f4468 100644
--- a/source/cChunkMap.h
+++ b/source/cChunkMap.h
@@ -55,8 +55,9 @@ private:
, m_Z( 0 )
, m_NumChunksLoaded( 0 )
{}
- cChunkData* GetChunk( int a_X, int a_Z );
- cChunkData* m_Chunks;
+ cChunkData * GetChunk( int a_X, int a_Z );
+
+ cChunkData * m_Chunks;
int m_X, m_Z;
int m_NumChunksLoaded;
};
diff --git a/source/cFile.cpp b/source/cFile.cpp
new file mode 100644
index 000000000..84308984a
--- /dev/null
+++ b/source/cFile.cpp
@@ -0,0 +1,200 @@
+
+// cFile.cpp
+
+// Implements the cFile class providing an OS-independent abstraction of a file.
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "cFile.h"
+
+
+
+
+
+
+/// Simple constructor - creates an unopened file object, use Open() to open / create a real file
+cFile::cFile(void) :
+ #ifdef USE_STDIO_FILE
+ m_File(NULL)
+ #else
+ m_File(INVALID_HANDLE_VALUE)
+ #endif // USE_STDIO_FILE
+{
+ // Nothing needed yet
+}
+
+
+
+
+
+/// Constructs and opens / creates the file specified, use IsOpen() to check for success
+cFile::cFile(const char * iFileName, EMode iMode) :
+ #ifdef USE_STDIO_FILE
+ m_File(NULL)
+ #else
+ m_File(INVALID_HANDLE_VALUE)
+ #endif // USE_STDIO_FILE
+{
+ Open(iFileName, iMode);
+}
+
+
+
+
+
+/// Auto-closes the file, if open
+cFile::~cFile()
+{
+ if (IsOpen())
+ {
+ Close();
+ }
+}
+
+
+
+
+
+bool cFile::Open(const char * iFileName, EMode iMode)
+{
+ assert(!IsOpen()); // You should close the file before opening another one
+
+ if (IsOpen())
+ {
+ Close();
+ }
+
+ const char * Mode = NULL;
+ switch (iMode)
+ {
+ case fmRead: Mode = "rb"; break;
+ case fmWrite: Mode = "wb"; break;
+ case fmReadWrite: Mode = "ab+"; break;
+ default:
+ {
+ assert(!"Unhandled file mode");
+ return false;
+ }
+ }
+ m_File = fopen(iFileName, Mode);
+ return (m_File != NULL);
+}
+
+
+
+
+
+void cFile::Close(void)
+{
+ assert(IsOpen()); // You should not close file objects that don't have an open file.
+
+ if (!IsOpen())
+ {
+ return;
+ }
+
+ fclose(m_File);
+}
+
+
+
+
+
+bool cFile::IsOpen(void) const
+{
+ return (m_File != NULL);
+}
+
+
+
+
+
+bool cFile::IsEOF(void) const
+{
+ assert(IsOpen());
+
+ if (!IsOpen())
+ {
+ // Unopened files behave as at EOF
+ return true;
+ }
+
+ return (feof(m_File) != 0);
+}
+
+
+
+
+
+/// Reads up to iNumBytes bytes into iBuffer, returns the number of bytes actually read, or -1 on failure; asserts if not open
+int cFile::Read (void * iBuffer, int iNumBytes)
+{
+ assert(IsOpen());
+
+ if (!IsOpen())
+ {
+ return -1;
+ }
+
+ return fread(iBuffer, 1, iNumBytes, m_File); // fread() returns the portion of Count parameter actually read, so we need to send iNumBytes as Count
+}
+
+
+
+
+
+/// Writes up to iNumBytes bytes from iBuffer, returns the number of bytes actually written, or -1 on failure; asserts if not open
+int cFile::Write(const void * iBuffer, int iNumBytes)
+{
+ assert(IsOpen());
+
+ if (!IsOpen())
+ {
+ return -1;
+ }
+
+ return fwrite(iBuffer, 1, iNumBytes, m_File); // fwrite() returns the portion of Count parameter actually written, so we need to send iNumBytes as Count
+}
+
+
+
+
+
+/// Seeks to iPosition bytes from file start, returns old position or -1 for failure
+int cFile::Seek (int iPosition)
+{
+ assert(IsOpen());
+
+ if (!IsOpen())
+ {
+ return -1;
+ }
+
+ if (fseek(m_File, iPosition, SEEK_SET) != 0)
+ {
+ return -1;
+ }
+ return ftell(m_File);
+}
+
+
+
+
+
+
+/// Returns the current position (bytes from file start)
+int cFile::Tell (void) const
+{
+ assert(IsOpen());
+
+ if (!IsOpen())
+ {
+ return -1;
+ }
+
+ return ftell(m_File);
+}
+
+
+
+
diff --git a/source/cFile.h b/source/cFile.h
new file mode 100644
index 000000000..0c3abb1d9
--- /dev/null
+++ b/source/cFile.h
@@ -0,0 +1,99 @@
+
+// cFile.h
+
+// Interfaces to the cFile class providing an OS-independent abstraction of a file.
+
+/*
+The object is optimized towards binary reads.
+The object has no multithreading locks, don't use from multiple threads!
+Usage:
+1, Construct a cFile instance (no-param constructor)
+2, Open a file using Open(), check return value for success
+3, Read / write
+4, Destroy the instance
+
+-- OR --
+
+1, Construct a cFile instance opening the file (filename-param constructor)
+2, Check if the file was opened using IsOpen()
+3, Read / write
+4, Destroy the instance
+*/
+
+
+
+
+
+#pragma once
+#ifndef CFILE_H_INCLUDED
+#define CFILE_H_INCLUDED
+
+
+
+
+
+#ifndef _WIN32
+ #define USE_STDIO_FILE
+#endif // _WIN32
+
+// DEBUG:
+#define USE_STDIO_FILE
+
+
+
+
+
+class cFile
+{
+public:
+ /// The mode in which to open the file
+ enum EMode
+ {
+ fmRead, // Read-only. If the file doesn't exist, object will not be valid
+ fmWrite, // Write-only. If the file already exists, it will be overwritten
+ fmReadWrite, // Read/write. If the file already exists, it will be left intact
+ } ;
+
+ /// Simple constructor - creates an unopened file object, use Open() to open / create a real file
+ cFile(void);
+
+ /// Constructs and opens / creates the file specified, use IsOpen() to check for success
+ cFile(const char * iFileName, EMode iMode);
+
+ /// Auto-closes the file, if open
+ ~cFile();
+
+ bool Open(const char * iFileName, EMode iMode);
+ void Close(void);
+ bool IsOpen(void) const;
+ bool IsEOF(void) const;
+
+ /// Reads up to iNumBytes bytes into iBuffer, returns the number of bytes actually read, or -1 on failure; asserts if not open
+ int Read (void * iBuffer, int iNumBytes);
+
+ /// Writes up to iNumBytes bytes from iBuffer, returns the number of bytes actually written, or -1 on failure; asserts if not open
+ int Write(const void * iBuffer, int iNumBytes);
+
+ /// Seeks to iPosition bytes from file start, returns old position or -1 for failure; asserts if not open
+ int Seek (int iPosition);
+
+ /// Returns the current position (bytes from file start) or -1 for failure; asserts if not open
+ int Tell (void) const;
+
+private:
+ #ifdef USE_STDIO_FILE
+ FILE * m_File;
+ #else
+ HANDLE m_File;
+ #endif
+} ;
+
+
+
+
+
+#endif // CFILE_H_INCLUDED
+
+
+
+