Optimise chunk set (#4260)
Closes #1244 Initially I was just going to add the cChunkData to cSetChunkData but profiling revealed that the copying wasn't even the biggest slowdown. Much more time was being spent in cChunk::CreateBlockEntities and cChunk::WakeUpSimulators than was in memcpy so I've made those significantly faster as well. Optimisations performed: * cSetChunkData now stores blocks in a cChunkData object * cChunkData objects can now perform moves even if they are using different pools * cChunk::CreateBlockEntities now iterates in the correct order and only over present chunk sections * Similarly for cChunk::WakeUpSimulators * cSetChunkData::CalculateHeightMap now shortcuts to the highest present chunk section before checking blocks directly
This commit is contained in:
parent
e27290f7d2
commit
31a11a6df4
@ -32,6 +32,25 @@ public:
|
|||||||
|
|
||||||
/** Frees the pointer passed in a_ptr, invalidating it */
|
/** Frees the pointer passed in a_ptr, invalidating it */
|
||||||
virtual void Free(T * a_ptr) = 0;
|
virtual void Free(T * a_ptr) = 0;
|
||||||
|
|
||||||
|
/** Two pools compare equal if memory allocated by one can be freed by the other */
|
||||||
|
bool IsEqual(const cAllocationPool & a_Other) const NOEXCEPT
|
||||||
|
{
|
||||||
|
return ((this == &a_Other) || DoIsEqual(a_Other) || a_Other.DoIsEqual(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator == (const cAllocationPool & a_Lhs, const cAllocationPool & a_Rhs)
|
||||||
|
{
|
||||||
|
return a_Lhs.IsEqual(a_Rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator != (const cAllocationPool & a_Lhs, const cAllocationPool & a_Rhs)
|
||||||
|
{
|
||||||
|
return !a_Lhs.IsEqual(a_Rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual bool DoIsEqual(const cAllocationPool & a_Other) const NOEXCEPT = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -40,16 +59,17 @@ public:
|
|||||||
|
|
||||||
/** Allocates memory storing unused elements in a linked list. Keeps at least NumElementsInReserve
|
/** Allocates memory storing unused elements in a linked list. Keeps at least NumElementsInReserve
|
||||||
elements in the list unless malloc fails so that the program has a reserve to handle OOM. */
|
elements in the list unless malloc fails so that the program has a reserve to handle OOM. */
|
||||||
template <class T, size_t NumElementsInReserve>
|
template <class T>
|
||||||
class cListAllocationPool:
|
class cListAllocationPool:
|
||||||
public cAllocationPool<T>
|
public cAllocationPool<T>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
cListAllocationPool(std::unique_ptr<typename cAllocationPool<T>::cStarvationCallbacks> a_Callbacks):
|
cListAllocationPool(std::unique_ptr<typename cAllocationPool<T>::cStarvationCallbacks> a_Callbacks, size_t a_NumElementsInReserve):
|
||||||
|
m_NumElementsInReserve(a_NumElementsInReserve),
|
||||||
m_Callbacks(std::move(a_Callbacks))
|
m_Callbacks(std::move(a_Callbacks))
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < NumElementsInReserve; i++)
|
for (size_t i = 0; i < m_NumElementsInReserve; i++)
|
||||||
{
|
{
|
||||||
void * space = malloc(sizeof(T));
|
void * space = malloc(sizeof(T));
|
||||||
if (space == nullptr)
|
if (space == nullptr)
|
||||||
@ -74,7 +94,7 @@ public:
|
|||||||
|
|
||||||
virtual T * Allocate() override
|
virtual T * Allocate() override
|
||||||
{
|
{
|
||||||
if (m_FreeList.size() <= NumElementsInReserve)
|
if (m_FreeList.size() <= m_NumElementsInReserve)
|
||||||
{
|
{
|
||||||
void * space = malloc(sizeof(T));
|
void * space = malloc(sizeof(T));
|
||||||
if (space != nullptr)
|
if (space != nullptr)
|
||||||
@ -93,7 +113,7 @@ public:
|
|||||||
#pragma pop_macro("new")
|
#pragma pop_macro("new")
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (m_FreeList.size() == NumElementsInReserve)
|
else if (m_FreeList.size() == m_NumElementsInReserve)
|
||||||
{
|
{
|
||||||
m_Callbacks->OnStartUsingReserve();
|
m_Callbacks->OnStartUsingReserve();
|
||||||
}
|
}
|
||||||
@ -134,15 +154,22 @@ public:
|
|||||||
// placement destruct.
|
// placement destruct.
|
||||||
a_ptr->~T();
|
a_ptr->~T();
|
||||||
m_FreeList.push_front(a_ptr);
|
m_FreeList.push_front(a_ptr);
|
||||||
if (m_FreeList.size() == NumElementsInReserve)
|
if (m_FreeList.size() == m_NumElementsInReserve)
|
||||||
{
|
{
|
||||||
m_Callbacks->OnEndUsingReserve();
|
m_Callbacks->OnEndUsingReserve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/** The minimum number of elements to keep in the free list before malloc fails */
|
||||||
|
size_t m_NumElementsInReserve;
|
||||||
std::list<void *> m_FreeList;
|
std::list<void *> m_FreeList;
|
||||||
std::unique_ptr<typename cAllocationPool<T>::cStarvationCallbacks> m_Callbacks;
|
std::unique_ptr<typename cAllocationPool<T>::cStarvationCallbacks> m_Callbacks;
|
||||||
|
|
||||||
|
virtual bool DoIsEqual(const cAllocationPool<T> & a_Other) const NOEXCEPT override
|
||||||
|
{
|
||||||
|
return (dynamic_cast<const cListAllocationPool<T>*>(&a_Other) != nullptr);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
125
src/Chunk.cpp
125
src/Chunk.cpp
@ -322,26 +322,15 @@ void cChunk::SetAllData(cSetChunkData & a_SetChunkData)
|
|||||||
memcpy(m_BiomeMap, a_SetChunkData.GetBiomes(), sizeof(m_BiomeMap));
|
memcpy(m_BiomeMap, a_SetChunkData.GetBiomes(), sizeof(m_BiomeMap));
|
||||||
memcpy(m_HeightMap, a_SetChunkData.GetHeightMap(), sizeof(m_HeightMap));
|
memcpy(m_HeightMap, a_SetChunkData.GetHeightMap(), sizeof(m_HeightMap));
|
||||||
|
|
||||||
m_ChunkData.SetBlockTypes(a_SetChunkData.GetBlockTypes());
|
m_ChunkData.Assign(std::move(a_SetChunkData.GetChunkData()));
|
||||||
m_ChunkData.SetMetas(a_SetChunkData.GetBlockMetas());
|
m_IsLightValid = a_SetChunkData.IsLightValid();
|
||||||
if (a_SetChunkData.IsLightValid())
|
|
||||||
{
|
|
||||||
m_ChunkData.SetBlockLight(a_SetChunkData.GetBlockLight());
|
|
||||||
m_ChunkData.SetSkyLight(a_SetChunkData.GetSkyLight());
|
|
||||||
m_IsLightValid = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_IsLightValid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the block entities present - either the loader / saver has better, or we'll create empty ones:
|
// Clear the block entities present - either the loader / saver has better, or we'll create empty ones:
|
||||||
for (auto & KeyPair : m_BlockEntities)
|
for (auto & KeyPair : m_BlockEntities)
|
||||||
{
|
{
|
||||||
delete KeyPair.second;
|
delete KeyPair.second;
|
||||||
}
|
}
|
||||||
m_BlockEntities.clear();
|
m_BlockEntities = std::move(a_SetChunkData.GetBlockEntities());
|
||||||
std::swap(a_SetChunkData.GetBlockEntities(), m_BlockEntities);
|
|
||||||
|
|
||||||
// Check that all block entities have a valid blocktype at their respective coords (DEBUG-mode only):
|
// Check that all block entities have a valid blocktype at their respective coords (DEBUG-mode only):
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
@ -504,9 +493,9 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cChunk::HasBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ)
|
bool cChunk::HasBlockEntityAt(Vector3i a_BlockPos)
|
||||||
{
|
{
|
||||||
return (GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ) != nullptr);
|
return (GetBlockEntity(a_BlockPos) != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1433,48 +1422,32 @@ int cChunk::GetHeight(int a_X, int a_Z)
|
|||||||
|
|
||||||
void cChunk::CreateBlockEntities(void)
|
void cChunk::CreateBlockEntities(void)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < Width; x++)
|
for (size_t SectionIdx = 0; SectionIdx != cChunkData::NumSections; ++SectionIdx)
|
||||||
{
|
{
|
||||||
for (int z = 0; z < Width; z++)
|
const auto * Section = m_ChunkData.GetSection(SectionIdx);
|
||||||
|
if (Section == nullptr)
|
||||||
{
|
{
|
||||||
for (int y = 0; y < Height; y++)
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t BlockIdx = 0; BlockIdx != cChunkData::SectionBlockCount; ++BlockIdx)
|
||||||
{
|
{
|
||||||
BLOCKTYPE BlockType = GetBlock(x, y, z);
|
auto BlockType = Section->m_BlockTypes[BlockIdx];
|
||||||
switch (BlockType)
|
if (cBlockEntity::IsBlockEntityBlockType(BlockType))
|
||||||
{
|
{
|
||||||
case E_BLOCK_BEACON:
|
auto RelPos = IndexToCoordinate(BlockIdx);
|
||||||
case E_BLOCK_BED:
|
RelPos.y += SectionIdx * cChunkData::SectionHeight;
|
||||||
case E_BLOCK_TRAPPED_CHEST:
|
auto WorldPos = RelativeToAbsolute(RelPos, m_PosX, m_PosZ);
|
||||||
case E_BLOCK_CHEST:
|
|
||||||
case E_BLOCK_COMMAND_BLOCK:
|
if (!HasBlockEntityAt(WorldPos))
|
||||||
case E_BLOCK_DISPENSER:
|
|
||||||
case E_BLOCK_DROPPER:
|
|
||||||
case E_BLOCK_ENDER_CHEST:
|
|
||||||
case E_BLOCK_LIT_FURNACE:
|
|
||||||
case E_BLOCK_FURNACE:
|
|
||||||
case E_BLOCK_HOPPER:
|
|
||||||
case E_BLOCK_SIGN_POST:
|
|
||||||
case E_BLOCK_WALLSIGN:
|
|
||||||
case E_BLOCK_HEAD:
|
|
||||||
case E_BLOCK_NOTE_BLOCK:
|
|
||||||
case E_BLOCK_JUKEBOX:
|
|
||||||
case E_BLOCK_FLOWER_POT:
|
|
||||||
case E_BLOCK_MOB_SPAWNER:
|
|
||||||
case E_BLOCK_BREWING_STAND:
|
|
||||||
{
|
|
||||||
if (!HasBlockEntityAt(x + m_PosX * Width, y, z + m_PosZ * Width))
|
|
||||||
{
|
{
|
||||||
AddBlockEntityClean(cBlockEntity::CreateByBlockType(
|
AddBlockEntityClean(cBlockEntity::CreateByBlockType(
|
||||||
BlockType, GetMeta(x, y, z),
|
BlockType, GetMeta(RelPos), WorldPos.x, WorldPos.y, WorldPos.z, m_World
|
||||||
x + m_PosX * Width, y, z + m_PosZ * Width, m_World
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} // switch (BlockType)
|
}
|
||||||
} // for y
|
}
|
||||||
} // for z
|
|
||||||
} // for x
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1483,38 +1456,47 @@ void cChunk::CreateBlockEntities(void)
|
|||||||
|
|
||||||
void cChunk::WakeUpSimulators(void)
|
void cChunk::WakeUpSimulators(void)
|
||||||
{
|
{
|
||||||
cSimulator * WaterSimulator = m_World->GetWaterSimulator();
|
auto * WaterSimulator = m_World->GetWaterSimulator();
|
||||||
cSimulator * LavaSimulator = m_World->GetLavaSimulator();
|
auto * LavaSimulator = m_World->GetLavaSimulator();
|
||||||
cSimulator * RedstoneSimulator = m_World->GetRedstoneSimulator();
|
auto * RedstoneSimulator = m_World->GetRedstoneSimulator();
|
||||||
int BaseX = m_PosX * cChunkDef::Width;
|
|
||||||
int BaseZ = m_PosZ * cChunkDef::Width;
|
|
||||||
for (int x = 0; x < Width; x++)
|
|
||||||
{
|
|
||||||
int BlockX = x + BaseX;
|
|
||||||
for (int z = 0; z < Width; z++)
|
|
||||||
{
|
|
||||||
int BlockZ = z + BaseZ;
|
|
||||||
for (int y = GetHeight(x, z); y >= 0; y--)
|
|
||||||
{
|
|
||||||
BLOCKTYPE Block = GetBlock(x, y, z);
|
|
||||||
|
|
||||||
// The redstone sim takes multiple blocks, use the inbuilt checker
|
for (size_t SectionIdx = 0; SectionIdx != cChunkData::NumSections; ++SectionIdx)
|
||||||
if (RedstoneSimulator->IsAllowedBlock(Block))
|
{
|
||||||
|
const auto * Section = m_ChunkData.GetSection(SectionIdx);
|
||||||
|
if (Section == nullptr)
|
||||||
{
|
{
|
||||||
RedstoneSimulator->AddBlock({BlockX, y, BlockZ}, this);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (Block)
|
for (size_t BlockIdx = 0; BlockIdx != cChunkData::SectionBlockCount; ++BlockIdx)
|
||||||
|
{
|
||||||
|
auto BlockType = Section->m_BlockTypes[BlockIdx];
|
||||||
|
|
||||||
|
// Defer calculation until it's actually needed
|
||||||
|
auto WorldPos = [&]
|
||||||
|
{
|
||||||
|
auto RelPos = IndexToCoordinate(BlockIdx);
|
||||||
|
RelPos.y += SectionIdx * cChunkData::SectionHeight;
|
||||||
|
return RelativeToAbsolute(RelPos, m_PosX, m_PosZ);
|
||||||
|
};
|
||||||
|
|
||||||
|
// The redstone sim takes multiple blocks, use the inbuilt checker
|
||||||
|
if (RedstoneSimulator->IsAllowedBlock(BlockType))
|
||||||
|
{
|
||||||
|
RedstoneSimulator->AddBlock(WorldPos(), this);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (BlockType)
|
||||||
{
|
{
|
||||||
case E_BLOCK_WATER:
|
case E_BLOCK_WATER:
|
||||||
{
|
{
|
||||||
WaterSimulator->AddBlock({BlockX, y, BlockZ}, this);
|
WaterSimulator->AddBlock(WorldPos(), this);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case E_BLOCK_LAVA:
|
case E_BLOCK_LAVA:
|
||||||
{
|
{
|
||||||
LavaSimulator->AddBlock({BlockX, y, BlockZ}, this);
|
LavaSimulator->AddBlock(WorldPos(), this);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -1522,9 +1504,8 @@ void cChunk::WakeUpSimulators(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} // switch (BlockType)
|
} // switch (BlockType)
|
||||||
} // for y
|
}
|
||||||
} // for z
|
}
|
||||||
} // for x
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ public:
|
|||||||
void WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes);
|
void WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes);
|
||||||
|
|
||||||
/** Returns true if there is a block entity at the coords specified */
|
/** Returns true if there is a block entity at the coords specified */
|
||||||
bool HasBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ);
|
bool HasBlockEntityAt(Vector3i a_BlockPos);
|
||||||
|
|
||||||
/** Sets or resets the internal flag that prevents chunk from being unloaded.
|
/** Sets or resets the internal flag that prevents chunk from being unloaded.
|
||||||
The flag is cumulative - it can be set multiple times and then needs to be un-set that many times
|
The flag is cumulative - it can be set multiple times and then needs to be un-set that many times
|
||||||
|
@ -113,7 +113,7 @@ void cChunkData::Assign(cChunkData && a_Other)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (&m_Pool != &a_Other.m_Pool)
|
if (m_Pool != a_Other.m_Pool)
|
||||||
{
|
{
|
||||||
// Cannot transfer the memory, do a copy instead
|
// Cannot transfer the memory, do a copy instead
|
||||||
const cChunkData & CopyOther = a_Other;
|
const cChunkData & CopyOther = a_Other;
|
||||||
|
@ -115,13 +115,13 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
cChunkDataCopyCollector():
|
cChunkDataCopyCollector():
|
||||||
m_Pool(cpp14::make_unique<MemCallbacks>()),
|
m_Pool(cpp14::make_unique<MemCallbacks>(), cChunkData::NumSections), // Keep 1 chunk worth of reserve
|
||||||
m_Data(m_Pool)
|
m_Data(m_Pool)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cListAllocationPool<cChunkData::sChunkSection, cChunkData::NumSections> m_Pool; // Keep 1 chunk worth of reserve
|
cListAllocationPool<cChunkData::sChunkSection> m_Pool;
|
||||||
cChunkData m_Data;
|
cChunkData m_Data;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -207,19 +207,19 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline static Vector3i IndexToCoordinate( unsigned int index)
|
inline static Vector3i IndexToCoordinate(size_t index)
|
||||||
{
|
{
|
||||||
#if AXIS_ORDER == AXIS_ORDER_XZY
|
#if AXIS_ORDER == AXIS_ORDER_XZY
|
||||||
return Vector3i( // 1.2
|
return Vector3i( // 1.2
|
||||||
index % cChunkDef::Width, // X
|
static_cast<int>(index % cChunkDef::Width), // X
|
||||||
index / (cChunkDef::Width * cChunkDef::Width), // Y
|
static_cast<int>(index / (cChunkDef::Width * cChunkDef::Width)), // Y
|
||||||
(index / cChunkDef::Width) % cChunkDef::Width // Z
|
static_cast<int>((index / cChunkDef::Width) % cChunkDef::Width) // Z
|
||||||
);
|
);
|
||||||
#elif AXIS_ORDER == AXIS_ORDER_YZX
|
#elif AXIS_ORDER == AXIS_ORDER_YZX
|
||||||
return Vector3i( // 1.1
|
return Vector3i( // 1.1
|
||||||
index / (cChunkDef::Height * cChunkDef::Width), // X
|
static_cast<int>(index / (cChunkDef::Height * cChunkDef::Width)), // X
|
||||||
index % cChunkDef::Height, // Y
|
static_cast<int>(index % cChunkDef::Height), // Y
|
||||||
(index / cChunkDef::Height) % cChunkDef::Width // Z
|
static_cast<int>((index / cChunkDef::Height) % cChunkDef::Width) // Z
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -38,10 +38,8 @@
|
|||||||
cChunkMap::cChunkMap(cWorld * a_World) :
|
cChunkMap::cChunkMap(cWorld * a_World) :
|
||||||
m_World(a_World),
|
m_World(a_World),
|
||||||
m_Pool(
|
m_Pool(
|
||||||
new cListAllocationPool<cChunkData::sChunkSection, 1600>(
|
cpp14::make_unique<cListAllocationPool<cChunkData::sChunkSection>>(
|
||||||
std::unique_ptr<cAllocationPool<cChunkData::sChunkSection>::cStarvationCallbacks>(
|
cpp14::make_unique<cStarvationCallbacks>(), 1600u
|
||||||
new cStarvationCallbacks()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -8,6 +8,17 @@
|
|||||||
#include "BlockEntities/BlockEntity.h"
|
#include "BlockEntities/BlockEntity.h"
|
||||||
#include "Entities/Entity.h"
|
#include "Entities/Entity.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct sMemCallbacks:
|
||||||
|
cAllocationPool<cChunkData::sChunkSection>::cStarvationCallbacks
|
||||||
|
{
|
||||||
|
virtual void OnStartUsingReserve() override {}
|
||||||
|
virtual void OnEndUsingReserve() override {}
|
||||||
|
virtual void OnOutOfReserve() override {}
|
||||||
|
};
|
||||||
|
} // namespace (anonymous)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -15,6 +26,8 @@
|
|||||||
cSetChunkData::cSetChunkData(int a_ChunkX, int a_ChunkZ, bool a_ShouldMarkDirty) :
|
cSetChunkData::cSetChunkData(int a_ChunkX, int a_ChunkZ, bool a_ShouldMarkDirty) :
|
||||||
m_ChunkX(a_ChunkX),
|
m_ChunkX(a_ChunkX),
|
||||||
m_ChunkZ(a_ChunkZ),
|
m_ChunkZ(a_ChunkZ),
|
||||||
|
m_Pool(cpp14::make_unique<sMemCallbacks>(), cChunkData::NumSections),
|
||||||
|
m_ChunkData(m_Pool),
|
||||||
m_IsLightValid(false),
|
m_IsLightValid(false),
|
||||||
m_IsHeightMapValid(false),
|
m_IsHeightMapValid(false),
|
||||||
m_AreBiomesValid(false),
|
m_AreBiomesValid(false),
|
||||||
@ -38,29 +51,23 @@ cSetChunkData::cSetChunkData(
|
|||||||
cBlockEntities && a_BlockEntities,
|
cBlockEntities && a_BlockEntities,
|
||||||
bool a_ShouldMarkDirty
|
bool a_ShouldMarkDirty
|
||||||
) :
|
) :
|
||||||
m_ChunkX(a_ChunkX),
|
cSetChunkData(a_ChunkX, a_ChunkZ, a_ShouldMarkDirty)
|
||||||
m_ChunkZ(a_ChunkZ),
|
|
||||||
m_ShouldMarkDirty(a_ShouldMarkDirty)
|
|
||||||
{
|
{
|
||||||
// Check the params' validity:
|
// Check the params' validity:
|
||||||
ASSERT(a_BlockTypes != nullptr);
|
ASSERT(a_BlockTypes != nullptr);
|
||||||
ASSERT(a_BlockMetas != nullptr);
|
ASSERT(a_BlockMetas != nullptr);
|
||||||
|
|
||||||
// Copy block types and metas:
|
// Copy block types and metas:
|
||||||
memcpy(m_BlockTypes, a_BlockTypes, sizeof(cChunkDef::BlockTypes));
|
m_ChunkData.SetBlockTypes(a_BlockTypes);
|
||||||
memcpy(m_BlockMetas, a_BlockMetas, sizeof(cChunkDef::BlockNibbles));
|
m_ChunkData.SetMetas(a_BlockMetas);
|
||||||
|
|
||||||
// Copy lights, if both given:
|
// Copy lights, if both given:
|
||||||
if ((a_BlockLight != nullptr) && (a_SkyLight != nullptr))
|
if ((a_BlockLight != nullptr) && (a_SkyLight != nullptr))
|
||||||
{
|
{
|
||||||
memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight));
|
m_ChunkData.SetBlockLight(a_BlockLight);
|
||||||
memcpy(m_SkyLight, a_SkyLight, sizeof(m_SkyLight));
|
m_ChunkData.SetSkyLight(a_SkyLight);
|
||||||
m_IsLightValid = true;
|
m_IsLightValid = true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
m_IsLightValid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the heightmap, if available:
|
// Copy the heightmap, if available:
|
||||||
if (a_HeightMap != nullptr)
|
if (a_HeightMap != nullptr)
|
||||||
@ -68,10 +75,6 @@ cSetChunkData::cSetChunkData(
|
|||||||
memcpy(m_HeightMap, a_HeightMap, sizeof(m_HeightMap));
|
memcpy(m_HeightMap, a_HeightMap, sizeof(m_HeightMap));
|
||||||
m_IsHeightMapValid = true;
|
m_IsHeightMapValid = true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
m_IsHeightMapValid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy biomes, if available:
|
// Copy biomes, if available:
|
||||||
if (a_Biomes != nullptr)
|
if (a_Biomes != nullptr)
|
||||||
@ -79,10 +82,6 @@ cSetChunkData::cSetChunkData(
|
|||||||
memcpy(m_Biomes, a_Biomes, sizeof(m_Biomes));
|
memcpy(m_Biomes, a_Biomes, sizeof(m_Biomes));
|
||||||
m_AreBiomesValid = true;
|
m_AreBiomesValid = true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
m_AreBiomesValid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move entities and blockentities:
|
// Move entities and blockentities:
|
||||||
m_Entities = std::move(a_Entities);
|
m_Entities = std::move(a_Entities);
|
||||||
@ -95,14 +94,25 @@ cSetChunkData::cSetChunkData(
|
|||||||
|
|
||||||
void cSetChunkData::CalculateHeightMap(void)
|
void cSetChunkData::CalculateHeightMap(void)
|
||||||
{
|
{
|
||||||
|
// Find the heighest present section in the chunk
|
||||||
|
size_t MaxSection = 0;
|
||||||
|
for (size_t i = cChunkData::NumSections - 1; i != 0; --i)
|
||||||
|
{
|
||||||
|
if (m_ChunkData.GetSection(i) != nullptr)
|
||||||
|
{
|
||||||
|
MaxSection = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const int MaxHeight = static_cast<int>(MaxSection + 1) * cChunkData::SectionHeight - 1;
|
||||||
|
|
||||||
for (int x = 0; x < cChunkDef::Width; x++)
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
{
|
{
|
||||||
for (int z = 0; z < cChunkDef::Width; z++)
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
{
|
{
|
||||||
for (int y = cChunkDef::Height - 1; y > -1; y--)
|
for (int y = MaxHeight; y > -1; y--)
|
||||||
{
|
{
|
||||||
int index = cChunkDef::MakeIndexNoCheck(x, y, z);
|
if (m_ChunkData.GetBlock({x, y, z}) != E_BLOCK_AIR)
|
||||||
if (m_BlockTypes[index] != E_BLOCK_AIR)
|
|
||||||
{
|
{
|
||||||
m_HeightMap[x + z * cChunkDef::Width] = static_cast<HEIGHTTYPE>(y);
|
m_HeightMap[x + z * cChunkDef::Width] = static_cast<HEIGHTTYPE>(y);
|
||||||
break;
|
break;
|
||||||
@ -124,7 +134,7 @@ void cSetChunkData::RemoveInvalidBlockEntities(void)
|
|||||||
{
|
{
|
||||||
cBlockEntity * BlockEntity = itr->second;
|
cBlockEntity * BlockEntity = itr->second;
|
||||||
BLOCKTYPE EntityBlockType = BlockEntity->GetBlockType();
|
BLOCKTYPE EntityBlockType = BlockEntity->GetBlockType();
|
||||||
BLOCKTYPE WorldBlockType = cChunkDef::GetBlock(m_BlockTypes, BlockEntity->GetRelX(), BlockEntity->GetPosY(), BlockEntity->GetRelZ());
|
BLOCKTYPE WorldBlockType = m_ChunkData.GetBlock({BlockEntity->GetRelX(), BlockEntity->GetPosY(), BlockEntity->GetRelZ()});
|
||||||
if (EntityBlockType != WorldBlockType)
|
if (EntityBlockType != WorldBlockType)
|
||||||
{
|
{
|
||||||
// Bad blocktype, remove the block entity:
|
// Bad blocktype, remove the block entity:
|
||||||
|
@ -3,12 +3,10 @@
|
|||||||
|
|
||||||
// Declares the cSetChunkData class used for sending loaded / generated chunk data into cWorld
|
// Declares the cSetChunkData class used for sending loaded / generated chunk data into cWorld
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "ChunkData.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -51,17 +49,8 @@ public:
|
|||||||
int GetChunkX(void) const { return m_ChunkX; }
|
int GetChunkX(void) const { return m_ChunkX; }
|
||||||
int GetChunkZ(void) const { return m_ChunkZ; }
|
int GetChunkZ(void) const { return m_ChunkZ; }
|
||||||
|
|
||||||
/** Returns the internal storage of the block types, read-only. */
|
/** Returns the internal storage of block types, metas and lighting. */
|
||||||
const cChunkDef::BlockTypes & GetBlockTypes(void) const { return m_BlockTypes; }
|
cChunkData & GetChunkData(void) { return m_ChunkData; }
|
||||||
|
|
||||||
/** Returns the internal storage of the block types, read-only. */
|
|
||||||
const cChunkDef::BlockNibbles & GetBlockMetas(void) const { return m_BlockMetas; }
|
|
||||||
|
|
||||||
/** Returns the internal storage of the block light, read-only. */
|
|
||||||
const cChunkDef::BlockNibbles & GetBlockLight(void) const { return m_BlockLight; }
|
|
||||||
|
|
||||||
/** Returns the internal storage of the block types, read-only. */
|
|
||||||
const cChunkDef::BlockNibbles & GetSkyLight(void) const { return m_SkyLight; }
|
|
||||||
|
|
||||||
/** Returns the internal storage for heightmap, read-only. */
|
/** Returns the internal storage for heightmap, read-only. */
|
||||||
const cChunkDef::HeightMap & GetHeightMap(void) const { return m_HeightMap; }
|
const cChunkDef::HeightMap & GetHeightMap(void) const { return m_HeightMap; }
|
||||||
@ -101,10 +90,8 @@ protected:
|
|||||||
int m_ChunkX;
|
int m_ChunkX;
|
||||||
int m_ChunkZ;
|
int m_ChunkZ;
|
||||||
|
|
||||||
cChunkDef::BlockTypes m_BlockTypes;
|
cListAllocationPool<cChunkData::sChunkSection> m_Pool;
|
||||||
cChunkDef::BlockNibbles m_BlockMetas;
|
cChunkData m_ChunkData;
|
||||||
cChunkDef::BlockNibbles m_BlockLight;
|
|
||||||
cChunkDef::BlockNibbles m_SkyLight;
|
|
||||||
cChunkDef::HeightMap m_HeightMap;
|
cChunkDef::HeightMap m_HeightMap;
|
||||||
cChunkDef::BiomeMap m_Biomes;
|
cChunkDef::BiomeMap m_Biomes;
|
||||||
cEntityList m_Entities;
|
cEntityList m_Entities;
|
||||||
|
@ -11,15 +11,20 @@ int main(int argc, char** argv)
|
|||||||
class cMockAllocationPool
|
class cMockAllocationPool
|
||||||
: public cAllocationPool<cChunkData::sChunkSection>
|
: public cAllocationPool<cChunkData::sChunkSection>
|
||||||
{
|
{
|
||||||
virtual cChunkData::sChunkSection * Allocate()
|
virtual cChunkData::sChunkSection * Allocate() override
|
||||||
{
|
{
|
||||||
return new cChunkData::sChunkSection();
|
return new cChunkData::sChunkSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Free(cChunkData::sChunkSection * a_Ptr)
|
virtual void Free(cChunkData::sChunkSection * a_Ptr) override
|
||||||
{
|
{
|
||||||
delete a_Ptr;
|
delete a_Ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool DoIsEqual(const cAllocationPool<cChunkData::sChunkSection> &) const NOEXCEPT override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} Pool;
|
} Pool;
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -11,15 +11,20 @@ int main(int argc, char** argv)
|
|||||||
class cMockAllocationPool
|
class cMockAllocationPool
|
||||||
: public cAllocationPool<cChunkData::sChunkSection>
|
: public cAllocationPool<cChunkData::sChunkSection>
|
||||||
{
|
{
|
||||||
virtual cChunkData::sChunkSection * Allocate()
|
virtual cChunkData::sChunkSection * Allocate() override
|
||||||
{
|
{
|
||||||
return new cChunkData::sChunkSection();
|
return new cChunkData::sChunkSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Free(cChunkData::sChunkSection * a_Ptr)
|
virtual void Free(cChunkData::sChunkSection * a_Ptr) override
|
||||||
{
|
{
|
||||||
delete a_Ptr;
|
delete a_Ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool DoIsEqual(const cAllocationPool<cChunkData::sChunkSection> &) const NOEXCEPT override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} Pool;
|
} Pool;
|
||||||
{
|
{
|
||||||
cChunkData buffer(Pool);
|
cChunkData buffer(Pool);
|
||||||
|
@ -11,15 +11,20 @@ int main(int argc, char** argv)
|
|||||||
class cMockAllocationPool
|
class cMockAllocationPool
|
||||||
: public cAllocationPool<cChunkData::sChunkSection>
|
: public cAllocationPool<cChunkData::sChunkSection>
|
||||||
{
|
{
|
||||||
virtual cChunkData::sChunkSection * Allocate()
|
virtual cChunkData::sChunkSection * Allocate() override
|
||||||
{
|
{
|
||||||
return new cChunkData::sChunkSection();
|
return new cChunkData::sChunkSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Free(cChunkData::sChunkSection * a_Ptr)
|
virtual void Free(cChunkData::sChunkSection * a_Ptr) override
|
||||||
{
|
{
|
||||||
delete a_Ptr;
|
delete a_Ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool DoIsEqual(const cAllocationPool<cChunkData::sChunkSection>&) const NOEXCEPT override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} Pool;
|
} Pool;
|
||||||
{
|
{
|
||||||
cChunkData buffer(Pool);
|
cChunkData buffer(Pool);
|
||||||
|
@ -22,15 +22,20 @@ int main(int argc, char ** argv)
|
|||||||
class cMockAllocationPool
|
class cMockAllocationPool
|
||||||
: public cAllocationPool<cChunkData::sChunkSection>
|
: public cAllocationPool<cChunkData::sChunkSection>
|
||||||
{
|
{
|
||||||
virtual cChunkData::sChunkSection * Allocate()
|
virtual cChunkData::sChunkSection * Allocate() override
|
||||||
{
|
{
|
||||||
return new cChunkData::sChunkSection();
|
return new cChunkData::sChunkSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Free(cChunkData::sChunkSection * a_Ptr)
|
virtual void Free(cChunkData::sChunkSection * a_Ptr) override
|
||||||
{
|
{
|
||||||
delete a_Ptr;
|
delete a_Ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool DoIsEqual(const cAllocationPool<cChunkData::sChunkSection> &) const NOEXCEPT override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} Pool;
|
} Pool;
|
||||||
cChunkData Data(Pool);
|
cChunkData Data(Pool);
|
||||||
cChunkDef::BlockTypes BlockTypes;
|
cChunkDef::BlockTypes BlockTypes;
|
||||||
|
@ -9,15 +9,20 @@ int main(int argc, char** argv)
|
|||||||
class cMockAllocationPool
|
class cMockAllocationPool
|
||||||
: public cAllocationPool<cChunkData::sChunkSection>
|
: public cAllocationPool<cChunkData::sChunkSection>
|
||||||
{
|
{
|
||||||
virtual cChunkData::sChunkSection * Allocate()
|
virtual cChunkData::sChunkSection * Allocate() override
|
||||||
{
|
{
|
||||||
return new cChunkData::sChunkSection();
|
return new cChunkData::sChunkSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Free(cChunkData::sChunkSection * a_Ptr)
|
virtual void Free(cChunkData::sChunkSection * a_Ptr) override
|
||||||
{
|
{
|
||||||
delete a_Ptr;
|
delete a_Ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool DoIsEqual(const cAllocationPool<cChunkData::sChunkSection> &) const NOEXCEPT override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} Pool;
|
} Pool;
|
||||||
cChunkData buffer(Pool);
|
cChunkData buffer(Pool);
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user