1
0

Merge branch 'master' into EntityCustomName

Conflicts:
	src/ClientHandle.cpp
	src/ClientHandle.h
	src/Protocol/Protocol.h
	src/Protocol/Protocol125.cpp
	src/Protocol/Protocol125.h
	src/Protocol/Protocol17x.cpp
	src/Protocol/Protocol17x.h
	src/Protocol/ProtocolRecognizer.cpp
	src/Protocol/ProtocolRecognizer.h
	src/World.cpp
	src/World.h
This commit is contained in:
Howaner
2014-09-23 14:39:49 +02:00
232 changed files with 10895 additions and 4787 deletions

View File

@@ -66,8 +66,17 @@ Since only the header is actually in the memory, this number can be high, but st
*/
#define MAX_MCA_FILES 32
/// The maximum size of an inflated chunk; raw chunk data is 192 KiB, allow 64 KiB more of entities
#define CHUNK_INFLATE_MAX 256 KiB
#define LOAD_FAILED(CHX, CHZ) \
{ \
const int RegionX = FAST_FLOOR_DIV(CHX, 32); \
const int RegionZ = FAST_FLOOR_DIV(CHZ, 32); \
LOGERROR("%s (%d): Loading chunk [%d, %d] from file r.%d.%d.mca failed. " \
"The server will now abort in order to avoid further data loss. " \
"Please add the reported file and this message to the issue report.", \
__FUNCTION__, __LINE__, CHX, CHZ, RegionX, RegionZ \
); \
*((volatile int *)0) = 0; /* Crash intentionally */ \
}
@@ -248,29 +257,22 @@ cWSSAnvil::cMCAFile * cWSSAnvil::LoadMCAFile(const cChunkCoords & a_Chunk)
bool cWSSAnvil::LoadChunkFromData(const cChunkCoords & a_Chunk, const AString & a_Data)
{
// Decompress the data:
char Uncompressed[CHUNK_INFLATE_MAX];
z_stream strm;
strm.zalloc = (alloc_func)NULL;
strm.zfree = (free_func)NULL;
strm.opaque = NULL;
inflateInit(&strm);
strm.next_out = (Bytef *)Uncompressed;
strm.avail_out = sizeof(Uncompressed);
strm.next_in = (Bytef *)a_Data.data();
strm.avail_in = (uInt)a_Data.size();
int res = inflate(&strm, Z_FINISH);
inflateEnd(&strm);
if (res != Z_STREAM_END)
// Uncompress the data:
AString Uncompressed;
int res = InflateString(a_Data.data(), a_Data.size(), Uncompressed);
if (res != Z_OK)
{
LOGWARNING("Uncompressing chunk [%d, %d] failed: %d", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, res);
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
return false;
}
// Parse the NBT data:
cParsedNBT NBT(Uncompressed, strm.total_out);
cParsedNBT NBT(Uncompressed.data(), Uncompressed.size());
if (!NBT.IsValid())
{
// NBT Parsing failed
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
return false;
}
@@ -317,11 +319,19 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
int Level = a_NBT.FindChildByName(0, "Level");
if (Level < 0)
{
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
return false;
}
int Sections = a_NBT.FindChildByName(Level, "Sections");
if ((Sections < 0) || (a_NBT.GetType(Sections) != TAG_List) || (a_NBT.GetChildrenType(Sections) != TAG_Compound))
if ((Sections < 0) || (a_NBT.GetType(Sections) != TAG_List))
{
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
return false;
}
eTagType SectionsType = a_NBT.GetChildrenType(Sections);
if ((SectionsType != TAG_Compound) && (SectionsType != TAG_End))
{
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
return false;
}
for (int Child = a_NBT.GetFirstChild(Sections); Child >= 0; Child = a_NBT.GetNextSibling(Child))
@@ -585,7 +595,7 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
// Get the BlockEntity's position
int x, y, z;
if (!GetBlockEntityNBTPos(a_NBT, Child, x, y, z))
if (!GetBlockEntityNBTPos(a_NBT, Child, x, y, z) || (y < 0) || (y >= cChunkDef::Height))
{
LOGWARNING("Bad block entity, missing the coords. Will be ignored.");
continue;
@@ -613,6 +623,8 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
cBlockEntity * cWSSAnvil::LoadBlockEntityFromNBT(const cParsedNBT & a_NBT, int a_Tag, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
ASSERT((a_BlockY >= 0) && (a_BlockY < cChunkDef::Height));
// Load the specific BlockEntity type:
switch (a_BlockType)
{
@@ -2824,30 +2836,42 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a
}
unsigned ChunkLocation = ntohl(m_Header[LocalX + 32 * LocalZ]);
unsigned ChunkOffset = ChunkLocation >> 8;
if (ChunkOffset < 2)
{
return false;
}
m_File.Seek((int)ChunkOffset * 4096);
int ChunkSize = 0;
if (m_File.Read(&ChunkSize, 4) != 4)
{
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
return false;
}
ChunkSize = ntohl((u_long)ChunkSize);
char CompressionType = 0;
if (m_File.Read(&CompressionType, 1) != 1)
{
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
return false;
}
if (CompressionType != 2)
{
// Chunk is in an unknown compression
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
return false;
}
ChunkSize--;
// HACK: This depends on the internal knowledge that AString's data() function returns the internal buffer directly
a_Data.assign(ChunkSize, '\0');
return (m_File.Read((void *)a_Data.data(), ChunkSize) == ChunkSize);
if (m_File.Read((void *)a_Data.data(), ChunkSize) == ChunkSize)
{
return true;
}
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
return false;
}
@@ -2902,7 +2926,13 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri
// Store the header:
ChunkSize = ((u_long)a_Data.size() + MCA_CHUNK_HEADER_LENGTH + 4095) / 4096; // Round data size *up* to nearest 4KB sector, make it a sector number
ASSERT(ChunkSize < 256);
if (ChunkSize > 255)
{
LOGWARNING("Cannot save chunk [%d, %d], the data is too large (%u KiB, maximum is 1024 KiB). Remove some entities and retry.",
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, (unsigned)(ChunkSize * 4)
);
return false;
}
m_Header[LocalX + 32 * LocalZ] = htonl((ChunkSector << 8) | ChunkSize);
if (m_File.Seek(0) < 0)
{