diff --git a/src/Bindings/LuaWindow.cpp b/src/Bindings/LuaWindow.cpp index a81021475..eb4187887 100644 --- a/src/Bindings/LuaWindow.cpp +++ b/src/Bindings/LuaWindow.cpp @@ -196,11 +196,7 @@ void cLuaWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Pl void cLuaWindow::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) { - if (a_ItemGrid != &m_Contents) - { - ASSERT(!"Invalid ItemGrid in callback"); - return; - } + ASSERT(a_ItemGrid == &m_Contents); // If an OnSlotChanged callback has been registered, call it: if (m_OnSlotChanged != nullptr) diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp index 4b17f10a6..7c0660431 100644 --- a/src/BlockEntities/BlockEntity.cpp +++ b/src/BlockEntities/BlockEntity.cpp @@ -168,6 +168,15 @@ bool cBlockEntity::IsBlockEntityBlockType(const BLOCKTYPE a_BlockType) +void cBlockEntity::OnAddToWorld(cWorld & a_World, cChunk & a_Chunk) +{ + m_World = &a_World; +} + + + + + void cBlockEntity::OnRemoveFromWorld() { } diff --git a/src/BlockEntities/BlockEntity.h b/src/BlockEntities/BlockEntity.h index 3e9cf38e7..e13600e8c 100644 --- a/src/BlockEntities/BlockEntity.h +++ b/src/BlockEntities/BlockEntity.h @@ -51,12 +51,19 @@ public: Returns nullptr for unknown block types. */ static OwnedBlockEntity CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World = nullptr); + /** Called when this block entity's associated block is destroyed. + It is guaranteed that this function is called before OnRemoveFromWorld. */ virtual void Destroy(); /** Returns true if the specified blocktype is supposed to have an associated block entity. */ static bool IsBlockEntityBlockType(BLOCKTYPE a_BlockType); - /** Called when the block entity is removed from a world. */ + /** Called when the block entity object is added to a world. */ + virtual void OnAddToWorld(cWorld & a_World, cChunk & a_Chunk); + + /** Called when the block entity object is removed from a world. + This occurs when the chunk it resides in is unloaded, or when the associated block is destroyed. + If it is the latter, Destroy() is guaranteed to be called first. */ virtual void OnRemoveFromWorld(); /** Sends the packet defining the block entity to the client specified. diff --git a/src/BlockEntities/ChestEntity.cpp b/src/BlockEntities/ChestEntity.cpp index 3c80a7aa3..c2c31b30a 100644 --- a/src/BlockEntities/ChestEntity.cpp +++ b/src/BlockEntities/ChestEntity.cpp @@ -2,6 +2,7 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "ChestEntity.h" +#include "../Chunk.h" #include "../BlockInfo.h" #include "../Item.h" #include "../Entities/Player.h" @@ -18,125 +19,59 @@ cChestEntity::cChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector m_NumActivePlayers(0), m_Neighbour(nullptr) { - auto chunkCoord = cChunkDef::BlockToChunk(a_Pos); - if ( - (m_World != nullptr) && - m_World->IsChunkValid(chunkCoord.m_ChunkX, chunkCoord.m_ChunkZ) - ) - { - ScanNeighbours(); - } } -void cChestEntity::CopyFrom(const cBlockEntity & a_Src) +cChestEntity & cChestEntity::GetPrimaryChest() { - Super::CopyFrom(a_Src); - auto & src = static_cast(a_Src); - m_Contents.CopyFrom(src.m_Contents); - - // Reset the neighbor and player count, there's no sense in copying these: - m_Neighbour = nullptr; - m_NumActivePlayers = 0; -} - - - - - -void cChestEntity::OnRemoveFromWorld() -{ - if (m_Neighbour != nullptr) - { - // Neighbour may share a window with us, force the window shut: - m_Neighbour->DestroyWindow(); - m_Neighbour->m_Neighbour = nullptr; - } - - DestroyWindow(); -} - - - - - -void cChestEntity::SendTo(cClientHandle & a_Client) -{ - // Send a dummy "number of players with chest open" packet to make the chest visible: - a_Client.SendBlockAction(m_Pos.x, m_Pos.y, m_Pos.z, 1, 0, m_BlockType); -} - - - - - -bool cChestEntity::UsedBy(cPlayer * a_Player) -{ - if (IsBlocked()) - { - // Obstruction, don't open - return true; - } - if (m_Neighbour == nullptr) { - ScanNeighbours(); + return *this; } // The primary chest should be the one with lesser X or Z coord: - cChestEntity * PrimaryChest = this; - if (m_Neighbour != nullptr) - { - if (m_Neighbour->IsBlocked()) - { - // Obstruction, don't open - return true; - } + return ( + (m_Neighbour->GetPosX() < GetPosX()) || + (m_Neighbour->GetPosZ() < GetPosZ()) + ) ? *m_Neighbour : *this; +} - if ( - (m_Neighbour->GetPosX() > GetPosX()) || - (m_Neighbour->GetPosZ() > GetPosZ()) - ) - { - PrimaryChest = m_Neighbour; - } + + + + +cChestEntity * cChestEntity::GetSecondaryChest() +{ + // If we're the primary, then our neighbour is the secondary, and vice versa: + return (&GetPrimaryChest() == this) ? m_Neighbour : this; +} + + + + + +bool cChestEntity::ScanNeighbour(cChunk & a_Chunk, Vector3i a_Position) +{ + const auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(a_Position); + + if ((Chunk == nullptr) || !Chunk->IsValid()) + { + // If a chest was in fact there, they'll find us when their chunk loads. + return false; } - if (m_BlockType == E_BLOCK_CHEST) + const auto BlockEntity = Chunk->GetBlockEntityRel(a_Position); + + if ((BlockEntity == nullptr) || (BlockEntity->GetBlockType() != m_BlockType)) { - a_Player->GetStatManager().AddValue(Statistic::OpenChest); - } - else // E_BLOCK_TRAPPED_CHEST - { - a_Player->GetStatManager().AddValue(Statistic::TriggerTrappedChest); + // Neighbouring block is not the same type of chest: + return false; } - // If the window is not created, open it anew: - cWindow * Window = PrimaryChest->GetWindow(); - if (Window == nullptr) - { - PrimaryChest->OpenNewWindow(); - Window = PrimaryChest->GetWindow(); - } - - // Open the window for the player: - if (Window != nullptr) - { - if (a_Player->GetWindow() != Window) - { - a_Player->OpenWindow(*Window); - } - } - - // This is rather a hack - // Instead of marking the chunk as dirty upon chest contents change, we mark it dirty now - // We cannot properly detect contents change, but such a change doesn't happen without a player opening the chest first. - // The few false positives aren't much to worry about - auto chunkCoords = cChunkDef::BlockToChunk(m_Pos); - m_World->MarkChunkDirty(chunkCoords.m_ChunkX, chunkCoords.m_ChunkZ); + m_Neighbour = static_cast(BlockEntity); return true; } @@ -144,69 +79,6 @@ bool cChestEntity::UsedBy(cPlayer * a_Player) -cChestEntity * cChestEntity::GetNeighbour() -{ - return m_Neighbour; -} - - - - - -void cChestEntity::ScanNeighbours() -{ - // Callback for finding neighbouring chest. - auto FindNeighbour = [this](cBlockEntity & a_BlockEntity) - { - if (a_BlockEntity.GetBlockType() != m_BlockType) - { - // Neighboring block is not the same type of chest - return false; - } - - m_Neighbour = static_cast(&a_BlockEntity); - return true; - }; - - // Scan horizontally adjacent blocks for any neighbouring chest of the same type: - if ( - m_World->DoWithBlockEntityAt(m_Pos.addedX(-1), FindNeighbour) || - m_World->DoWithBlockEntityAt(m_Pos.addedX(+1), FindNeighbour) || - m_World->DoWithBlockEntityAt(m_Pos.addedZ(-1), FindNeighbour) || - m_World->DoWithBlockEntityAt(m_Pos.addedX(+1), FindNeighbour) - ) - { - m_Neighbour->m_Neighbour = this; - // Force neighbour's window shut. Does Mojang server do this or should a double window open? - m_Neighbour->DestroyWindow(); - } -} - - - - - -void cChestEntity::OpenNewWindow(void) -{ - if (m_Neighbour != nullptr) - { - ASSERT( // This should be the primary chest - (m_Neighbour->GetPosX() < GetPosX()) || - (m_Neighbour->GetPosZ() < GetPosZ()) - ); - OpenWindow(new cChestWindow(this, m_Neighbour)); - } - else - { - // There is no chest neighbour, open a single-chest window: - OpenWindow(new cChestWindow(this)); - } -} - - - - - void cChestEntity::DestroyWindow() { const auto Window = GetWindow(); @@ -235,15 +107,140 @@ bool cChestEntity::IsBlocked() +void cChestEntity::OpenNewWindow(void) +{ + if (m_Neighbour != nullptr) + { + ASSERT(&GetPrimaryChest() == this); // Should only open windows for the primary chest. + + OpenWindow(new cChestWindow(this, m_Neighbour)); + } + else + { + // There is no chest neighbour, open a single-chest window: + OpenWindow(new cChestWindow(this)); + } +} + + + + + +void cChestEntity::CopyFrom(const cBlockEntity & a_Src) +{ + Super::CopyFrom(a_Src); + auto & src = static_cast(a_Src); + m_Contents.CopyFrom(src.m_Contents); + + // Reset the neighbor and player count, there's no sense in copying these: + m_Neighbour = nullptr; + m_NumActivePlayers = 0; +} + + + + + +void cChestEntity::OnAddToWorld(cWorld & a_World, cChunk & a_Chunk) +{ + Super::OnAddToWorld(a_World, a_Chunk); + + // Scan horizontally adjacent blocks for any neighbouring chest of the same type: + if ( + const auto Position = GetRelPos(); + + ScanNeighbour(a_Chunk, Position.addedX(-1)) || + ScanNeighbour(a_Chunk, Position.addedX(+1)) || + ScanNeighbour(a_Chunk, Position.addedZ(-1)) || + ScanNeighbour(a_Chunk, Position.addedZ(+1)) + ) + { + m_Neighbour->m_Neighbour = this; + m_Neighbour->DestroyWindow(); // Force neighbour's window shut. Does Mojang server do this or should a double window open? + } +} + + + + + +void cChestEntity::OnRemoveFromWorld() +{ + if (m_Neighbour != nullptr) + { + // Neighbour may share a window with us, force the window shut: + m_Neighbour->DestroyWindow(); + m_Neighbour->m_Neighbour = nullptr; + } + + DestroyWindow(); +} + + + + + +void cChestEntity::SendTo(cClientHandle & a_Client) +{ + a_Client.SendUpdateBlockEntity(*this); +} + + + + + +bool cChestEntity::UsedBy(cPlayer * a_Player) +{ + if (IsBlocked()) + { + // Obstruction, don't open + return true; + } + + if ((m_Neighbour != nullptr) && m_Neighbour->IsBlocked()) + { + return true; + } + + if (m_BlockType == E_BLOCK_CHEST) + { + a_Player->GetStatManager().AddValue(Statistic::OpenChest); + } + else // E_BLOCK_TRAPPED_CHEST + { + a_Player->GetStatManager().AddValue(Statistic::TriggerTrappedChest); + } + + auto & PrimaryChest = GetPrimaryChest(); + cWindow * Window = PrimaryChest.GetWindow(); + + // If the window is not created, open it anew: + if (Window == nullptr) + { + PrimaryChest.OpenNewWindow(); + Window = PrimaryChest.GetWindow(); + } + + // Open the window for the player: + if (Window != nullptr) + { + if (a_Player->GetWindow() != Window) + { + a_Player->OpenWindow(*Window); + } + } + + return true; +} + + + + + void cChestEntity::OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) { ASSERT(a_Grid == &m_Contents); - if (m_World == nullptr) - { - return; - } - // Have cBlockEntityWithItems update redstone and try to broadcast our window: Super::OnSlotChanged(a_Grid, a_SlotNum); @@ -259,9 +256,4 @@ void cChestEntity::OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) { Window->BroadcastWholeWindow(); } - - m_World->MarkChunkDirty(GetChunkX(), GetChunkZ()); - - // Notify comparators: - m_World->WakeUpSimulators(m_Pos); } diff --git a/src/BlockEntities/ChestEntity.h b/src/BlockEntities/ChestEntity.h index 02b182481..ee3c59b8b 100644 --- a/src/BlockEntities/ChestEntity.h +++ b/src/BlockEntities/ChestEntity.h @@ -34,33 +34,21 @@ public: // tolua_end - /** Constructor used for normal operation */ cChestEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World); - // cBlockEntity overrides: - virtual void CopyFrom(const cBlockEntity & a_Src) override; - virtual void OnRemoveFromWorld() override; - virtual void SendTo(cClientHandle & a_Client) override; - virtual bool UsedBy(cPlayer * a_Player) override; - - /** Search horizontally adjacent blocks for neighbouring chests of the same type and links them together. */ - void ScanNeighbours(); - - /** Returns the value of m_Neighbour. */ - cChestEntity * GetNeighbour(); - - /** Opens a new chest window where this is the primary chest and any neighbour is the secondary. */ - void OpenNewWindow(); - - /** Forces any players to close the owned window. */ - void DestroyWindow(); - - /** Returns true if the chest should not be accessible by players. */ - bool IsBlocked(); - /** Gets the number of players who currently have this chest open */ int GetNumberOfPlayers(void) const { return m_NumActivePlayers; } + /** Returns the associated primary chest. */ + cChestEntity & GetPrimaryChest(); + + /** Returns the associated secondary chest, if any. */ + cChestEntity * GetSecondaryChest(); + + /** Search the given horizontally adjacent relative position for a neighbouring chest of the same type. + If found, links them together with ourselves and returns true. */ + bool ScanNeighbour(cChunk & a_Chunk, Vector3i a_Position); + /** Sets the number of players who currently have this chest open */ void SetNumberOfPlayers(int a_NumActivePlayers) { m_NumActivePlayers = a_NumActivePlayers; } @@ -72,6 +60,22 @@ private: /** Neighbouring chest that links to form a double chest */ cChestEntity * m_Neighbour; + /** Forces any players to close the owned window. */ + void DestroyWindow(); + + /** Returns true if the chest should not be accessible by players. */ + bool IsBlocked(); + + /** Opens a new chest window where this is the primary chest and any neighbour is the secondary. */ + void OpenNewWindow(); + + // cBlockEntity overrides: + virtual void CopyFrom(const cBlockEntity & a_Src) override; + virtual void OnAddToWorld(cWorld & a_World, cChunk & a_Chunk) override; + virtual void OnRemoveFromWorld() override; + virtual void SendTo(cClientHandle & a_Client) override; + virtual bool UsedBy(cPlayer * a_Player) override; + /** cItemGrid::cListener overrides: */ virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) override; } ; // tolua_export diff --git a/src/BlockEntities/HopperEntity.cpp b/src/BlockEntities/HopperEntity.cpp index 5b273b13c..82e07f6a0 100644 --- a/src/BlockEntities/HopperEntity.cpp +++ b/src/BlockEntities/HopperEntity.cpp @@ -132,12 +132,6 @@ bool cHopperEntity::UsedBy(cPlayer * a_Player) } } - // This is rather a hack - // Instead of marking the chunk as dirty upon chest contents change, we mark it dirty now - // We cannot properly detect contents change, but such a change doesn't happen without a player opening the chest first. - // The few false positives aren't much to worry about - cChunkCoords ChunkPos = cChunkDef::BlockToChunk(GetPos()); - m_World->MarkChunkDirty(ChunkPos.m_ChunkX, ChunkPos.m_ChunkZ); return true; } @@ -172,15 +166,15 @@ bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, const cTickTimeLong a_CurrentT bool res = false; switch (a_Chunk.GetBlock(GetRelPos().addedY(1))) { - case E_BLOCK_TRAPPED_CHEST: case E_BLOCK_CHEST: + case E_BLOCK_TRAPPED_CHEST: { // Chests have special handling because of double-chests res = MoveItemsFromChest(a_Chunk); break; } - case E_BLOCK_LIT_FURNACE: case E_BLOCK_FURNACE: + case E_BLOCK_LIT_FURNACE: { // Furnaces have special handling because only the output and leftover fuel buckets shall be moved res = MoveItemsFromFurnace(a_Chunk); @@ -331,15 +325,15 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, const cTickTimeLong a_Current auto absCoord = destChunk->RelativeToAbsolute(relCoord); switch (destChunk->GetBlock(relCoord)) { - case E_BLOCK_TRAPPED_CHEST: case E_BLOCK_CHEST: + case E_BLOCK_TRAPPED_CHEST: { // Chests have special handling because of double-chests res = MoveItemsToChest(*destChunk, absCoord); break; } - case E_BLOCK_LIT_FURNACE: case E_BLOCK_FURNACE: + case E_BLOCK_LIT_FURNACE: { // Furnaces have special handling because of the direction-to-slot relation res = MoveItemsToFurnace(*destChunk, absCoord, meta); @@ -375,52 +369,22 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, const cTickTimeLong a_Current bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk) { - auto ChestPos = GetPos().addedY(1); - auto MainChest = static_cast(a_Chunk.GetBlockEntity(ChestPos)); - if (MainChest == nullptr) + const auto ConnectedBlockEntity = a_Chunk.GetBlockEntityRel(GetRelPos().addedY(1)); + + if (ConnectedBlockEntity == nullptr) { - FLOGWARNING("{0}: A chest entity was not found where expected, at {1}", __FUNCTION__, ChestPos); return false; } - auto SideChest = MainChest->GetNeighbour(); - if (SideChest == nullptr) + + const auto ConnectedChest = static_cast(ConnectedBlockEntity); + + if (MoveItemsFromGrid(ConnectedChest->GetPrimaryChest())) { - if (MoveItemsFromGrid(*MainChest)) - { - return true; - } + return true; } - else - { - auto SideAbsCoords = SideChest->GetPos(); - // the "primary" chest is the one with the higher z or x value - if (SideAbsCoords.z > ChestPos.z || SideAbsCoords.x > ChestPos.x) - { - // side is "primary" so pull from it first - if (MoveItemsFromGrid(*SideChest)) - { - return true; - } - // main is secondary, pull from next - if (MoveItemsFromGrid(*MainChest)) - { - return true; - } - } - else - { - if (MoveItemsFromGrid(*MainChest)) - { - return true; - } - if (MoveItemsFromGrid(*SideChest)) - { - return true; - } - } - } - // The chest was empty - return false; + + const auto SecondaryChest = ConnectedChest->GetSecondaryChest(); + return (SecondaryChest != nullptr) && MoveItemsFromGrid(*SecondaryChest); } @@ -529,48 +493,22 @@ bool cHopperEntity::MoveItemsFromSlot(cBlockEntityWithItems & a_Entity, int a_Sl bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, Vector3i a_Coords) { - // Try the chest directly connected to the hopper: - auto ConnectedChest = static_cast(a_Chunk.GetBlockEntity(a_Coords)); - if (ConnectedChest == nullptr) + const auto ConnectedBlockEntity = a_Chunk.GetBlockEntity(a_Coords); + + if (ConnectedBlockEntity == nullptr) { - FLOGWARNING("{0}: A chest entity was not found where expected, at {1}", __FUNCTION__, a_Coords); return false; } - auto SideChest = ConnectedChest->GetNeighbour(); - if (SideChest == nullptr) + + const auto ConnectedChest = static_cast(ConnectedBlockEntity); + + if (MoveItemsToGrid(ConnectedChest->GetPrimaryChest())) { - if (MoveItemsToGrid(*ConnectedChest)) - { - return true; - } + return true; } - else - { - auto SideAbsCoords = SideChest->GetPos(); - if (SideAbsCoords.z > a_Coords.z || SideAbsCoords.x > a_Coords.x) - { - if (MoveItemsToGrid(*SideChest)) - { - return true; - } - if (MoveItemsToGrid(*ConnectedChest)) - { - return true; - } - } - else - { - if (MoveItemsToGrid(*ConnectedChest)) - { - return true; - } - if (MoveItemsToGrid(*SideChest)) - { - return true; - } - } - } - return false; + + const auto SecondaryChest = ConnectedChest->GetSecondaryChest(); + return (SecondaryChest != nullptr) && MoveItemsToGrid(*SecondaryChest); } @@ -661,7 +599,3 @@ bool cHopperEntity::MoveItemsToSlot(cBlockEntityWithItems & a_Entity, int a_DstS return false; } } - - - - diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp index 68f45b518..ef4359416 100644 --- a/src/Blocks/BlockBed.cpp +++ b/src/Blocks/BlockBed.cpp @@ -163,6 +163,7 @@ void cBlockBedHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWor a_Player.GetWorld()->DoWithBlockEntityAt(a_BlockChange.GetAbsolutePos(), [&a_Player](cBlockEntity & a_BlockEntity) { ASSERT(a_BlockEntity.GetBlockType() == E_BLOCK_BED); + static_cast(a_BlockEntity).SetColor(a_Player.GetEquippedItem().m_ItemDamage); return false; }); diff --git a/src/Blocks/BlockEnchantingTable.h b/src/Blocks/BlockEnchantingTable.h index 188f9c9b3..ba3932e5c 100644 --- a/src/Blocks/BlockEnchantingTable.h +++ b/src/Blocks/BlockEnchantingTable.h @@ -34,10 +34,7 @@ private: AString WindowName = "Enchant"; a_WorldInterface.DoWithBlockEntityAt(a_BlockPos, [&WindowName](cBlockEntity & a_Entity) { - if (a_Entity.GetBlockType() != E_BLOCK_ENCHANTMENT_TABLE) - { - return false; - } + ASSERT(a_Entity.GetBlockType() == E_BLOCK_ENCHANTMENT_TABLE); const auto & EnchantingTable = static_cast(a_Entity); const auto & CustomName = EnchantingTable.GetCustomName(); diff --git a/src/Blocks/BlockNoteBlock.h b/src/Blocks/BlockNoteBlock.h index 566b9bef5..f5ada0d2d 100644 --- a/src/Blocks/BlockNoteBlock.h +++ b/src/Blocks/BlockNoteBlock.h @@ -28,10 +28,7 @@ private: { a_WorldInterface.DoWithBlockEntityAt(a_BlockPos, [](cBlockEntity & a_BlockEntity) { - if (a_BlockEntity.GetBlockType() != E_BLOCK_NOTE_BLOCK) - { - return false; - } + ASSERT(a_BlockEntity.GetBlockType() == E_BLOCK_NOTE_BLOCK); static_cast(a_BlockEntity).MakeSound(); return false; diff --git a/src/Chunk.cpp b/src/Chunk.cpp index aa1544c7d..efdce7edc 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -336,13 +336,16 @@ void cChunk::GetAllData(cChunkDataCallback & a_Callback) const void cChunk::SetAllData(SetChunkData && a_SetChunkData) { - std::copy(a_SetChunkData.HeightMap, a_SetChunkData.HeightMap + std::size(a_SetChunkData.HeightMap), m_HeightMap); - std::copy(a_SetChunkData.BiomeMap, a_SetChunkData.BiomeMap + std::size(a_SetChunkData.BiomeMap), m_BiomeMap); + std::copy_n(a_SetChunkData.HeightMap, std::size(a_SetChunkData.HeightMap), m_HeightMap); + std::copy_n(a_SetChunkData.BiomeMap, std::size(a_SetChunkData.BiomeMap), m_BiomeMap); m_BlockData = std::move(a_SetChunkData.BlockData); m_LightData = std::move(a_SetChunkData.LightData); m_IsLightValid = a_SetChunkData.IsLightValid; + m_PendingSendBlocks.clear(); + m_PendingSendBlockEntities.clear(); + // Entities need some extra steps to destroy, so here we're keeping the old ones. // Move the entities already in the chunk, including player entities, so that we don't lose any: a_SetChunkData.Entities.insert( @@ -383,15 +386,17 @@ void cChunk::SetAllData(SetChunkData && a_SetChunkData) } #endif - // Set all block entities' World variable: + // Set the chunk data as valid. + // This may be needed for some simulators that perform actions upon block adding (Vaporize), + // as well as some block entities upon being added to the chunk (Chests). + SetPresence(cpPresent); + + // Initialise all block entities: for (auto & KeyPair : m_BlockEntities) { - KeyPair.second->SetWorld(m_World); + KeyPair.second->OnAddToWorld(*m_World, *this); } - // Set the chunk data as valid. This may be needed for some simulators that perform actions upon block adding (Vaporize) - SetPresence(cpPresent); - // Wake up all simulators for their respective blocks: WakeUpSimulators(); } @@ -466,22 +471,34 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock } // for y // Erase all affected block entities: - cCuboid affectedArea( // In world coordinates - {BlockStartX, a_MinBlockY, BlockStartZ}, - {BlockEndX, a_MinBlockY + SizeY - 1, BlockEndZ} - ); - for (auto itr = m_BlockEntities.begin(); itr != m_BlockEntities.end();) { - if (affectedArea.IsInside(itr->second->GetPos())) + // The affected area, in world coordinates. + cCuboid affectedArea( + { BlockStartX, a_MinBlockY, BlockStartZ }, + { BlockEndX, a_MinBlockY + SizeY - 1, BlockEndZ } + ); + + // Where in the pending block entity send list to start removing the invalidated elements from. + auto PendingRemove = m_PendingSendBlockEntities.end(); + + for (auto itr = m_BlockEntities.begin(); itr != m_BlockEntities.end();) { - itr->second->Destroy(); - itr->second->OnRemoveFromWorld(); - itr = m_BlockEntities.erase(itr); - } - else - { - ++itr; + if (affectedArea.IsInside(itr->second->GetPos())) + { + itr->second->Destroy(); + itr->second->OnRemoveFromWorld(); + + PendingRemove = std::remove(m_PendingSendBlockEntities.begin(), PendingRemove, itr->second.get()); // Search the remaining valid pending sends. + itr = m_BlockEntities.erase(itr); + } + else + { + ++itr; + } } + + // Remove all the deleted block entities from the pending send list: + m_PendingSendBlockEntities.erase(PendingRemove, m_PendingSendBlockEntities.end()); } // Clone block entities from a_Area into this chunk: @@ -500,16 +517,13 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock { continue; } - // This block entity is inside the chunk, clone it (and remove any that is there currently): - auto idx = static_cast(cChunkDef::MakeIndex(posX - m_PosX * cChunkDef::Width, posY, posZ - m_PosZ * cChunkDef::Width)); - auto itr = m_BlockEntities.find(idx); - if (itr != m_BlockEntities.end()) - { - m_BlockEntities.erase(itr); - } - auto clone = be->Clone({posX, posY, posZ}); - clone->SetWorld(m_World); - AddBlockEntity(std::move(clone)); + + // This block entity is inside the chunk. + // The code above should have removed any that were here before: + ASSERT(GetBlockEntityRel(cChunkDef::AbsoluteToRelative({ posX, posY, posZ })) == nullptr); + + // Clone, and add the new one: + AddBlockEntity(be->Clone({posX, posY, posZ})); } } } @@ -518,15 +532,6 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock -bool cChunk::HasBlockEntityAt(Vector3i a_BlockPos) -{ - return (GetBlockEntity(a_BlockPos) != nullptr); -} - - - - - void cChunk::Stay(bool a_Stay) { if (a_Stay) @@ -1287,12 +1292,15 @@ void cChunk::SetBlock(Vector3i a_RelPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_Blo GetWorld()->GetSimulatorManager()->WakeUp(*this, a_RelPos); // If there was a block entity, remove it: - cBlockEntity * BlockEntity = GetBlockEntityRel(a_RelPos); - if (BlockEntity != nullptr) + if (const auto FindResult = m_BlockEntities.find(cChunkDef::MakeIndex(a_RelPos)); FindResult != m_BlockEntities.end()) { - BlockEntity->Destroy(); - BlockEntity->OnRemoveFromWorld(); - RemoveBlockEntity(BlockEntity); + auto & BlockEntity = *FindResult->second; + + BlockEntity.Destroy(); + BlockEntity.OnRemoveFromWorld(); + + m_BlockEntities.erase(FindResult); + m_PendingSendBlockEntities.erase(std::remove(m_PendingSendBlockEntities.begin(), m_PendingSendBlockEntities.end(), &BlockEntity), m_PendingSendBlockEntities.end()); } // If the new block is a block entity, create the entity object: @@ -1414,11 +1422,14 @@ void cChunk::SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_C void cChunk::AddBlockEntity(OwnedBlockEntity a_BlockEntity) { + const auto BlockEntityPtr = a_BlockEntity.get(); [[maybe_unused]] const auto Result = m_BlockEntities.emplace( cChunkDef::MakeIndex(a_BlockEntity->GetRelX(), a_BlockEntity->GetPosY(), a_BlockEntity->GetRelZ()), std::move(a_BlockEntity) ); - ASSERT(Result.second); // No block entity already at this position + + ASSERT(Result.second); // No block entity already at this position. + BlockEntityPtr->OnAddToWorld(*m_World, *this); } @@ -1435,7 +1446,7 @@ cBlockEntity * cChunk::GetBlockEntity(Vector3i a_AbsPos) return nullptr; } - auto itr = m_BlockEntities.find(static_cast(cChunkDef::MakeIndexNoCheck(relPos))); + auto itr = m_BlockEntities.find(cChunkDef::MakeIndex(relPos)); return (itr == m_BlockEntities.end()) ? nullptr : itr->second.get(); } @@ -1446,7 +1457,7 @@ cBlockEntity * cChunk::GetBlockEntity(Vector3i a_AbsPos) cBlockEntity * cChunk::GetBlockEntityRel(Vector3i a_RelPos) { ASSERT(cChunkDef::IsValidRelPos(a_RelPos)); - auto itr = m_BlockEntities.find(static_cast(cChunkDef::MakeIndexNoCheck(a_RelPos))); + auto itr = m_BlockEntities.find(cChunkDef::MakeIndex(a_RelPos)); return (itr == m_BlockEntities.end()) ? nullptr : itr->second.get(); } @@ -1527,18 +1538,6 @@ void cChunk::SetAreaBiome(int a_MinRelX, int a_MaxRelX, int a_MinRelZ, int a_Max -void cChunk::RemoveBlockEntity(cBlockEntity * a_BlockEntity) -{ - MarkDirty(); - ASSERT(a_BlockEntity != nullptr); - m_BlockEntities.erase(static_cast(cChunkDef::MakeIndex(a_BlockEntity->GetRelX(), a_BlockEntity->GetPosY(), a_BlockEntity->GetRelZ()))); - m_PendingSendBlockEntities.erase(std::remove(m_PendingSendBlockEntities.begin(), m_PendingSendBlockEntities.end(), a_BlockEntity), m_PendingSendBlockEntities.end()); -} - - - - - bool cChunk::AddClient(cClientHandle * a_Client) { if (std::find(m_LoadedByClient.begin(), m_LoadedByClient.end(), a_Client) != m_LoadedByClient.end()) diff --git a/src/Chunk.h b/src/Chunk.h index 9178c6f1b..92e46cf5c 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -114,9 +114,6 @@ public: /** Writes the specified cBlockArea at the coords specified. Note that the coords may extend beyond the chunk! */ 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(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 before the chunk is unloadable again. */ @@ -493,7 +490,7 @@ private: /** Block entities that have been touched and need to be sent to all clients. Because block changes are buffered and we need to happen after them, this buffer exists too. - Pointers to block entities that were destroyed are guaranteed to be removed from this array by RemoveBlockEntity. */ + Pointers to block entities that were destroyed are guaranteed to be removed from this array by SetAllData, SetBlock, WriteBlockArea. */ std::vector m_PendingSendBlockEntities; /** A queue of relative positions to call cBlockHandler::Check on. @@ -543,8 +540,8 @@ private: void GetRandomBlockCoords(int & a_X, int & a_Y, int & a_Z); void GetThreeRandomNumbers(int & a_X, int & a_Y, int & a_Z, int a_MaxX, int a_MaxY, int a_MaxZ); - void RemoveBlockEntity(cBlockEntity * a_BlockEntity); - void AddBlockEntity (OwnedBlockEntity a_BlockEntity); + /** Takes ownership of a block entity, which MUST actually reside in this chunk. */ + void AddBlockEntity(OwnedBlockEntity a_BlockEntity); /** Wakes up each simulator for its specific blocks; through all the blocks in the chunk */ void WakeUpSimulators(void); diff --git a/src/ChunkData.cpp b/src/ChunkData.cpp index a820f043b..318c0c481 100644 --- a/src/ChunkData.cpp +++ b/src/ChunkData.cpp @@ -26,7 +26,7 @@ namespace return { static_cast(a_RelPos.y / cChunkDef::SectionHeight), - static_cast(cChunkDef::MakeIndexNoCheck(a_RelPos.x, a_RelPos.y % cChunkDef::SectionHeight, a_RelPos.z)) + cChunkDef::MakeIndex(a_RelPos.x, a_RelPos.y % cChunkDef::SectionHeight, a_RelPos.z) }; } diff --git a/src/ChunkDef.h b/src/ChunkDef.h index 673ae347a..12036cdbe 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -207,36 +207,22 @@ public: } - inline static int MakeIndex(int x, int y, int z) + inline static size_t MakeIndex(int x, int y, int z) { - if ( - (x < Width) && (x > -1) && - (y < Height) && (y > -1) && - (z < Width) && (z > -1) - ) - { - return MakeIndexNoCheck(x, y, z); - } - FLOGERROR("cChunkDef::MakeIndex(): coords out of range: {0}; returning fake index 0", Vector3i{x, y, z}); - ASSERT(!"cChunkDef::MakeIndex(): coords out of chunk range!"); - return 0; - } + ASSERT(IsValidRelPos({ x, y, z })); - - inline static int MakeIndexNoCheck(int x, int y, int z) - { #if AXIS_ORDER == AXIS_ORDER_XZY // For some reason, NOT using the Horner schema is faster. Weird. - return x + (z * cChunkDef::Width) + (y * cChunkDef::Width * cChunkDef::Width); // 1.2 uses XZY + return static_cast(x + (z * Width) + (y * Width * Width)); // 1.2 uses XZY #elif AXIS_ORDER == AXIS_ORDER_YZX - return y + (z * cChunkDef::Width) + (x * cChunkDef::Height * cChunkDef::Width); // 1.1 uses YZX + return static_cast(y + (z * Width) + (x * Height * Width)); // 1.1 uses YZX #endif } - inline static int MakeIndexNoCheck(Vector3i a_RelPos) + inline static size_t MakeIndex(Vector3i a_RelPos) { - return MakeIndexNoCheck(a_RelPos.x, a_RelPos.y, a_RelPos.z); + return MakeIndex(a_RelPos.x, a_RelPos.y, a_RelPos.z); } @@ -263,7 +249,7 @@ public: ASSERT((a_X >= 0) && (a_X < Width)); ASSERT((a_Y >= 0) && (a_Y < Height)); ASSERT((a_Z >= 0) && (a_Z < Width)); - a_BlockTypes[MakeIndexNoCheck(a_X, a_Y, a_Z)] = a_Type; + a_BlockTypes[MakeIndex(a_X, a_Y, a_Z)] = a_Type; } @@ -277,7 +263,7 @@ public: inline static BLOCKTYPE GetBlock(const BLOCKTYPE * a_BlockTypes, Vector3i a_RelPos) { ASSERT(IsValidRelPos(a_RelPos)); - return a_BlockTypes[MakeIndexNoCheck(a_RelPos)]; + return a_BlockTypes[MakeIndex(a_RelPos)]; } @@ -286,7 +272,7 @@ public: ASSERT((a_X >= 0) && (a_X < Width)); ASSERT((a_Y >= 0) && (a_Y < Height)); ASSERT((a_Z >= 0) && (a_Z < Width)); - return a_BlockTypes[MakeIndexNoCheck(a_X, a_Y, a_Z)]; + return a_BlockTypes[MakeIndex(a_X, a_Y, a_Z)]; } @@ -333,8 +319,7 @@ public: { if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1)) { - int Index = MakeIndexNoCheck(x, y, z); - return ExpandNibble(a_Buffer, static_cast(Index)); + return ExpandNibble(a_Buffer, MakeIndex(x, y, z)); } ASSERT(!"cChunkDef::GetNibble(): coords out of chunk range!"); return 0; @@ -436,7 +421,6 @@ struct sSetBlock } }; -typedef std::list sSetBlockList; typedef std::vector sSetBlockVector; typedef std::list cChunkCoordsList; @@ -461,27 +445,6 @@ public: -class cChunkCoordsWithBool -{ -public: - int m_ChunkX; - int m_ChunkZ; - bool m_ForceGenerate; - - cChunkCoordsWithBool(int a_ChunkX, int a_ChunkZ, bool a_ForceGenerate) : m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ), m_ForceGenerate(a_ForceGenerate){} - - bool operator == (const cChunkCoordsWithBool & a_Other) const - { - return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkZ == a_Other.m_ChunkZ) && (m_ForceGenerate == a_Other.m_ForceGenerate)); - } -}; - -typedef std::list cChunkCoordsWithBoolList; - - - - - /** Interface class used as a callback for operations that involve chunk coords */ class cChunkCoordCallback { @@ -518,7 +481,6 @@ public: } ; typedef cCoordWithData cCoordWithInt; -typedef cCoordWithData cCoordWithBlock; typedef std::list cCoordWithIntList; typedef std::vector cCoordWithIntVector; diff --git a/src/Generating/Caves.cpp b/src/Generating/Caves.cpp index 5da6b4833..fcad9032c 100644 --- a/src/Generating/Caves.cpp +++ b/src/Generating/Caves.cpp @@ -513,7 +513,7 @@ void cCaveTunnel::ProcessChunk( { if (cChunkDef::GetBlock(a_BlockTypes, x, y, z) == E_BLOCK_SAND) { - int Index = cChunkDef::MakeIndexNoCheck(x, y, z); + const auto Index = cChunkDef::MakeIndex(x, y, z); if (a_BlockMetas[Index] == 1) { a_BlockMetas[Index] = 0; diff --git a/src/Generating/ChunkDesc.cpp b/src/Generating/ChunkDesc.cpp index b4b8e8868..b2a332489 100644 --- a/src/Generating/ChunkDesc.cpp +++ b/src/Generating/ChunkDesc.cpp @@ -572,8 +572,8 @@ void cChunkDesc::RandomFillRelCuboid( cBlockEntity * cChunkDesc::GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ) { - auto Idx = static_cast(cChunkDef::MakeIndex(a_RelX, a_RelY, a_RelZ)); - auto itr = m_BlockEntities.find(Idx); + const auto Idx = cChunkDef::MakeIndex(a_RelX, a_RelY, a_RelZ); + const auto itr = m_BlockEntities.find(Idx); if (itr != m_BlockEntities.end()) { diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index ef4af91c5..a6da93976 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -1227,7 +1227,7 @@ void cFinishGenBottomLava::GenFinish(cChunkDesc & a_ChunkDesc) { for (int z = 0; z < cChunkDef::Width; z++) for (int x = 0; x < cChunkDef::Width; x++) { - int Index = cChunkDef::MakeIndexNoCheck(x, y, z); + const auto Index = cChunkDef::MakeIndex(x, y, z); if (BlockTypes[Index] == E_BLOCK_AIR) { BlockTypes[Index] = E_BLOCK_STATIONARY_LAVA; @@ -2000,8 +2000,8 @@ void cFinishGenOreNests::GenerateOre( continue; } - int Index = cChunkDef::MakeIndexNoCheck(BlockX, BlockY, BlockZ); - auto blockType = blockTypes[Index]; + const auto Index = cChunkDef::MakeIndex(BlockX, BlockY, BlockZ); + const auto blockType = blockTypes[Index]; if ((blockType == E_BLOCK_STONE) || (blockType == E_BLOCK_NETHERRACK)) { blockTypes[Index] = a_OreType; diff --git a/src/Items/ItemMobHead.h b/src/Items/ItemMobHead.h index f1e963e1f..07c628ceb 100644 --- a/src/Items/ItemMobHead.h +++ b/src/Items/ItemMobHead.h @@ -244,10 +244,7 @@ public: (BlockType == E_BLOCK_HEAD) && !a_World.DoWithBlockEntityAt({ BlockX, BlockY, BlockZ }, [&](cBlockEntity & a_BlockEntity) { - if (a_BlockEntity.GetBlockType() != E_BLOCK_HEAD) - { - return false; - } + ASSERT(a_BlockEntity.GetBlockType() == E_BLOCK_HEAD); return static_cast(a_BlockEntity).GetType() == SKULL_TYPE_WITHER; }) diff --git a/src/Mobs/PathFinder.cpp b/src/Mobs/PathFinder.cpp index 5356cedfe..bcc48d80e 100644 --- a/src/Mobs/PathFinder.cpp +++ b/src/Mobs/PathFinder.cpp @@ -192,7 +192,7 @@ bool cPathFinder::EnsureProperPoint(Vector3d & a_Vector, cChunk & a_Chunk) // This fixes the player leaning issue. // If that failed, we instead go down to the lowest air block. int YBelowUs = FloorC(a_Vector.y) - 1; - if (YBelowUs < 0) + if (!cChunkDef::IsValidHeight(YBelowUs)) { return false; diff --git a/src/Protocol/Protocol_1_11.cpp b/src/Protocol/Protocol_1_11.cpp index 1bce409f4..30935574b 100644 --- a/src/Protocol/Protocol_1_11.cpp +++ b/src/Protocol/Protocol_1_11.cpp @@ -463,8 +463,16 @@ void cProtocol_1_11_0::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) Byte Action; switch (a_BlockEntity.GetBlockType()) { - case E_BLOCK_ENCHANTMENT_TABLE: Action = 0; break; // The ones with a action of 0 is just a workaround to send the block entities to a client. - case E_BLOCK_END_PORTAL: Action = 0; break; // Todo: 18.09.2020 - remove this when block entities are transmitted in the ChunkData packet - 12xx12 + case E_BLOCK_CHEST: + case E_BLOCK_ENCHANTMENT_TABLE: + case E_BLOCK_END_PORTAL: + case E_BLOCK_TRAPPED_CHEST: + { + // The ones with a action of 0 is just a workaround to send the block entities to a client. + // Todo: 18.09.2020 - remove this when block entities are transmitted in the ChunkData packet - 12xx12 + Action = 0; + break; + } case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text diff --git a/src/Protocol/Protocol_1_13.cpp b/src/Protocol/Protocol_1_13.cpp index 0f9dfe544..44a011c76 100644 --- a/src/Protocol/Protocol_1_13.cpp +++ b/src/Protocol/Protocol_1_13.cpp @@ -205,8 +205,16 @@ void cProtocol_1_13::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) Byte Action; switch (a_BlockEntity.GetBlockType()) { - case E_BLOCK_ENCHANTMENT_TABLE: Action = 0; break; // The ones with a action of 0 is just a workaround to send the block entities to a client. - case E_BLOCK_END_PORTAL: Action = 0; break; // Todo: 18.09.2020 - remove this when block entities are transmitted in the ChunkData packet - 12xx12 + case E_BLOCK_CHEST: + case E_BLOCK_ENCHANTMENT_TABLE: + case E_BLOCK_END_PORTAL: + case E_BLOCK_TRAPPED_CHEST: + { + // The ones with a action of 0 is just a workaround to send the block entities to a client. + // Todo: 18.09.2020 - remove this when block entities are transmitted in the ChunkData packet - 12xx12 + Action = 0; + break; + } case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text @@ -464,6 +472,7 @@ UInt32 cProtocol_1_13::GetPacketID(ePacketType a_PacketType) const case pktUpdateScore: return 0x48; case pktUpdateSign: return GetPacketID(pktUpdateBlockEntity); case pktUseBed: return 0x33; + case pktWeather: return 0x20; case pktWindowClose: return 0x13; case pktWindowItems: return 0x15; case pktWindowOpen: return 0x14; diff --git a/src/Protocol/Protocol_1_13.h b/src/Protocol/Protocol_1_13.h index 4992c5a1f..b478fe5ed 100644 --- a/src/Protocol/Protocol_1_13.h +++ b/src/Protocol/Protocol_1_13.h @@ -45,9 +45,6 @@ protected: virtual void SendStatistics (const cStatManager & a_Manager) override; virtual void SendTabCompletionResults (const AStringVector & a_Results) override; virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override; - - virtual void SendWeather (eWeather a_Weather) override {} // This packet was removed. This keeps players from joining the server with 1.13 while there is downfall - virtual UInt8 GetEntityMetadataID(EntityMetadata a_Metadata) const; virtual UInt8 GetEntityMetadataID(EntityMetadataType a_FieldType) const; virtual std::pair GetItemFromProtocolID(UInt32 a_ProtocolID) const; diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp index 4d15d8978..78483a45d 100644 --- a/src/Protocol/Protocol_1_8.cpp +++ b/src/Protocol/Protocol_1_8.cpp @@ -1582,8 +1582,16 @@ void cProtocol_1_8_0::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) Byte Action; switch (a_BlockEntity.GetBlockType()) { - case E_BLOCK_ENCHANTMENT_TABLE: Action = 0; break; // The ones with a action of 0 is just a workaround to send the block entities to a client. - case E_BLOCK_END_PORTAL: Action = 0; break; // Todo: 18.09.2020 - remove this when block entities are transmitted in the ChunkData packet - 12xx12 + case E_BLOCK_CHEST: + case E_BLOCK_ENCHANTMENT_TABLE: + case E_BLOCK_END_PORTAL: + case E_BLOCK_TRAPPED_CHEST: + { + // The ones with a action of 0 is just a workaround to send the block entities to a client. + // Todo: 18.09.2020 - remove this when block entities are transmitted in the ChunkData packet - 12xx12 + Action = 0; + break; + } case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text diff --git a/src/Simulator/DelayedFluidSimulator.cpp b/src/Simulator/DelayedFluidSimulator.cpp index b231f5fef..59f76a7f8 100644 --- a/src/Simulator/DelayedFluidSimulator.cpp +++ b/src/Simulator/DelayedFluidSimulator.cpp @@ -22,11 +22,11 @@ bool cDelayedFluidSimulatorChunkData::cSlot::Add(int a_RelX, int a_RelY, int a_R ASSERT(a_RelZ >= 0); ASSERT(a_RelZ < static_cast(ARRAYCOUNT(m_Blocks))); - cCoordWithIntVector & Blocks = m_Blocks[a_RelZ]; - int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); - for (cCoordWithIntVector::const_iterator itr = Blocks.begin(), end = Blocks.end(); itr != end; ++itr) + auto & Blocks = m_Blocks[a_RelZ]; + const auto Index = cChunkDef::MakeIndex(a_RelX, a_RelY, a_RelZ); + for (const auto & Block : Blocks) { - if (itr->Data == Index) + if (Block.Data == Index) { // Already present return false; @@ -101,14 +101,14 @@ void cDelayedFluidSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a // Simulate all the blocks in the scheduled slot: for (size_t i = 0; i < ARRAYCOUNT(Slot.m_Blocks); i++) { - cCoordWithIntVector & Blocks = Slot.m_Blocks[i]; + auto & Blocks = Slot.m_Blocks[i]; if (Blocks.empty()) { continue; } - for (cCoordWithIntVector::iterator itr = Blocks.begin(), end = Blocks.end(); itr != end; ++itr) + for (const auto & Block : Blocks) { - SimulateBlock(a_Chunk, itr->x, itr->y, itr->z); + SimulateBlock(a_Chunk, Block.x, Block.y, Block.z); } m_TotalBlocks -= static_cast(Blocks.size()); Blocks.clear(); diff --git a/src/Simulator/DelayedFluidSimulator.h b/src/Simulator/DelayedFluidSimulator.h index 1a9f42a65..826489849 100644 --- a/src/Simulator/DelayedFluidSimulator.h +++ b/src/Simulator/DelayedFluidSimulator.h @@ -29,9 +29,9 @@ public: bool Add(int a_RelX, int a_RelY, int a_RelZ); /** Array of block containers, each item stores blocks for one Z coord - Int param is the block index (for faster duplicate comparison in Add()) + size_t param is the block index (for faster duplicate comparison in Add()) */ - cCoordWithIntVector m_Blocks[16]; + std::vector> m_Blocks[16]; } ; cDelayedFluidSimulatorChunkData(int a_TickDelay); diff --git a/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h b/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h index 0a5ffe136..50ea6dcb6 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h @@ -33,10 +33,7 @@ namespace CommandBlockHandler a_Chunk.DoWithBlockEntityAt(a_Position, [](cBlockEntity & a_BlockEntity) { - if (a_BlockEntity.GetBlockType() != E_BLOCK_COMMAND_BLOCK) - { - return false; - } + ASSERT(a_BlockEntity.GetBlockType() == E_BLOCK_COMMAND_BLOCK); static_cast(a_BlockEntity).Activate(); return false; diff --git a/src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h b/src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h index 4dd87e972..5f92c3868 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h @@ -48,10 +48,7 @@ namespace DropSpenserHandler { a_Chunk.DoWithBlockEntityAt(a_Position, [](cBlockEntity & a_BlockEntity) { - if ((a_BlockEntity.GetBlockType() != E_BLOCK_DISPENSER) && (a_BlockEntity.GetBlockType() != E_BLOCK_DROPPER)) - { - return false; - } + ASSERT((a_BlockEntity.GetBlockType() == E_BLOCK_DISPENSER) || (a_BlockEntity.GetBlockType() == E_BLOCK_DROPPER)); static_cast(a_BlockEntity).Activate(); return false; diff --git a/src/Simulator/IncrementalRedstoneSimulator/HopperHandler.h b/src/Simulator/IncrementalRedstoneSimulator/HopperHandler.h index ca820441c..95ef6ae62 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/HopperHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/HopperHandler.h @@ -43,10 +43,7 @@ namespace HopperHandler a_Chunk.DoWithBlockEntityAt(a_Position, [ShouldBeLocked](cBlockEntity & a_BlockEntity) { - if (a_BlockEntity.GetBlockType() != E_BLOCK_HOPPER) - { - return false; - } + ASSERT(a_BlockEntity.GetBlockType() == E_BLOCK_HOPPER); static_cast(a_BlockEntity).SetLocked(ShouldBeLocked); return false; diff --git a/src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h b/src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h index 8bd639357..fd96d8721 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h @@ -33,10 +33,7 @@ namespace NoteBlockHandler a_Chunk.DoWithBlockEntityAt(a_Position, [](cBlockEntity & a_BlockEntity) { - if (a_BlockEntity.GetBlockType() != E_BLOCK_NOTE_BLOCK) - { - return false; - } + ASSERT(a_BlockEntity.GetBlockType() == E_BLOCK_NOTE_BLOCK); static_cast(a_BlockEntity).MakeSound(); return false; diff --git a/src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h b/src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h index 145c5dc83..d68e48997 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h @@ -24,10 +24,7 @@ namespace TrappedChestHandler int NumberOfPlayers = 0; a_Chunk.DoWithBlockEntityAt(a_Position, [&NumberOfPlayers](cBlockEntity & a_BlockEntity) { - if (a_BlockEntity.GetBlockType() != E_BLOCK_TRAPPED_CHEST) - { - return false; - } + ASSERT(a_BlockEntity.GetBlockType() == E_BLOCK_TRAPPED_CHEST); NumberOfPlayers = static_cast(a_BlockEntity).GetNumberOfPlayers(); return false; diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 18c4f13b6..d901c061a 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -439,7 +439,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT { for (int x = 0; x < cChunkDef::Width; x++) for (int z = 0; z < cChunkDef::Width; z++) { - int Index = cChunkDef::MakeIndexNoCheck(x, y, z); + const auto Index = cChunkDef::MakeIndex(x, y, z); if (ShouldInvert[x + cChunkDef::Width * z]) { BlockTypes[Index] = (BlockTypes[Index] == E_BLOCK_AIR) ? E_BLOCK_STONE : E_BLOCK_AIR; @@ -618,10 +618,10 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntities & a_BlockEntities, const } // Index computed before Entity moved. - const auto Idx = cChunkDef::MakeIndexNoCheck(Entity->GetRelPos()); + const auto Index = cChunkDef::MakeIndex(Entity->GetRelPos()); // Add the BlockEntity to the loaded data: - a_BlockEntities.emplace(Idx, std::move(Entity)); + a_BlockEntities.emplace(Index, std::move(Entity)); } // for Child - tag children }