Anvil: Allow loading chunks without HeightMap.
This commit is contained in:
parent
c5412becd1
commit
889eba1df5
@ -57,6 +57,7 @@ target_sources(
|
|||||||
Root.cpp
|
Root.cpp
|
||||||
Scoreboard.cpp
|
Scoreboard.cpp
|
||||||
Server.cpp
|
Server.cpp
|
||||||
|
SetChunkData.cpp
|
||||||
SpawnPrepare.cpp
|
SpawnPrepare.cpp
|
||||||
StatisticsManager.cpp
|
StatisticsManager.cpp
|
||||||
StringCompression.cpp
|
StringCompression.cpp
|
||||||
|
30
src/SetChunkData.cpp
Normal file
30
src/SetChunkData.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include "Globals.h"
|
||||||
|
#include "SetChunkData.h"
|
||||||
|
#include "BlockType.h"
|
||||||
|
#include "Entities/Entity.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void SetChunkData::UpdateHeightMap()
|
||||||
|
{
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
HEIGHTTYPE Height = 0;
|
||||||
|
for (HEIGHTTYPE y = cChunkDef::Height - 1; y > 0; y--)
|
||||||
|
{
|
||||||
|
BLOCKTYPE BlockType = BlockData.GetBlock({x, y, z});
|
||||||
|
if (BlockType != E_BLOCK_AIR)
|
||||||
|
{
|
||||||
|
Height = y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // for y
|
||||||
|
auto idx = x + cChunkDef::Width * z;
|
||||||
|
HeightMap[idx] = Height;
|
||||||
|
} // for z
|
||||||
|
} // for x
|
||||||
|
}
|
@ -1,8 +1,3 @@
|
|||||||
|
|
||||||
// SetChunkData.h
|
|
||||||
|
|
||||||
// Defines the SetChunkData struct that contains the data for a loaded / generated chunk, ready to be set
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ChunkData.h"
|
#include "ChunkData.h"
|
||||||
@ -12,6 +7,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Contains the data for a loaded / generated chunk, ready to be set into a cWorld. */
|
||||||
struct SetChunkData
|
struct SetChunkData
|
||||||
{
|
{
|
||||||
/** Initialise the structure with chunk coordinates.
|
/** Initialise the structure with chunk coordinates.
|
||||||
@ -33,4 +29,8 @@ struct SetChunkData
|
|||||||
cBlockEntities BlockEntities;
|
cBlockEntities BlockEntities;
|
||||||
|
|
||||||
bool IsLightValid;
|
bool IsLightValid;
|
||||||
|
|
||||||
|
|
||||||
|
/** Recalculates the HeightMap based on BlockData contents. */
|
||||||
|
void UpdateHeightMap();
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,3 @@
|
|||||||
|
|
||||||
// WSSAnvil.cpp
|
|
||||||
|
|
||||||
// Implements the cWSSAnvil class representing the Anvil world storage scheme
|
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "WSSAnvil.h"
|
#include "WSSAnvil.h"
|
||||||
#include "NBTChunkSerializer.h"
|
#include "NBTChunkSerializer.h"
|
||||||
@ -85,7 +80,7 @@ Since only the header is actually in the memory, this number can be high, but st
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cWSSAnvil:
|
// cWSSAnvil:
|
||||||
|
|
||||||
cWSSAnvil::cWSSAnvil(cWorld * a_World, int a_CompressionFactor) :
|
cWSSAnvil::cWSSAnvil(cWorld * a_World, int a_CompressionFactor):
|
||||||
Super(a_World),
|
Super(a_World),
|
||||||
m_Compressor(a_CompressionFactor)
|
m_Compressor(a_CompressionFactor)
|
||||||
{
|
{
|
||||||
@ -178,7 +173,7 @@ bool cWSSAnvil::SaveChunk(const cChunkCoords & a_Chunk)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWSSAnvil::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ, const AString & a_Reason, const ContiguousByteBufferView a_ChunkDataToSave)
|
void cWSSAnvil::ChunkLoadFailed(const cChunkCoords a_ChunkCoords, const AString & a_Reason, const ContiguousByteBufferView a_ChunkDataToSave)
|
||||||
{
|
{
|
||||||
// Construct the filename for offloading:
|
// Construct the filename for offloading:
|
||||||
auto OffloadFileName = fmt::format(FMT_STRING("{0}{1}region{1}badchunks"), m_World->GetDataPath(), cFile::PathSeparator());
|
auto OffloadFileName = fmt::format(FMT_STRING("{0}{1}region{1}badchunks"), m_World->GetDataPath(), cFile::PathSeparator());
|
||||||
@ -192,16 +187,16 @@ void cWSSAnvil::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ, const AString & a_Re
|
|||||||
#endif
|
#endif
|
||||||
OffloadFileName.append(fmt::format(
|
OffloadFileName.append(fmt::format(
|
||||||
FMT_STRING("{}ch.{}.{}.{}-{:02d}-{:02d}-{:02d}-{:02d}-{:02d}.dat"),
|
FMT_STRING("{}ch.{}.{}.{}-{:02d}-{:02d}-{:02d}-{:02d}-{:02d}.dat"),
|
||||||
cFile::PathSeparator(), a_ChunkX, a_ChunkZ,
|
cFile::PathSeparator(), a_ChunkCoords.m_ChunkX, a_ChunkCoords.m_ChunkZ,
|
||||||
stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec
|
stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec
|
||||||
));
|
));
|
||||||
|
|
||||||
// Log the warning to console:
|
// Log the warning to console:
|
||||||
const int RegionX = FAST_FLOOR_DIV(a_ChunkX, 32);
|
const int RegionX = FAST_FLOOR_DIV(a_ChunkCoords.m_ChunkX, 32);
|
||||||
const int RegionZ = FAST_FLOOR_DIV(a_ChunkZ, 32);
|
const int RegionZ = FAST_FLOOR_DIV(a_ChunkCoords.m_ChunkZ, 32);
|
||||||
auto Info = fmt::format(
|
auto Info = fmt::format(
|
||||||
FMT_STRING("Loading chunk [{}, {}] for world {} from file r.{}.{}.mca failed: {} Offloading old chunk data to file {} and regenerating chunk."),
|
FMT_STRING("Loading chunk {} for world {} from file r.{}.{}.mca failed: {} Offloading old chunk data to file {} and regenerating chunk."),
|
||||||
a_ChunkX, a_ChunkZ, m_World->GetName(), RegionX, RegionZ, a_Reason, OffloadFileName
|
a_ChunkCoords, m_World->GetName(), RegionX, RegionZ, a_Reason, OffloadFileName
|
||||||
);
|
);
|
||||||
LOGWARNING("%s", Info);
|
LOGWARNING("%s", Info);
|
||||||
|
|
||||||
@ -329,7 +324,7 @@ bool cWSSAnvil::LoadChunkFromData(const cChunkCoords & a_Chunk, const Contiguous
|
|||||||
}
|
}
|
||||||
catch (const std::exception & Oops)
|
catch (const std::exception & Oops)
|
||||||
{
|
{
|
||||||
ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, Oops.what(), a_Data);
|
ChunkLoadFailed(a_Chunk, Oops.what(), a_Data);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -359,21 +354,21 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
|
|||||||
int Level = a_NBT.FindChildByName(0, "Level");
|
int Level = a_NBT.FindChildByName(0, "Level");
|
||||||
if (Level < 0)
|
if (Level < 0)
|
||||||
{
|
{
|
||||||
ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Missing NBT tag: Level", a_RawChunkData);
|
ChunkLoadFailed(a_Chunk, "Missing NBT tag: Level", a_RawChunkData);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Sections = a_NBT.FindChildByName(Level, "Sections");
|
int Sections = a_NBT.FindChildByName(Level, "Sections");
|
||||||
if ((Sections < 0) || (a_NBT.GetType(Sections) != TAG_List))
|
if ((Sections < 0) || (a_NBT.GetType(Sections) != TAG_List))
|
||||||
{
|
{
|
||||||
ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Missing NBT tag: Sections", a_RawChunkData);
|
ChunkLoadFailed(a_Chunk, "Missing NBT tag: Sections", a_RawChunkData);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
eTagType SectionsType = a_NBT.GetChildrenType(Sections);
|
eTagType SectionsType = a_NBT.GetChildrenType(Sections);
|
||||||
if ((SectionsType != TAG_Compound) && (SectionsType != TAG_End))
|
if ((SectionsType != TAG_Compound) && (SectionsType != TAG_End))
|
||||||
{
|
{
|
||||||
ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "NBT tag has wrong type: Sections", a_RawChunkData);
|
ChunkLoadFailed(a_Chunk, "NBT tag has wrong type: Sections", a_RawChunkData);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int Child = a_NBT.GetFirstChild(Sections); Child >= 0; Child = a_NBT.GetNextSibling(Child))
|
for (int Child = a_NBT.GetFirstChild(Sections); Child >= 0; Child = a_NBT.GetNextSibling(Child))
|
||||||
@ -381,14 +376,14 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
|
|||||||
const int SectionYTag = a_NBT.FindChildByName(Child, "Y");
|
const int SectionYTag = a_NBT.FindChildByName(Child, "Y");
|
||||||
if ((SectionYTag < 0) || (a_NBT.GetType(SectionYTag) != TAG_Byte))
|
if ((SectionYTag < 0) || (a_NBT.GetType(SectionYTag) != TAG_Byte))
|
||||||
{
|
{
|
||||||
ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "NBT tag missing or has wrong: Y", a_RawChunkData);
|
ChunkLoadFailed(a_Chunk, "NBT tag missing or has wrong: Y", a_RawChunkData);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int Y = a_NBT.GetByte(SectionYTag);
|
const int Y = a_NBT.GetByte(SectionYTag);
|
||||||
if ((Y < 0) || (Y > static_cast<int>(cChunkDef::NumSections - 1)))
|
if ((Y < 0) || (Y > static_cast<int>(cChunkDef::NumSections - 1)))
|
||||||
{
|
{
|
||||||
ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "NBT tag exceeds chunk bounds: Y", a_RawChunkData);
|
ChunkLoadFailed(a_Chunk, "NBT tag exceeds chunk bounds: Y", a_RawChunkData);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,7 +399,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Missing chunk block/light data", a_RawChunkData);
|
ChunkLoadFailed(a_Chunk, "Missing chunk block/light data", a_RawChunkData);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} // for itr - LevelSections[]
|
} // for itr - LevelSections[]
|
||||||
@ -412,15 +407,14 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
|
|||||||
// Load the biomes from NBT, if present and valid:
|
// Load the biomes from NBT, if present and valid:
|
||||||
if (!LoadBiomeMapFromNBT(Data.BiomeMap, a_NBT, a_NBT.FindChildByName(Level, "Biomes")))
|
if (!LoadBiomeMapFromNBT(Data.BiomeMap, a_NBT, a_NBT.FindChildByName(Level, "Biomes")))
|
||||||
{
|
{
|
||||||
ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Missing chunk biome data", a_RawChunkData);
|
ChunkLoadFailed(a_Chunk, "Missing chunk biome data", a_RawChunkData);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Height map too:
|
// Load the Height map, if it fails, recalculate it:
|
||||||
if (!LoadHeightMapFromNBT(Data.HeightMap, a_NBT, a_NBT.FindChildByName(Level, "HeightMap")))
|
if (!LoadHeightMapFromNBT(Data.HeightMap, a_NBT, a_NBT.FindChildByName(Level, "HeightMap")))
|
||||||
{
|
{
|
||||||
ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Missing chunk height data", a_RawChunkData);
|
Data.UpdateHeightMap();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the entities from NBT:
|
// Load the entities from NBT:
|
||||||
@ -3981,21 +3975,21 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, ContiguousB
|
|||||||
UInt32 ChunkSize = 0;
|
UInt32 ChunkSize = 0;
|
||||||
if (m_File.Read(&ChunkSize, 4) != 4)
|
if (m_File.Read(&ChunkSize, 4) != 4)
|
||||||
{
|
{
|
||||||
m_ParentSchema.ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Cannot read chunk size", {});
|
m_ParentSchema.ChunkLoadFailed(a_Chunk, "Cannot read chunk size", {});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ChunkSize = ntohl(ChunkSize);
|
ChunkSize = ntohl(ChunkSize);
|
||||||
if (ChunkSize < 1)
|
if (ChunkSize < 1)
|
||||||
{
|
{
|
||||||
// Chunk size too small
|
// Chunk size too small
|
||||||
m_ParentSchema.ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Chunk size too small", {});
|
m_ParentSchema.ChunkLoadFailed(a_Chunk, "Chunk size too small", {});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char CompressionType = 0;
|
char CompressionType = 0;
|
||||||
if (m_File.Read(&CompressionType, 1) != 1)
|
if (m_File.Read(&CompressionType, 1) != 1)
|
||||||
{
|
{
|
||||||
m_ParentSchema.ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Cannot read chunk compression", {});
|
m_ParentSchema.ChunkLoadFailed(a_Chunk, "Cannot read chunk compression", {});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ChunkSize--;
|
ChunkSize--;
|
||||||
@ -4003,14 +3997,14 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, ContiguousB
|
|||||||
a_Data = m_File.Read(ChunkSize);
|
a_Data = m_File.Read(ChunkSize);
|
||||||
if (a_Data.size() != ChunkSize)
|
if (a_Data.size() != ChunkSize)
|
||||||
{
|
{
|
||||||
m_ParentSchema.ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "Cannot read entire chunk data", a_Data);
|
m_ParentSchema.ChunkLoadFailed(a_Chunk, "Cannot read entire chunk data", a_Data);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CompressionType != 2)
|
if (CompressionType != 2)
|
||||||
{
|
{
|
||||||
// Chunk is in an unknown compression
|
// Chunk is in an unknown compression
|
||||||
m_ParentSchema.ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, fmt::format(FMT_STRING("Unknown chunk compression: {}"), CompressionType), a_Data);
|
m_ParentSchema.ChunkLoadFailed(a_Chunk, fmt::format(FMT_STRING("Unknown chunk compression: {}"), CompressionType), a_Data);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,11 +1,3 @@
|
|||||||
|
|
||||||
// WSSAnvil.h
|
|
||||||
|
|
||||||
// Interfaces to the cWSSAnvil class representing the Anvil world storage scheme
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../BlockEntities/BlockEntity.h"
|
#include "../BlockEntities/BlockEntity.h"
|
||||||
@ -30,22 +22,7 @@ class ChunkBlockData;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum
|
/** Implements the Anvil world storage schema. */
|
||||||
{
|
|
||||||
/** Maximum number of chunks in an MCA file - also the count of the header items */
|
|
||||||
MCA_MAX_CHUNKS = 32 * 32,
|
|
||||||
|
|
||||||
/** The MCA header is 8 KiB */
|
|
||||||
MCA_HEADER_SIZE = MCA_MAX_CHUNKS * 8,
|
|
||||||
|
|
||||||
/** There are 5 bytes of header in front of each chunk */
|
|
||||||
MCA_CHUNK_HEADER_LENGTH = 5,
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cWSSAnvil:
|
class cWSSAnvil:
|
||||||
public cWSSchema
|
public cWSSchema
|
||||||
{
|
{
|
||||||
@ -58,6 +35,19 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
/** Maximum number of chunks in an MCA file - also the count of the header items */
|
||||||
|
MCA_MAX_CHUNKS = 32 * 32,
|
||||||
|
|
||||||
|
/** The MCA header is 8 KiB */
|
||||||
|
MCA_HEADER_SIZE = MCA_MAX_CHUNKS * 8,
|
||||||
|
|
||||||
|
/** There are 5 bytes of header in front of each chunk */
|
||||||
|
MCA_CHUNK_HEADER_LENGTH = 5,
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
class cMCAFile
|
class cMCAFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -67,9 +57,9 @@ protected:
|
|||||||
bool GetChunkData (const cChunkCoords & a_Chunk, ContiguousByteBuffer & a_Data);
|
bool GetChunkData (const cChunkCoords & a_Chunk, ContiguousByteBuffer & a_Data);
|
||||||
bool SetChunkData (const cChunkCoords & a_Chunk, ContiguousByteBufferView a_Data);
|
bool SetChunkData (const cChunkCoords & a_Chunk, ContiguousByteBufferView a_Data);
|
||||||
|
|
||||||
int GetRegionX (void) const {return m_RegionX; }
|
int GetRegionX () const {return m_RegionX; }
|
||||||
int GetRegionZ (void) const {return m_RegionZ; }
|
int GetRegionZ () const {return m_RegionZ; }
|
||||||
const AString & GetFileName(void) const {return m_FileName; }
|
const AString & GetFileName() const {return m_FileName; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@ -102,7 +92,7 @@ protected:
|
|||||||
Compression::Compressor m_Compressor;
|
Compression::Compressor m_Compressor;
|
||||||
|
|
||||||
/** Reports that the specified chunk failed to load and saves the chunk data to an external file. */
|
/** Reports that the specified chunk failed to load and saves the chunk data to an external file. */
|
||||||
void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ, const AString & a_Reason, ContiguousByteBufferView a_ChunkDataToSave);
|
void ChunkLoadFailed(const cChunkCoords a_ChunkCoords, const AString & a_Reason, ContiguousByteBufferView a_ChunkDataToSave);
|
||||||
|
|
||||||
/** Gets chunk data from the correct file; locks file CS as needed */
|
/** Gets chunk data from the correct file; locks file CS as needed */
|
||||||
bool GetChunkData(const cChunkCoords & a_Chunk, ContiguousByteBuffer & a_Data);
|
bool GetChunkData(const cChunkCoords & a_Chunk, ContiguousByteBuffer & a_Data);
|
||||||
@ -306,5 +296,5 @@ protected:
|
|||||||
// cWSSchema overrides:
|
// cWSSchema overrides:
|
||||||
virtual bool LoadChunk(const cChunkCoords & a_Chunk) override;
|
virtual bool LoadChunk(const cChunkCoords & a_Chunk) override;
|
||||||
virtual bool SaveChunk(const cChunkCoords & a_Chunk) override;
|
virtual bool SaveChunk(const cChunkCoords & a_Chunk) override;
|
||||||
virtual const AString GetName(void) const override {return "anvil"; }
|
virtual const AString GetName() const override {return "anvil"; }
|
||||||
} ;
|
} ;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user