diff options
Diffstat (limited to '')
-rw-r--r-- | src/AllocationPool.h | 39 | ||||
-rw-r--r-- | src/Chunk.cpp | 159 | ||||
-rw-r--r-- | src/Chunk.h | 2 | ||||
-rw-r--r-- | src/ChunkData.cpp | 2 | ||||
-rw-r--r-- | src/ChunkDataCallback.h | 4 | ||||
-rw-r--r-- | src/ChunkDef.h | 14 | ||||
-rw-r--r-- | src/ChunkMap.cpp | 6 | ||||
-rw-r--r-- | src/SetChunkData.cpp | 56 | ||||
-rw-r--r-- | src/SetChunkData.h | 25 |
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; |