From 05d71675f69e13d8ab590a33b38ee6d0f8a77b6f Mon Sep 17 00:00:00 2001 From: "luksor111@gmail.com" Date: Wed, 19 Dec 2012 21:19:36 +0000 Subject: Added dispensers (they can't dispense items yet) Fixed crash when digging snow Moved BlockPlace hook check, so Core plugin will no longer block item usage Player chat messages are now visible in the console git-svn-id: http://mc-server.googlecode.com/svn/trunk@1081 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- VC2008/MCServer.vcproj | 8 ++ source/Blocks/BlockDispenser.h | 9 +- source/Blocks/BlockDoor.cpp | 17 +--- source/Blocks/BlockFenceGate.h | 3 +- source/Blocks/BlockSnow.h | 2 +- source/Chunk.cpp | 15 +++ source/Chunk.h | 10 +- source/ChunkMap.h | 8 +- source/ClientHandle.cpp | 36 ++++--- source/DispenserEntity.cpp | 192 +++++++++++++++++++++++++++++++++++++ source/DispenserEntity.h | 55 +++++++++++ source/UI/SlotArea.cpp | 48 ++++++++++ source/UI/SlotArea.h | 21 ++++ source/UI/Window.cpp | 15 +++ source/UI/Window.h | 12 +++ source/World.h | 10 +- source/WorldStorage/WSSAnvil.cpp | 86 +++++++++++++++-- source/WorldStorage/WSSAnvil.h | 11 ++- source/WorldStorage/WSSCompact.cpp | 34 +++++-- 19 files changed, 533 insertions(+), 59 deletions(-) create mode 100644 source/DispenserEntity.cpp create mode 100644 source/DispenserEntity.h diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj index de990c19b..0ec8a7cff 100644 --- a/VC2008/MCServer.vcproj +++ b/VC2008/MCServer.vcproj @@ -950,6 +950,14 @@ RelativePath="..\source\ChestEntity.h" > + + + + diff --git a/source/Blocks/BlockDispenser.h b/source/Blocks/BlockDispenser.h index 4a54fbde5..581e0f49b 100644 --- a/source/Blocks/BlockDispenser.h +++ b/source/Blocks/BlockDispenser.h @@ -1,10 +1,17 @@ + #pragma once + #include "BlockEntity.h" #include "../World.h" #include "../Piston.h" #include "../Player.h" -class cBlockDispenserHandler : public cBlockEntityHandler + + + + +class cBlockDispenserHandler : + public cBlockEntityHandler { public: cBlockDispenserHandler(BLOCKTYPE a_BlockType) diff --git a/source/Blocks/BlockDoor.cpp b/source/Blocks/BlockDoor.cpp index 1976e2f20..a2c352d7b 100644 --- a/source/Blocks/BlockDoor.cpp +++ b/source/Blocks/BlockDoor.cpp @@ -69,19 +69,10 @@ void cBlockDoorHandler::PlaceBlock(cWorld * a_World, cPlayer * a_Player, NIBBLET { a_BlockMeta = cDoors::RotationToMetaData(a_Player->GetRotation()); char a_TopBlockMeta = 8; - if((a_BlockMeta == 0) && (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1) == m_BlockType)) - { - a_TopBlockMeta = 9; - } - else if((a_BlockMeta == 1) && (a_World->GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ) == m_BlockType)) - { - a_TopBlockMeta = 9; - } - else if((a_BlockMeta == 2) && (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1) == m_BlockType)) - { - a_TopBlockMeta = 9; - } - else if((a_BlockMeta == 3) && (a_World->GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ) == m_BlockType)) + if( (a_BlockMeta == 0) && (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1) == m_BlockType) || + (a_BlockMeta == 1) && (a_World->GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ) == m_BlockType) || + (a_BlockMeta == 2) && (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1) == m_BlockType) || + (a_BlockMeta == 3) && (a_World->GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ) == m_BlockType)) { a_TopBlockMeta = 9; } diff --git a/source/Blocks/BlockFenceGate.h b/source/Blocks/BlockFenceGate.h index 072eb9c3a..0390bcc7d 100644 --- a/source/Blocks/BlockFenceGate.h +++ b/source/Blocks/BlockFenceGate.h @@ -34,7 +34,8 @@ public: char OldMetaData = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); char NewMetaData = cDoors::RotationToMetaData(a_Player->GetRotation() + 270); OldMetaData ^= 4; //Toggle the gate - if((OldMetaData & 1) == (NewMetaData & 1)){ + if((OldMetaData & 1) == (NewMetaData & 1)) + { //Standing in front of the gate - apply new direction a_World->SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, (OldMetaData & 4) | (NewMetaData & 3)); } diff --git a/source/Blocks/BlockSnow.h b/source/Blocks/BlockSnow.h index 7d29c67f2..2a5009b69 100644 --- a/source/Blocks/BlockSnow.h +++ b/source/Blocks/BlockSnow.h @@ -25,7 +25,7 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - a_Pickups.push_back(cItem(E_ITEM_SNOWBALL, 4, 0)); + a_Pickups.push_back(cItem(E_ITEM_SNOWBALL, 1, 0)); } diff --git a/source/Chunk.cpp b/source/Chunk.cpp index 5bfe28e41..5dc19915a 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -13,6 +13,7 @@ #include "zlib.h" #include "Defines.h" #include "ChestEntity.h" +#include "DispenserEntity.h" #include "FurnaceEntity.h" #include "SignEntity.h" #include "NoteEntity.h" @@ -982,6 +983,15 @@ void cChunk::CreateBlockEntities(void) } break; } + + case E_BLOCK_DISPENSER: + { + if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width)) + { + m_BlockEntities.push_back( new cDispenserEntity( x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width, m_World) ); + } + break; + } case E_BLOCK_FURNACE: { @@ -1128,6 +1138,11 @@ void cChunk::SetBlock( int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType AddBlockEntity( new cChestEntity( WorldPos.x, WorldPos.y, WorldPos.z, m_World) ); break; } + case E_BLOCK_DISPENSER: + { + AddBlockEntity( new cDispenserEntity( WorldPos.x, WorldPos.y, WorldPos.z, m_World) ); + break; + } case E_BLOCK_FURNACE: { AddBlockEntity( new cFurnaceEntity( WorldPos.x, WorldPos.y, WorldPos.z, m_World) ); diff --git a/source/Chunk.h b/source/Chunk.h index c285a26e3..fbf65b4fd 100644 --- a/source/Chunk.h +++ b/source/Chunk.h @@ -38,6 +38,7 @@ class MTRand; class cPlayer; class cChunkMap; class cChestEntity; +class cDispenserEntity; class cFurnaceEntity; class cBlockArea; class cPawn; @@ -45,10 +46,11 @@ class cPickup; class cChunkDataSerializer; class cBlockArea; -typedef std::list cClientHandleList; -typedef cItemCallback cEntityCallback; -typedef cItemCallback cChestCallback; -typedef cItemCallback cFurnaceCallback; +typedef std::list cClientHandleList; +typedef cItemCallback cEntityCallback; +typedef cItemCallback cChestCallback; +typedef cItemCallback cDispenserCallback; +typedef cItemCallback cFurnaceCallback; diff --git a/source/ChunkMap.h b/source/ChunkMap.h index 5dd4778ce..6a1a26d83 100644 --- a/source/ChunkMap.h +++ b/source/ChunkMap.h @@ -18,6 +18,7 @@ class cChunkStay; class cChunk; class cPlayer; class cChestEntity; +class cDispenserEntity; class cFurnaceEntity; class cPawn; class cPickup; @@ -26,9 +27,10 @@ class cBlockArea; typedef std::list cClientHandleList; typedef cChunk * cChunkPtr; -typedef cItemCallback cEntityCallback; -typedef cItemCallback cChestCallback; -typedef cItemCallback cFurnaceCallback; +typedef cItemCallback cEntityCallback; +typedef cItemCallback cChestCallback; +typedef cItemCallback cDispenserCallback; +typedef cItemCallback cFurnaceCallback; diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp index ba1c8db35..69e2496d3 100644 --- a/source/ClientHandle.cpp +++ b/source/ClientHandle.cpp @@ -578,11 +578,14 @@ void cClientHandle::HandleBlockDig(int a_BlockX, int a_BlockY, int a_BlockZ, cha if (bBroken) { - ItemHandler->OnBlockDestroyed(World, m_Player, &Equipped, a_BlockX, a_BlockY, a_BlockZ); - - BlockHandler(OldBlock)->OnDestroyedByPlayer(World, m_Player, a_BlockX, a_BlockY, a_BlockZ); - World->BroadcastSoundParticleEffect(2001, a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, OldBlock, this); - World->DigBlock(a_BlockX, a_BlockY, a_BlockZ); + if(World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_AIR) + { + ItemHandler->OnBlockDestroyed(World, m_Player, &Equipped, a_BlockX, a_BlockY, a_BlockZ); + + BlockHandler(OldBlock)->OnDestroyedByPlayer(World, m_Player, a_BlockX, a_BlockY, a_BlockZ); + World->BroadcastSoundParticleEffect(2001, a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, OldBlock, this); + World->DigBlock(a_BlockX, a_BlockY, a_BlockZ); + } } else { @@ -643,20 +646,12 @@ void cClientHandle::HandleBlockPlace(int a_BlockX, int a_BlockY, int a_BlockZ, c } return; } - - if (cRoot::Get()->GetPluginManager()->CallHookBlockPlace(m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, Equipped)) - { - if (a_BlockFace > -1) - { - AddDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); - m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); - } - return; - } cWorld * World = m_Player->GetWorld(); cBlockHandler *Handler = cBlockHandler::GetBlockHandler(World->GetBlock(a_BlockX, a_BlockY, a_BlockZ)); + + // TODO: Wrap following if into another if which will call hook 'OnBlockUse' (or some nicer name) if (Handler->IsUseable()) { Handler->OnUse(World, m_Player, a_BlockX, a_BlockY, a_BlockZ); @@ -742,6 +737,16 @@ void cClientHandle::HandleBlockPlace(int a_BlockX, int a_BlockY, int a_BlockZ, c } } } + + if (cRoot::Get()->GetPluginManager()->CallHookBlockPlace(m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, Equipped)) + { + if (a_BlockFace > -1) + { + AddDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); + m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); + } + return; + } } @@ -760,6 +765,7 @@ void cClientHandle::HandleChat(const AString & a_Message) a_Message.c_str() ); m_Player->GetWorld()->BroadcastChat(Msg); + LOG("<%s> %s", m_Player->GetName().c_str(), a_Message.c_str()); } } diff --git a/source/DispenserEntity.cpp b/source/DispenserEntity.cpp new file mode 100644 index 000000000..dc13f30b8 --- /dev/null +++ b/source/DispenserEntity.cpp @@ -0,0 +1,192 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "DispenserEntity.h" +#include "BlockID.h" +#include "Item.h" +#include "UI/Window.h" +#include "Player.h" +#include "World.h" +#include "ClientHandle.h" +#include "Server.h" +#include "Pickup.h" +#include "Root.h" +#include + + + + + +cDispenserEntity::cDispenserEntity(int a_X, int a_Y, int a_Z, cWorld * a_World) + : cBlockEntity( E_BLOCK_DISPENSER, a_X, a_Y, a_Z, a_World ) + , m_Items( new cItem[9] ) +{ + SetBlockEntity(this); // cBlockEntityWindowOwner +} + + + + + +cDispenserEntity::~cDispenserEntity() +{ + // Tell window its owner is destroyed + if( GetWindow() ) + { + GetWindow()->OwnerDestroyed(); + } + + // Clean up items + if( m_Items ) + { + delete [] m_Items; + } +} + + + + + +void cDispenserEntity::Destroy() +{ + // Drop items + cItems Pickups; + for( int i = 0; i < 3; i++) + { + if( !m_Items[i].IsEmpty() ) + { + Pickups.push_back(m_Items[i]); + m_Items[i].Empty(); + } + } + m_World->SpawnItemPickups(Pickups, m_PosX, m_PosY, m_PosZ); +} + + + + + +void cDispenserEntity::UsedBy(cPlayer * a_Player) +{ + if (GetWindow() == NULL) + { + OpenWindow(new cDispenserWindow(m_PosX, m_PosY, m_PosZ, this)); + } + if (GetWindow() != NULL) + { + if (a_Player->GetWindow() != GetWindow()) + { + a_Player->OpenWindow(GetWindow()); + GetWindow()->SendWholeWindow(*a_Player->GetClientHandle()); + } + } +} + + + + + +bool cDispenserEntity::Tick( float a_Dt ) +{ + return true; +} + + + + + +void cDispenserEntity::SetSlot(int a_Slot, const cItem & a_Item) +{ + if ((a_Slot < 0) || (a_Slot >= 9)) + { + ASSERT(!"Dispenser: slot number out of range"); + return; + } + m_Items[a_Slot] = a_Item; +} + + + + + +#define READ(File, Var) \ + if (File.Read(&Var, sizeof(Var)) != sizeof(Var)) \ + { \ + LOGERROR("ERROR READING cDispenserEntity %s FROM FILE (line %d)", #Var, __LINE__); \ + return false; \ + } + +bool cDispenserEntity::LoadFromFile(cFile & f) +{ + READ(f, m_PosX); + READ(f, m_PosY); + READ(f, m_PosZ); + + unsigned int NumSlots = 0; + READ(f, NumSlots); + m_Items = new cItem[ NumSlots ]; + for(unsigned int i = 0; i < NumSlots; i++) + { + cItem & Item = m_Items[i]; + READ(f, Item.m_ItemID); + READ(f, Item.m_ItemCount); + READ(f, Item.m_ItemHealth); + } + + return true; +} + + + + + +bool cDispenserEntity::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 ) + { + m_Items[ SlotIdx ].FromJson( *itr ); + SlotIdx++; + } + + return true; +} + + + + + +void cDispenserEntity::SaveToJson( Json::Value& a_Value ) +{ + a_Value["x"] = m_PosX; + a_Value["y"] = m_PosY; + a_Value["z"] = m_PosZ; + + Json::Value AllSlots; + for(unsigned int i = 0; i < 3; i++) + { + Json::Value Slot; + m_Items[ i ].GetJson( Slot ); + AllSlots.append( Slot ); + } + a_Value["Slots"] = AllSlots; +} + + + + + +void cDispenserEntity::SendTo(cClientHandle & a_Client) +{ + // Nothing needs to be sent + UNUSED(a_Client); +} + + + + diff --git a/source/DispenserEntity.h b/source/DispenserEntity.h new file mode 100644 index 000000000..8f2e89833 --- /dev/null +++ b/source/DispenserEntity.h @@ -0,0 +1,55 @@ + +#pragma once + +#include "BlockEntity.h" +#include "UI/WindowOwner.h" +#include "Item.h" + + + + + +namespace Json +{ + class Value; +} + +class cClientHandle; +class cServer; + + + + + +class cDispenserEntity : + public cBlockEntity, + public cBlockEntityWindowOwner +{ +public: + cDispenserEntity(int a_X, int a_Y, int a_Z, cWorld * a_World); + virtual ~cDispenserEntity(); + virtual void Destroy(); + + bool LoadFromFile(cFile & a_File); // deprecated format + + bool LoadFromJson(const Json::Value& a_Value ); + virtual void SaveToJson(Json::Value& a_Value ) override; + + virtual void SendTo(cClientHandle & a_Client) override; + + // Returns true if there's any change, forcing the chunk to go dirty. + bool Tick( float a_Dt ); + + virtual void UsedBy( cPlayer * a_Player ) override; + + const cItem * GetSlot(int i) const { return &(m_Items[i]); } + + void SetSlot(int a_Slot, const cItem & a_Item); + +private: + cItem * m_Items; +}; + + + + diff --git a/source/UI/SlotArea.cpp b/source/UI/SlotArea.cpp index 4b6d237ba..01f77d74a 100644 --- a/source/UI/SlotArea.cpp +++ b/source/UI/SlotArea.cpp @@ -7,6 +7,7 @@ #include "SlotArea.h" #include "../Player.h" #include "../ChestEntity.h" +#include "../DispenserEntity.h" #include "../FurnaceEntity.h" #include "../Items/ItemHandler.h" #include "Window.h" @@ -414,6 +415,53 @@ cCraftingRecipe & cSlotAreaCrafting::GetRecipeForPlayer(cPlayer & a_Player) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cSlotAreaFurnace: + +cSlotAreaDispenser::cSlotAreaDispenser(cDispenserEntity * a_Dispenser, cWindow & a_ParentWindow) : + cSlotArea(9, a_ParentWindow), + m_Dispenser(a_Dispenser) +{ +} + + + + + +void cSlotAreaDispenser::Clicked(cPlayer & a_Player, int a_SlotNum, bool a_IsRightClick, bool a_IsShiftPressed, const cItem & a_ClickedItem) +{ + super::Clicked(a_Player, a_SlotNum, a_IsRightClick, a_IsShiftPressed, a_ClickedItem); + + if (m_Dispenser == NULL) + { + LOGERROR("cSlotAreaDispenser::Clicked(): m_Dispenser == NULL"); + ASSERT(!"cSlotAreaDispenser::Clicked(): m_Dispenser == NULL"); + return; + } +} + + + + + +const cItem * cSlotAreaDispenser::GetSlot(int a_SlotNum, cPlayer & a_Player) +{ + return m_Dispenser->GetSlot(a_SlotNum); +} + + + + + +void cSlotAreaDispenser::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) +{ + m_Dispenser->SetSlot(a_SlotNum, a_Item); +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cSlotAreaFurnace: diff --git a/source/UI/SlotArea.h b/source/UI/SlotArea.h index ffb8ed553..50c7e0c28 100644 --- a/source/UI/SlotArea.h +++ b/source/UI/SlotArea.h @@ -15,6 +15,7 @@ class cWindow; class cPlayer; class cChestEntity; +class cDispenserEntity; class cFurnaceEntity; class cCraftingRecipe; @@ -231,6 +232,26 @@ protected: +class cSlotAreaDispenser : + public cSlotArea +{ + typedef cSlotArea super; + +public: + cSlotAreaDispenser(cDispenserEntity * a_Dispenser, cWindow & a_ParentWindow); + + virtual void Clicked(cPlayer & a_Player, int a_SlotNum, bool a_IsRightClick, bool a_IsShiftPressed, const cItem & a_ClickedItem) override; + virtual const cItem * GetSlot(int a_SlotNum, cPlayer & a_Player) override; + virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override; + +protected: + cDispenserEntity * m_Dispenser; +} ; + + + + + class cSlotAreaFurnace : public cSlotArea { diff --git a/source/UI/Window.cpp b/source/UI/Window.cpp index dc5587390..7ad7b1a58 100644 --- a/source/UI/Window.cpp +++ b/source/UI/Window.cpp @@ -460,6 +460,21 @@ cChestWindow::~cChestWindow() +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cDispenserWindow: + +cDispenserWindow::cDispenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserEntity * a_Dispenser) : + cWindow(cWindow::Dispenser, "MCS-Dispenser") +{ + m_SlotAreas.push_back(new cSlotAreaDispenser(a_Dispenser, *this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cFurnaceWindow: diff --git a/source/UI/Window.h b/source/UI/Window.h index a570ed480..f939727c9 100644 --- a/source/UI/Window.h +++ b/source/UI/Window.h @@ -19,6 +19,7 @@ class cPlayer; class cWindowOwner; class cClientHandle; class cChestEntity; +class cDispenserEntity; class cFurnaceEntity; class cSlotArea; class cWorld; @@ -148,6 +149,17 @@ public: +class cDispenserWindow : + public cWindow +{ +public: + cDispenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserEntity * a_Dispenser); +} ; + + + + + class cChestWindow : public cWindow { diff --git a/source/World.h b/source/World.h index 9b6b16f59..530370ce5 100644 --- a/source/World.h +++ b/source/World.h @@ -38,14 +38,16 @@ class cBlockEntity; class cWorldGenerator; // The generator that actually generates the chunks for a single world class cChunkGenerator; // The thread responsible for generating chunks class cChestEntity; +class cDispenserEntity; class cFurnaceEntity; typedef std::list< cPlayer * > cPlayerList; -typedef cItemCallback cPlayerListCallback; -typedef cItemCallback cEntityCallback; -typedef cItemCallback cChestCallback; -typedef cItemCallback cFurnaceCallback; +typedef cItemCallback cPlayerListCallback; +typedef cItemCallback cEntityCallback; +typedef cItemCallback cChestCallback; +typedef cItemCallback cDispenserCallback; +typedef cItemCallback cFurnaceCallback; diff --git a/source/WorldStorage/WSSAnvil.cpp b/source/WorldStorage/WSSAnvil.cpp index e30b3c409..895386e4c 100644 --- a/source/WorldStorage/WSSAnvil.cpp +++ b/source/WorldStorage/WSSAnvil.cpp @@ -9,6 +9,7 @@ #include "zlib.h" #include "../BlockID.h" #include "../ChestEntity.h" +#include "../DispenserEntity.h" #include "../FurnaceEntity.h" #include "../SignEntity.h" #include "../NoteEntity.h" @@ -132,8 +133,27 @@ protected: m_Writer.EndList(); m_Writer.EndCompound(); } + + + void AddDispenserEntity(cDispenserEntity * a_Entity) + { + m_Writer.BeginCompound(""); + AddBasicTileEntity(a_Entity, "Trap"); + m_Writer.BeginList("Items", TAG_Compound); + for (int i = 0; i < 9; i++) + { + const cItem * Item = a_Entity->GetSlot(i); + if ((Item == NULL) || Item->IsEmpty()) + { + continue; + } + AddItem(Item, i); + } + m_Writer.EndList(); + m_Writer.EndCompound(); + } - + void AddFurnaceEntity(cFurnaceEntity * a_Furnace) { m_Writer.BeginCompound(""); @@ -229,12 +249,13 @@ protected: // Add tile-entity into NBT: switch (a_Entity->GetBlockType()) { - case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break; - case E_BLOCK_FURNACE: AddFurnaceEntity((cFurnaceEntity *)a_Entity); break; + case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break; + case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break; + case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break; case E_BLOCK_SIGN_POST: - case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break; - case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break; - case E_BLOCK_JUKEBOX: AddJukeboxEntity((cJukeboxEntity *)a_Entity); break; + case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break; + case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break; + case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break; default: { ASSERT(!"Unhandled block entity saved into Anvil"); @@ -728,6 +749,10 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con { LoadChestFromNBT(a_BlockEntities, a_NBT, Child); } + else if (strncmp(a_NBT.GetData(sID), "Trap", a_NBT.GetDataLength(sID)) == 0) + { + LoadDispenserFromNBT(a_BlockEntities, a_NBT, Child); + } else if (strncmp(a_NBT.GetData(sID), "Furnace", a_NBT.GetDataLength(sID)) == 0) { LoadFurnaceFromNBT(a_BlockEntities, a_NBT, Child); @@ -801,6 +826,55 @@ void cWSSAnvil::LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cPars +void cWSSAnvil::LoadDispenserFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); + int x, y, z; + if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z)) + { + return; + } + int Items = a_NBT.FindChildByName(a_TagIdx, "Items"); + if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List)) + { + return; // Make it an empty dispenser - the chunk loader will provide an empty cDispenserEntity for this + } + std::auto_ptr Dispenser(new cDispenserEntity(x, y, z, m_World)); + for (int Child = a_NBT.GetFirstChild(Items); Child != -1; Child = a_NBT.GetNextSibling(Child)) + { + int Slot = a_NBT.FindChildByName(Child, "Slot"); + if ((Slot < 0) || (a_NBT.GetType(Slot) != TAG_Byte)) + { + continue; + } + cItem Item; + int ID = a_NBT.FindChildByName(Child, "id"); + if ((ID < 0) || (a_NBT.GetType(ID) != TAG_Short)) + { + continue; + } + Item.m_ItemID = (ENUM_ITEM_ID)(a_NBT.GetShort(ID)); + int Damage = a_NBT.FindChildByName(Child, "Damage"); + if ((Damage < 0) || (a_NBT.GetType(Damage) != TAG_Short)) + { + continue; + } + Item.m_ItemHealth = a_NBT.GetShort(Damage); + int Count = a_NBT.FindChildByName(Child, "Count"); + if ((Count < 0) || (a_NBT.GetType(Count) != TAG_Byte)) + { + continue; + } + Item.m_ItemCount = a_NBT.GetByte(Count); + Dispenser->SetSlot(a_NBT.GetByte(Slot), Item); + } // for itr - ItemDefs[] + a_BlockEntities.push_back(Dispenser.release()); +} + + + + + void cWSSAnvil::LoadFurnaceFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) { ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); diff --git a/source/WorldStorage/WSSAnvil.h b/source/WorldStorage/WSSAnvil.h index 37c1f0b4e..cdd225bd5 100644 --- a/source/WorldStorage/WSSAnvil.h +++ b/source/WorldStorage/WSSAnvil.h @@ -111,11 +111,12 @@ protected: /// Loads the chunk's BlockEntities from NBT data (a_Tag is the Level\\TileEntities list tag; may be -1) void LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntitites, const cParsedNBT & a_NBT, int a_Tag); - void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadFurnaceFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadSignFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadNoteFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadJukeboxFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadFurnaceFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadSignFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadNoteFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadJukeboxFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); /// Helper function for extracting the X, Y, and Z int subtags of a NBT compound; returns true if successful bool GetBlockEntityNBTPos(const cParsedNBT & a_NBT, int a_TagIdx, int & a_X, int & a_Y, int & a_Z); diff --git a/source/WorldStorage/WSSCompact.cpp b/source/WorldStorage/WSSCompact.cpp index 22e25eb6f..87cf1d930 100644 --- a/source/WorldStorage/WSSCompact.cpp +++ b/source/WorldStorage/WSSCompact.cpp @@ -11,6 +11,7 @@ #include "../StringCompression.h" #include "../ChestEntity.h" #include "../SignEntity.h" +#include "../DispenserEntity.h" #include "../FurnaceEntity.h" #include "../NoteEntity.h" #include "../JukeboxEntity.h" @@ -71,12 +72,13 @@ void cJsonChunkSerializer::BlockEntity(cBlockEntity * a_BlockEntity) const char * SaveInto = NULL; switch (a_BlockEntity->GetBlockType()) { - case E_BLOCK_CHEST: SaveInto = "Chests"; break; - case E_BLOCK_FURNACE: SaveInto = "Furnaces"; break; - case E_BLOCK_SIGN_POST: SaveInto = "Signs"; break; - case E_BLOCK_WALLSIGN: SaveInto = "Signs"; break; - case E_BLOCK_NOTE_BLOCK: SaveInto = "Notes"; break; - case E_BLOCK_JUKEBOX: SaveInto = "Jukeboxes"; break; + case E_BLOCK_CHEST: SaveInto = "Chests"; break; + case E_BLOCK_DISPENSER: SaveInto = "Dispensers"; break; + case E_BLOCK_FURNACE: SaveInto = "Furnaces"; break; + case E_BLOCK_SIGN_POST: SaveInto = "Signs"; break; + case E_BLOCK_WALLSIGN: SaveInto = "Signs"; break; + case E_BLOCK_NOTE_BLOCK: SaveInto = "Notes"; break; + case E_BLOCK_JUKEBOX: SaveInto = "Jukeboxes"; break; default: { @@ -281,6 +283,26 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En } // for itr - AllChests[] } + // Load dispensers + Json::Value AllDispensers = a_Value.get("Dispensers", Json::nullValue); + if( !AllDispensers.empty() ) + { + for( Json::Value::iterator itr = AllDispensers.begin(); itr != AllDispensers.end(); ++itr ) + { + Json::Value & Dispenser = *itr; + cDispenserEntity * DispenserEntity = new cDispenserEntity(0,0,0, a_World); + if( !DispenserEntity->LoadFromJson( Dispenser ) ) + { + LOGERROR("ERROR READING DISPENSER FROM JSON!" ); + delete DispenserEntity; + } + else + { + a_BlockEntities.push_back( DispenserEntity ); + } + } // for itr - AllDispensers[] + } + // Load furnaces Json::Value AllFurnaces = a_Value.get("Furnaces", Json::nullValue); if( !AllFurnaces.empty() ) -- cgit v1.2.3