Merged the composable_generator branch into the trunk
git-svn-id: http://mc-server.googlecode.com/svn/trunk@504 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
@@ -7,7 +7,6 @@
|
||||
#include "WSSAnvil.h"
|
||||
#include "cWorld.h"
|
||||
#include "zlib.h"
|
||||
#include "NBT.h"
|
||||
#include "BlockID.h"
|
||||
#include "cChestEntity.h"
|
||||
#include "cItem.h"
|
||||
@@ -26,7 +25,7 @@ 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
|
||||
/// 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
|
||||
|
||||
|
||||
@@ -45,7 +44,8 @@ public:
|
||||
m_Writer(a_Writer),
|
||||
m_IsTagOpen(false),
|
||||
m_HasHadEntity(false),
|
||||
m_HasHadBlockEntity(false)
|
||||
m_HasHadBlockEntity(false),
|
||||
m_IsLightValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -59,6 +59,9 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool IsLightValid(void) const {return m_IsLightValid; }
|
||||
|
||||
protected:
|
||||
|
||||
/* From cChunkDataSeparateCollector we inherit:
|
||||
@@ -75,6 +78,7 @@ protected:
|
||||
bool m_IsTagOpen; // True if a tag has been opened in the callbacks and not yet closed.
|
||||
bool m_HasHadEntity; // True if any Entity has already been received and processed
|
||||
bool m_HasHadBlockEntity; // True if any BlockEntity has already been received and processed
|
||||
bool m_IsLightValid; // True if the chunk lighting is valid
|
||||
|
||||
|
||||
void AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID)
|
||||
@@ -89,10 +93,10 @@ protected:
|
||||
void AddItem(cItem * a_Item, int a_Slot)
|
||||
{
|
||||
m_Writer.BeginCompound("");
|
||||
m_Writer.AddShort("id", a_Item->m_ItemID);
|
||||
m_Writer.AddShort("id", (short)(a_Item->m_ItemID));
|
||||
m_Writer.AddShort("Damage", a_Item->m_ItemHealth);
|
||||
m_Writer.AddByte ("Count", a_Item->m_ItemCount);
|
||||
m_Writer.AddByte ("Slot", a_Slot);
|
||||
m_Writer.AddByte ("Slot", (unsigned char)a_Slot);
|
||||
m_Writer.EndCompound();
|
||||
}
|
||||
|
||||
@@ -116,6 +120,13 @@ protected:
|
||||
}
|
||||
|
||||
|
||||
virtual bool LightIsValid(bool a_IsLightValid) override
|
||||
{
|
||||
m_IsLightValid = a_IsLightValid;
|
||||
return a_IsLightValid; // We want lighting only if it's valid, otherwise don't bother
|
||||
}
|
||||
|
||||
|
||||
virtual void Entity(cEntity * a_Entity) override
|
||||
{
|
||||
// TODO: Add entity into NBT:
|
||||
@@ -363,12 +374,6 @@ bool cWSSAnvil::SaveChunkToData(const cChunkCoords & a_Chunk, AString & a_Data)
|
||||
return false;
|
||||
}
|
||||
Writer.Finish();
|
||||
|
||||
#ifdef _DEBUG
|
||||
cParsedNBT TestParse(Writer.GetResult().data(), Writer.GetResult().size());
|
||||
ASSERT(TestParse.IsValid());
|
||||
#endif // _DEBUG
|
||||
|
||||
CompressString(Writer.GetResult().data(), Writer.GetResult().size(), a_Data);
|
||||
return true;
|
||||
}
|
||||
@@ -380,13 +385,15 @@ bool cWSSAnvil::SaveChunkToData(const cChunkCoords & a_Chunk, AString & a_Data)
|
||||
bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT & a_NBT)
|
||||
{
|
||||
// The data arrays, in MCA-native y/z/x ordering (will be reordered for the final chunk data)
|
||||
BLOCKTYPE BlockData[cChunkDef::BlockDataSize];
|
||||
BLOCKTYPE * MetaData = BlockData + cChunkDef::MetaOffset;
|
||||
BLOCKTYPE * BlockLight = BlockData + cChunkDef::LightOffset;
|
||||
BLOCKTYPE * SkyLight = BlockData + cChunkDef::SkyLightOffset;
|
||||
cChunkDef::BlockTypes BlockTypes;
|
||||
cChunkDef::BlockNibbles MetaData;
|
||||
cChunkDef::BlockNibbles BlockLight;
|
||||
cChunkDef::BlockNibbles SkyLight;
|
||||
|
||||
memset(BlockData, E_BLOCK_AIR, sizeof(BlockData) - cChunkDef::NumBlocks / 2);
|
||||
memset(SkyLight, 0xff, cChunkDef::NumBlocks / 2); // By default, data not present in the NBT means air, which means full skylight
|
||||
memset(BlockTypes, E_BLOCK_AIR, sizeof(BlockTypes));
|
||||
memset(MetaData, 0, sizeof(MetaData));
|
||||
memset(SkyLight, 0xff, sizeof(SkyLight)); // By default, data not present in the NBT means air, which means full skylight
|
||||
memset(BlockLight, 0x00, sizeof(BlockLight));
|
||||
|
||||
// Load the blockdata, blocklight and skylight:
|
||||
int Level = a_NBT.FindChildByName(0, "Level");
|
||||
@@ -412,56 +419,26 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
|
||||
{
|
||||
continue;
|
||||
}
|
||||
CopyNBTData(a_NBT, Child, "Blocks", &(BlockData[y * 4096]), 4096);
|
||||
CopyNBTData(a_NBT, Child, "Data", &(MetaData[y * 2048]), 2048);
|
||||
CopyNBTData(a_NBT, Child, "SkyLight", &(SkyLight[y * 2048]), 2048);
|
||||
CopyNBTData(a_NBT, Child, "BlockLight", &(BlockLight[y * 2048]), 2048);
|
||||
CopyNBTData(a_NBT, Child, "Blocks", (char *)&(BlockTypes[y * 4096]), 4096);
|
||||
CopyNBTData(a_NBT, Child, "Data", (char *)&(MetaData[y * 2048]), 2048);
|
||||
CopyNBTData(a_NBT, Child, "SkyLight", (char *)&(SkyLight[y * 2048]), 2048);
|
||||
CopyNBTData(a_NBT, Child, "BlockLight", (char *)&(BlockLight[y * 2048]), 2048);
|
||||
} // for itr - LevelSections[]
|
||||
|
||||
cEntityList Entities;
|
||||
cBlockEntityList BlockEntities;
|
||||
// Load the biomes from NBT, if present and valid:
|
||||
cChunkDef::BiomeMap BiomeMap;
|
||||
cChunkDef::BiomeMap * Biomes = LoadBiomeMapFromNBT(&BiomeMap, a_NBT, a_NBT.FindChildByName(Level, "Biomes"));
|
||||
|
||||
// Load the entities from NBT:
|
||||
cEntityList Entities;
|
||||
cBlockEntityList BlockEntities;
|
||||
LoadEntitiesFromNBT (Entities, a_NBT, a_NBT.FindChildByName(Level, "Entities"));
|
||||
LoadBlockEntitiesFromNBT(BlockEntities, a_NBT, a_NBT.FindChildByName(Level, "TileEntities"));
|
||||
|
||||
#if (AXIS_ORDER == AXIS_ORDER_YZX)
|
||||
// Reorder the chunk data - walk the MCA-formatted data sequentially and copy it into the right place in the ChunkData:
|
||||
BLOCKTYPE ChunkData[cChunkDef::BlockDataSize];
|
||||
memset(ChunkData, 0, sizeof(ChunkData));
|
||||
int Index = 0; // Index into the MCA-formatted data, incremented sequentially
|
||||
for (int y = 0; y < cChunkDef::Height; y++) for (int z = 0; z < cChunkDef::Width; z++) for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
ChunkData[cChunk::MakeIndex(x, y, z)] = BlockData[Index];
|
||||
Index++;
|
||||
} // for y/z/x
|
||||
BLOCKTYPE * ChunkMeta = ChunkData + cChunkDef::NumBlocks;
|
||||
Index = 0;
|
||||
for (int y = 0; y < cChunkDef::Height; y++) for (int z = 0; z < cChunkDef::Width; z++) for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
cChunk::SetNibble(ChunkMeta, x, y, z, MetaData[Index / 2] >> ((Index % 2) * 4));
|
||||
Index++;
|
||||
} // for y/z/x
|
||||
BLOCKTYPE * ChunkBlockLight = ChunkMeta + cChunkDef::NumBlocks / 2;
|
||||
Index = 0;
|
||||
for (int y = 0; y < cChunkDef::Height; y++) for (int z = 0; z < cChunkDef::Width; z++) for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
cChunk::SetNibble(ChunkBlockLight, x, y, z, BlockLight[Index / 2] >> ((Index % 2) * 4));
|
||||
Index++;
|
||||
} // for y/z/x
|
||||
BLOCKTYPE * ChunkSkyLight = ChunkBlockLight + cChunkDef::NumBlocks / 2;
|
||||
Index = 0;
|
||||
for (int y = 0; y < cChunkDef::Height; y++) for (int z = 0; z < cChunkDef::Width; z++) for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
cChunk::SetNibble(ChunkSkyLight, x, y, z, SkyLight[Index / 2] >> ((Index % 2) * 4));
|
||||
Index++;
|
||||
} // for y/z/x
|
||||
#else // AXIS_ORDER_YZX
|
||||
BLOCKTYPE * ChunkData = BlockData;
|
||||
#endif // else AXIS_ORDER_YZX
|
||||
bool IsLightValid = (a_NBT.FindChildByName(Level, "MCSIsLightValid") > 0);
|
||||
|
||||
/*
|
||||
// Delete the comment above for really cool stuff :)
|
||||
// Uncomment this block for really cool stuff :)
|
||||
// DEBUG magic: Invert the underground, so that we can see the MC generator in action :)
|
||||
bool ShouldInvert[cChunkDef::Width * cChunkDef::Width];
|
||||
memset(ShouldInvert, 0, sizeof(ShouldInvert));
|
||||
@@ -484,15 +461,14 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
|
||||
memset(ChunkData + cChunkDef::SkyLightOffset, 0xff, cChunkDef::NumBlocks / 2);
|
||||
//*/
|
||||
|
||||
m_World->ChunkDataLoaded(
|
||||
m_World->SetChunkData(
|
||||
a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ,
|
||||
ChunkData,
|
||||
ChunkData + cChunkDef::MetaOffset,
|
||||
ChunkData + cChunkDef::LightOffset,
|
||||
ChunkData + cChunkDef::SkyLightOffset,
|
||||
NULL,
|
||||
Entities,
|
||||
BlockEntities
|
||||
BlockTypes, MetaData,
|
||||
IsLightValid ? BlockLight : NULL,
|
||||
IsLightValid ? SkyLight : NULL,
|
||||
NULL, Biomes,
|
||||
Entities, BlockEntities,
|
||||
false
|
||||
);
|
||||
return true;
|
||||
}
|
||||
@@ -525,24 +501,37 @@ bool cWSSAnvil::SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_
|
||||
}
|
||||
Serializer.Finish(); // Close NBT tags
|
||||
|
||||
// TODO: Save biomes:
|
||||
// TODO: Save biomes, both MCS (IntArray) and MC-vanilla (ByteArray):
|
||||
// Level->Add(new cNBTByteArray(Level, "Biomes", AString(Serializer.m_Biomes, sizeof(Serializer.m_Biomes));
|
||||
// Level->Add(new cNBTByteArray(Level, "MCSBiomes", AString(Serializer.m_Biomes, sizeof(Serializer.m_Biomes));
|
||||
|
||||
// Save blockdata:
|
||||
a_Writer.BeginList("Sections", TAG_Compound);
|
||||
int SliceSizeBlock = cChunkDef::Width * cChunkDef::Width * 16;
|
||||
int SliceSizeNibble = SliceSizeBlock / 2;
|
||||
const char * BlockTypes = (const char *)(Serializer.m_BlockTypes);
|
||||
const char * BlockMetas = (const char *)(Serializer.m_BlockMetas);
|
||||
const char * BlockLight = (const char *)(Serializer.m_BlockLight);
|
||||
const char * BlockSkyLight = (const char *)(Serializer.m_BlockSkyLight);
|
||||
for (int Y = 0; Y < 16; Y++)
|
||||
{
|
||||
a_Writer.BeginCompound("");
|
||||
a_Writer.AddByteArray("Blocks", Serializer.m_BlockTypes + Y * SliceSizeBlock, SliceSizeBlock);
|
||||
a_Writer.AddByteArray("Data", Serializer.m_BlockMetas + Y * SliceSizeNibble, SliceSizeNibble);
|
||||
a_Writer.AddByteArray("SkyLight", Serializer.m_BlockSkyLight + Y * SliceSizeNibble, SliceSizeNibble);
|
||||
a_Writer.AddByteArray("BlockLight", Serializer.m_BlockLight + Y * SliceSizeNibble, SliceSizeNibble);
|
||||
a_Writer.AddByte("Y", Y);
|
||||
a_Writer.AddByteArray("Blocks", BlockTypes + Y * SliceSizeBlock, SliceSizeBlock);
|
||||
a_Writer.AddByteArray("Data", BlockMetas + Y * SliceSizeNibble, SliceSizeNibble);
|
||||
a_Writer.AddByteArray("SkyLight", BlockSkyLight + Y * SliceSizeNibble, SliceSizeNibble);
|
||||
a_Writer.AddByteArray("BlockLight", BlockLight + Y * SliceSizeNibble, SliceSizeNibble);
|
||||
a_Writer.AddByte("Y", (unsigned char)Y);
|
||||
a_Writer.EndCompound();
|
||||
}
|
||||
a_Writer.EndList(); // "Sections"
|
||||
|
||||
// Store the information that the lighting is valid.
|
||||
// For compatibility reason, the default is "invalid" (missing) - this means older data is re-lighted upon loading.
|
||||
if (Serializer.IsLightValid())
|
||||
{
|
||||
a_Writer.AddByte("MCSIsLightValid", 1);
|
||||
}
|
||||
|
||||
a_Writer.EndCompound(); // "Level"
|
||||
return true;
|
||||
}
|
||||
@@ -551,6 +540,33 @@ bool cWSSAnvil::SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_
|
||||
|
||||
|
||||
|
||||
cChunkDef::BiomeMap * cWSSAnvil::LoadBiomeMapFromNBT(cChunkDef::BiomeMap * a_BiomeMap, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_ByteArray))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (a_NBT.GetDataLength(a_TagIdx) != sizeof(*a_BiomeMap))
|
||||
{
|
||||
// The biomes stored don't match in size
|
||||
return NULL;
|
||||
}
|
||||
memcpy(a_BiomeMap, a_NBT.GetData(a_TagIdx), sizeof(*a_BiomeMap));
|
||||
for (int i = 0; i < ARRAYCOUNT(*a_BiomeMap); i++)
|
||||
{
|
||||
if ((*a_BiomeMap)[i] == 0xff)
|
||||
{
|
||||
// Unassigned biomes
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return a_BiomeMap;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadEntitiesFromNBT(cEntityList & a_Entitites, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
// TODO: Load the entities
|
||||
@@ -672,12 +688,35 @@ bool cWSSAnvil::GetBlockEntityNBTPos(const cParsedNBT & a_NBT, int a_TagIdx, int
|
||||
cWSSAnvil::cMCAFile::cMCAFile(const AString & a_FileName, int a_RegionX, int a_RegionZ) :
|
||||
m_RegionX(a_RegionX),
|
||||
m_RegionZ(a_RegionZ),
|
||||
m_File(a_FileName, cFile::fmReadWrite),
|
||||
m_FileName(a_FileName)
|
||||
{
|
||||
if (!m_File.IsOpen())
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWSSAnvil::cMCAFile::OpenFile(bool a_IsForReading)
|
||||
{
|
||||
if (m_File.IsOpen())
|
||||
{
|
||||
return;
|
||||
// Already open
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a_IsForReading)
|
||||
{
|
||||
if (!cFile::Exists(m_FileName))
|
||||
{
|
||||
// We want to read and the file doesn't exist. Fail.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_File.Open(m_FileName, cFile::fmReadWrite))
|
||||
{
|
||||
// The file failed to open
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load the header:
|
||||
@@ -687,15 +726,16 @@ cWSSAnvil::cMCAFile::cMCAFile(const AString & a_FileName, int a_RegionX, int a_R
|
||||
// Try writing a NULL header (both chunk offsets and timestamps):
|
||||
memset(m_Header, 0, sizeof(m_Header));
|
||||
if (
|
||||
(m_File.Write(m_Header, sizeof(m_Header)) != sizeof(m_Header)) ||
|
||||
(m_File.Write(m_Header, sizeof(m_Header)) != sizeof(m_Header))
|
||||
(m_File.Write(m_Header, sizeof(m_Header)) != sizeof(m_Header)) || // Real header - chunk offsets
|
||||
(m_File.Write(m_Header, sizeof(m_Header)) != sizeof(m_Header)) // Bogus data for the chunk timestamps
|
||||
)
|
||||
{
|
||||
LOGWARNING("Cannot process MCA header in file \"%s\", chunks in that file will be lost", m_FileName.c_str());
|
||||
m_File.Close();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -704,10 +744,11 @@ cWSSAnvil::cMCAFile::cMCAFile(const AString & a_FileName, int a_RegionX, int a_R
|
||||
|
||||
bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a_Data)
|
||||
{
|
||||
if (!m_File.IsOpen())
|
||||
if (!OpenFile(true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int LocalX = a_Chunk.m_ChunkX % 32;
|
||||
if (LocalX < 0)
|
||||
{
|
||||
@@ -720,7 +761,6 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a
|
||||
}
|
||||
unsigned ChunkLocation = ntohl(m_Header[LocalX + 32 * LocalZ]);
|
||||
unsigned ChunkOffset = ChunkLocation >> 8;
|
||||
unsigned ChunkLen = ChunkLocation & 0xff;
|
||||
|
||||
m_File.Seek(ChunkOffset * 4096);
|
||||
|
||||
@@ -753,10 +793,11 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a
|
||||
|
||||
bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AString & a_Data)
|
||||
{
|
||||
if (!m_File.IsOpen())
|
||||
if (!OpenFile(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int LocalX = a_Chunk.m_ChunkX % 32;
|
||||
if (LocalX < 0)
|
||||
{
|
||||
@@ -782,7 +823,7 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (m_File.Write(a_Data.data(), a_Data.size()) != a_Data.size())
|
||||
if (m_File.Write(a_Data.data(), a_Data.size()) != (int)(a_Data.size()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user