summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/AllocationPool.h39
-rw-r--r--src/Chunk.cpp159
-rw-r--r--src/Chunk.h2
-rw-r--r--src/ChunkData.cpp2
-rw-r--r--src/ChunkDataCallback.h4
-rw-r--r--src/ChunkDef.h14
-rw-r--r--src/ChunkMap.cpp6
-rw-r--r--src/SetChunkData.cpp56
-rw-r--r--src/SetChunkData.h25
9 files changed, 155 insertions, 152 deletions
diff --git a/src/AllocationPool.h b/src/AllocationPool.h
index 52a1b933b..1b27462ab 100644
--- a/src/AllocationPool.h
+++ b/src/AllocationPool.h
@@ -32,6 +32,25 @@ public:
/** Frees the pointer passed in a_ptr, invalidating it */
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
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:
public cAllocationPool<T>
{
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))
{
- for (size_t i = 0; i < NumElementsInReserve; i++)
+ for (size_t i = 0; i < m_NumElementsInReserve; i++)
{
void * space = malloc(sizeof(T));
if (space == nullptr)
@@ -74,7 +94,7 @@ public:
virtual T * Allocate() override
{
- if (m_FreeList.size() <= NumElementsInReserve)
+ if (m_FreeList.size() <= m_NumElementsInReserve)
{
void * space = malloc(sizeof(T));
if (space != nullptr)
@@ -93,7 +113,7 @@ public:
#pragma pop_macro("new")
#endif
}
- else if (m_FreeList.size() == NumElementsInReserve)
+ else if (m_FreeList.size() == m_NumElementsInReserve)
{
m_Callbacks->OnStartUsingReserve();
}
@@ -134,15 +154,22 @@ public:
// placement destruct.
a_ptr->~T();
m_FreeList.push_front(a_ptr);
- if (m_FreeList.size() == NumElementsInReserve)
+ if (m_FreeList.size() == m_NumElementsInReserve)
{
m_Callbacks->OnEndUsingReserve();
}
}
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::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);
+ }
};
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index f43b5b4bb..03415b348 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -322,26 +322,15 @@ void cChunk::SetAllData(cSetChunkData & a_SetChunkData)
memcpy(m_BiomeMap, a_SetChunkData.GetBiomes(), sizeof(m_BiomeMap));
memcpy(m_HeightMap, a_SetChunkData.GetHeightMap(), sizeof(m_HeightMap));
- m_ChunkData.SetBlockTypes(a_SetChunkData.GetBlockTypes());
- m_ChunkData.SetMetas(a_SetChunkData.GetBlockMetas());
- if (a_SetChunkData.IsLightValid())
- {
- m_ChunkData.SetBlockLight(a_SetChunkData.GetBlockLight());
- m_ChunkData.SetSkyLight(a_SetChunkData.GetSkyLight());
- m_IsLightValid = true;
- }
- else
- {
- m_IsLightValid = false;
- }
+ m_ChunkData.Assign(std::move(a_SetChunkData.GetChunkData()));
+ m_IsLightValid = a_SetChunkData.IsLightValid();
// Clear the block entities present - either the loader / saver has better, or we'll create empty ones:
for (auto & KeyPair : m_BlockEntities)
{
delete KeyPair.second;
}
- m_BlockEntities.clear();
- std::swap(a_SetChunkData.GetBlockEntities(), m_BlockEntities);
+ m_BlockEntities = std::move(a_SetChunkData.GetBlockEntities());
// Check that all block entities have a valid blocktype at their respective coords (DEBUG-mode only):
#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)
{
- 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)
+ {
+ auto BlockType = Section->m_BlockTypes[BlockIdx];
+ if (cBlockEntity::IsBlockEntityBlockType(BlockType))
{
- BLOCKTYPE BlockType = GetBlock(x, y, z);
- switch (BlockType)
+ auto RelPos = IndexToCoordinate(BlockIdx);
+ RelPos.y += SectionIdx * cChunkData::SectionHeight;
+ auto WorldPos = RelativeToAbsolute(RelPos, m_PosX, m_PosZ);
+
+ if (!HasBlockEntityAt(WorldPos))
{
- case E_BLOCK_BEACON:
- case E_BLOCK_BED:
- case E_BLOCK_TRAPPED_CHEST:
- case E_BLOCK_CHEST:
- case E_BLOCK_COMMAND_BLOCK:
- 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(
- BlockType, GetMeta(x, y, z),
- x + m_PosX * Width, y, z + m_PosZ * Width, m_World
- ));
- }
- break;
- }
- } // switch (BlockType)
- } // for y
- } // for z
- } // for x
+ AddBlockEntityClean(cBlockEntity::CreateByBlockType(
+ BlockType, GetMeta(RelPos), WorldPos.x, WorldPos.y, WorldPos.z, m_World
+ ));
+ }
+ }
+ }
+ }
}
@@ -1483,48 +1456,56 @@ void cChunk::CreateBlockEntities(void)
void cChunk::WakeUpSimulators(void)
{
- cSimulator * WaterSimulator = m_World->GetWaterSimulator();
- cSimulator * LavaSimulator = m_World->GetLavaSimulator();
- cSimulator * RedstoneSimulator = m_World->GetRedstoneSimulator();
- int BaseX = m_PosX * cChunkDef::Width;
- int BaseZ = m_PosZ * cChunkDef::Width;
- for (int x = 0; x < Width; x++)
+ auto * WaterSimulator = m_World->GetWaterSimulator();
+ auto * LavaSimulator = m_World->GetLavaSimulator();
+ auto * RedstoneSimulator = m_World->GetRedstoneSimulator();
+
+ for (size_t SectionIdx = 0; SectionIdx != cChunkData::NumSections; ++SectionIdx)
{
- int BlockX = x + BaseX;
- for (int z = 0; z < Width; z++)
+ const auto * Section = m_ChunkData.GetSection(SectionIdx);
+ if (Section == nullptr)
+ {
+ continue;
+ }
+
+ for (size_t BlockIdx = 0; BlockIdx != cChunkData::SectionBlockCount; ++BlockIdx)
{
- int BlockZ = z + BaseZ;
- for (int y = GetHeight(x, z); y >= 0; y--)
+ auto BlockType = Section->m_BlockTypes[BlockIdx];
+
+ // Defer calculation until it's actually needed
+ auto WorldPos = [&]
{
- BLOCKTYPE Block = GetBlock(x, y, z);
+ 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(Block))
+ // 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:
{
- RedstoneSimulator->AddBlock({BlockX, y, BlockZ}, this);
- continue;
+ WaterSimulator->AddBlock(WorldPos(), this);
+ break;
}
-
- switch (Block)
+ case E_BLOCK_LAVA:
{
- case E_BLOCK_WATER:
- {
- WaterSimulator->AddBlock({BlockX, y, BlockZ}, this);
- break;
- }
- case E_BLOCK_LAVA:
- {
- LavaSimulator->AddBlock({BlockX, y, BlockZ}, this);
- break;
- }
- default:
- {
- break;
- }
- } // switch (BlockType)
- } // for y
- } // for z
- } // for x
+ LavaSimulator->AddBlock(WorldPos(), this);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ } // switch (BlockType)
+ }
+ }
}
diff --git a/src/Chunk.h b/src/Chunk.h
index 18b3e9482..2ca8a751a 100644
--- a/src/Chunk.h
+++ b/src/Chunk.h
@@ -129,7 +129,7 @@ public:
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 */
- 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.
The flag is cumulative - it can be set multiple times and then needs to be un-set that many times
diff --git a/src/ChunkData.cpp b/src/ChunkData.cpp
index 70e06b032..f25f675dc 100644
--- a/src/ChunkData.cpp
+++ b/src/ChunkData.cpp
@@ -113,7 +113,7 @@ void cChunkData::Assign(cChunkData && a_Other)
return;
}
- if (&m_Pool != &a_Other.m_Pool)
+ if (m_Pool != a_Other.m_Pool)
{
// Cannot transfer the memory, do a copy instead
const cChunkData & CopyOther = a_Other;
diff --git a/src/ChunkDataCallback.h b/src/ChunkDataCallback.h
index 2bf554b74..ec8e1180f 100644
--- a/src/ChunkDataCallback.h
+++ b/src/ChunkDataCallback.h
@@ -115,13 +115,13 @@ public:
};
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)
{
}
- cListAllocationPool<cChunkData::sChunkSection, cChunkData::NumSections> m_Pool; // Keep 1 chunk worth of reserve
+ cListAllocationPool<cChunkData::sChunkSection> m_Pool;
cChunkData m_Data;
protected:
diff --git a/src/ChunkDef.h b/src/ChunkDef.h
index bdba4061f..3807ae1aa 100644
--- a/src/ChunkDef.h
+++ b/src/ChunkDef.h
@@ -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
return Vector3i( // 1.2
- index % cChunkDef::Width, // X
- index / (cChunkDef::Width * cChunkDef::Width), // Y
- (index / cChunkDef::Width) % cChunkDef::Width // Z
+ static_cast<int>(index % cChunkDef::Width), // X
+ static_cast<int>(index / (cChunkDef::Width * cChunkDef::Width)), // Y
+ static_cast<int>((index / cChunkDef::Width) % cChunkDef::Width) // Z
);
#elif AXIS_ORDER == AXIS_ORDER_YZX
return Vector3i( // 1.1
- index / (cChunkDef::Height * cChunkDef::Width), // X
- index % cChunkDef::Height, // Y
- (index / cChunkDef::Height) % cChunkDef::Width // Z
+ static_cast<int>(index / (cChunkDef::Height * cChunkDef::Width)), // X
+ static_cast<int>(index % cChunkDef::Height), // Y
+ static_cast<int>((index / cChunkDef::Height) % cChunkDef::Width) // Z
);
#endif
}
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index 770d34b5a..607fd0081 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -38,10 +38,8 @@
cChunkMap::cChunkMap(cWorld * a_World) :
m_World(a_World),
m_Pool(
- new cListAllocationPool<cChunkData::sChunkSection, 1600>(
- std::unique_ptr<cAllocationPool<cChunkData::sChunkSection>::cStarvationCallbacks>(
- new cStarvationCallbacks()
- )
+ cpp14::make_unique<cListAllocationPool<cChunkData::sChunkSection>>(
+ cpp14::make_unique<cStarvationCallbacks>(), 1600u
)
)
{
diff --git a/src/SetChunkData.cpp b/src/SetChunkData.cpp
index c218c361c..1fdc2e775 100644
--- a/src/SetChunkData.cpp
+++ b/src/SetChunkData.cpp
@@ -8,6 +8,17 @@
#include "BlockEntities/BlockEntity.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) :
m_ChunkX(a_ChunkX),
m_ChunkZ(a_ChunkZ),
+ m_Pool(cpp14::make_unique<sMemCallbacks>(), cChunkData::NumSections),
+ m_ChunkData(m_Pool),
m_IsLightValid(false),
m_IsHeightMapValid(false),
m_AreBiomesValid(false),
@@ -38,29 +51,23 @@ cSetChunkData::cSetChunkData(
cBlockEntities && a_BlockEntities,
bool a_ShouldMarkDirty
) :
- m_ChunkX(a_ChunkX),
- m_ChunkZ(a_ChunkZ),
- m_ShouldMarkDirty(a_ShouldMarkDirty)
+ cSetChunkData(a_ChunkX, a_ChunkZ, a_ShouldMarkDirty)
{
// Check the params' validity:
ASSERT(a_BlockTypes != nullptr);
ASSERT(a_BlockMetas != nullptr);
// Copy block types and metas:
- memcpy(m_BlockTypes, a_BlockTypes, sizeof(cChunkDef::BlockTypes));
- memcpy(m_BlockMetas, a_BlockMetas, sizeof(cChunkDef::BlockNibbles));
+ m_ChunkData.SetBlockTypes(a_BlockTypes);
+ m_ChunkData.SetMetas(a_BlockMetas);
// Copy lights, if both given:
if ((a_BlockLight != nullptr) && (a_SkyLight != nullptr))
{
- memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight));
- memcpy(m_SkyLight, a_SkyLight, sizeof(m_SkyLight));
+ m_ChunkData.SetBlockLight(a_BlockLight);
+ m_ChunkData.SetSkyLight(a_SkyLight);
m_IsLightValid = true;
}
- else
- {
- m_IsLightValid = false;
- }
// Copy the heightmap, if available:
if (a_HeightMap != nullptr)
@@ -68,10 +75,6 @@ cSetChunkData::cSetChunkData(
memcpy(m_HeightMap, a_HeightMap, sizeof(m_HeightMap));
m_IsHeightMapValid = true;
}
- else
- {
- m_IsHeightMapValid = false;
- }
// Copy biomes, if available:
if (a_Biomes != nullptr)
@@ -79,10 +82,6 @@ cSetChunkData::cSetChunkData(
memcpy(m_Biomes, a_Biomes, sizeof(m_Biomes));
m_AreBiomesValid = true;
}
- else
- {
- m_AreBiomesValid = false;
- }
// Move entities and blockentities:
m_Entities = std::move(a_Entities);
@@ -95,14 +94,25 @@ cSetChunkData::cSetChunkData(
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 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_BlockTypes[index] != E_BLOCK_AIR)
+ if (m_ChunkData.GetBlock({x, y, z}) != E_BLOCK_AIR)
{
m_HeightMap[x + z * cChunkDef::Width] = static_cast<HEIGHTTYPE>(y);
break;
@@ -124,7 +134,7 @@ void cSetChunkData::RemoveInvalidBlockEntities(void)
{
cBlockEntity * BlockEntity = itr->second;
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)
{
// Bad blocktype, remove the block entity:
diff --git a/src/SetChunkData.h b/src/SetChunkData.h
index c608a8f61..3e1dde35a 100644
--- a/src/SetChunkData.h
+++ b/src/SetChunkData.h
@@ -3,12 +3,10 @@
// Declares the cSetChunkData class used for sending loaded / generated chunk data into cWorld
-
-
-
-
#pragma once
+#include "ChunkData.h"
+
@@ -51,17 +49,8 @@ public:
int GetChunkX(void) const { return m_ChunkX; }
int GetChunkZ(void) const { return m_ChunkZ; }
- /** Returns the internal storage of the block types, read-only. */
- const cChunkDef::BlockTypes & GetBlockTypes(void) const { return m_BlockTypes; }
-
- /** 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 of block types, metas and lighting. */
+ cChunkData & GetChunkData(void) { return m_ChunkData; }
/** Returns the internal storage for heightmap, read-only. */
const cChunkDef::HeightMap & GetHeightMap(void) const { return m_HeightMap; }
@@ -101,10 +90,8 @@ protected:
int m_ChunkX;
int m_ChunkZ;
- cChunkDef::BlockTypes m_BlockTypes;
- cChunkDef::BlockNibbles m_BlockMetas;
- cChunkDef::BlockNibbles m_BlockLight;
- cChunkDef::BlockNibbles m_SkyLight;
+ cListAllocationPool<cChunkData::sChunkSection> m_Pool;
+ cChunkData m_ChunkData;
cChunkDef::HeightMap m_HeightMap;
cChunkDef::BiomeMap m_Biomes;
cEntityList m_Entities;