diff options
Diffstat (limited to 'src/BlockEntities/ChestEntity.cpp')
-rw-r--r-- | src/BlockEntities/ChestEntity.cpp | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/src/BlockEntities/ChestEntity.cpp b/src/BlockEntities/ChestEntity.cpp new file mode 100644 index 000000000..dfbe6ae87 --- /dev/null +++ b/src/BlockEntities/ChestEntity.cpp @@ -0,0 +1,172 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "ChestEntity.h" +#include "../Item.h" +#include "../Entities/Player.h" +#include "../UI/Window.h" +#include "json/json.h" + + + + + +cChestEntity::cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : + super(E_BLOCK_CHEST, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World) +{ + cBlockEntityWindowOwner::SetBlockEntity(this); +} + + + + + +cChestEntity::~cChestEntity() +{ + cWindow * Window = GetWindow(); + if (Window != NULL) + { + Window->OwnerDestroyed(); + } +} + + + + + +bool cChestEntity::LoadFromJson(const Json::Value & a_Value) +{ + m_PosX = a_Value.get("x", 0).asInt(); + m_PosY = a_Value.get("y", 0).asInt(); + m_PosZ = a_Value.get("z", 0).asInt(); + + Json::Value AllSlots = a_Value.get("Slots", 0); + int SlotIdx = 0; + for (Json::Value::iterator itr = AllSlots.begin(); itr != AllSlots.end(); ++itr) + { + cItem Item; + Item.FromJson(*itr); + SetSlot(SlotIdx, Item); + SlotIdx++; + } + return true; +} + + + + + +void cChestEntity::SaveToJson(Json::Value & a_Value) +{ + a_Value["x"] = m_PosX; + a_Value["y"] = m_PosY; + a_Value["z"] = m_PosZ; + + Json::Value AllSlots; + for (int i = m_Contents.GetNumSlots() - 1; i >= 0; i--) + { + Json::Value Slot; + m_Contents.GetSlot(i).GetJson(Slot); + AllSlots.append(Slot); + } + a_Value["Slots"] = AllSlots; +} + + + + + +void cChestEntity::SendTo(cClientHandle & a_Client) +{ + // The chest entity doesn't need anything sent to the client when it's created / gets in the viewdistance + // All the actual handling is in the cWindow UI code that gets called when the chest is rclked + + UNUSED(a_Client); +} + + + + + +void cChestEntity::UsedBy(cPlayer * a_Player) +{ + // If the window is not created, open it anew: + cWindow * Window = GetWindow(); + if (Window == NULL) + { + OpenNewWindow(); + Window = GetWindow(); + } + + // Open the window for the player: + if (Window != NULL) + { + 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 + int ChunkX, ChunkZ; + cChunkDef::BlockToChunk(m_PosX, m_PosZ, ChunkX, ChunkZ); + m_World->MarkChunkDirty(ChunkX, ChunkZ); +} + + + + + +void cChestEntity::OpenNewWindow(void) +{ + // Callback for opening together with neighbor chest: + class cOpenDouble : + public cChestCallback + { + cChestEntity * m_ThisChest; + public: + cOpenDouble(cChestEntity * a_ThisChest) : + m_ThisChest(a_ThisChest) + { + } + + virtual bool Item(cChestEntity * a_Chest) override + { + // The primary chest should eb the one with lesser X or Z coord: + cChestEntity * Primary = a_Chest; + cChestEntity * Secondary = m_ThisChest; + if ( + (Primary->GetPosX() > Secondary->GetPosX()) || + (Primary->GetPosZ() > Secondary->GetPosZ()) + ) + { + std::swap(Primary, Secondary); + } + m_ThisChest->OpenWindow(new cChestWindow(Primary, Secondary)); + return false; + } + } ; + + // Scan neighbors for adjacent chests: + cOpenDouble OpenDbl(this); + if ( + m_World->DoWithChestAt(m_PosX - 1, m_PosY, m_PosZ, OpenDbl) || + m_World->DoWithChestAt(m_PosX + 1, m_PosY, m_PosZ, OpenDbl) || + m_World->DoWithChestAt(m_PosX , m_PosY, m_PosZ - 1, OpenDbl) || + m_World->DoWithChestAt(m_PosX , m_PosY, m_PosZ + 1, OpenDbl) + ) + { + // The double-chest window has been opened in the callback + return; + } + + // There is no chest neighbor, open a single-chest window: + OpenWindow(new cChestWindow(this)); +} + + + + |