From 84a7e14e86b0bb4025e3c93d6a5d09ee8240a531 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Sun, 26 May 2013 15:29:43 +0000 Subject: [PATCH] Block entities with storage now correctly mark the chunk as dirty when their contents change. http://forum.mc-server.org/showthread.php?tid=434&pid=8210#pid8210 git-svn-id: http://mc-server.googlecode.com/svn/trunk@1515 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/Bindings.cpp | 68 +++++++++++++++++++++- source/Bindings.h | 2 +- source/BlockEntity.h | 3 + source/BlockEntityWithItems.h | 13 +++++ source/WorldStorage/WSSAnvil.cpp | 96 +++++++++++++++++++++----------- source/WorldStorage/WSSAnvil.h | 14 +++++ 6 files changed, 162 insertions(+), 34 deletions(-) diff --git a/source/Bindings.cpp b/source/Bindings.cpp index 81d0f19f6..a6229c761 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 05/26/13 16:21:49. +** Generated automatically by tolua++-1.0.92 on 05/26/13 17:28:14. */ #ifndef __cplusplus @@ -15781,6 +15781,70 @@ static int tolua_AllToLua_cBlockEntity_GetWorld00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: GetChunkX of class cBlockEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBlockEntity_GetChunkX00 +static int tolua_AllToLua_cBlockEntity_GetChunkX00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cBlockEntity",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cBlockEntity* self = (const cBlockEntity*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetChunkX'", NULL); +#endif + { + int tolua_ret = (int) self->GetChunkX(); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetChunkX'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: GetChunkZ of class cBlockEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBlockEntity_GetChunkZ00 +static int tolua_AllToLua_cBlockEntity_GetChunkZ00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cBlockEntity",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cBlockEntity* self = (const cBlockEntity*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetChunkZ'", NULL); +#endif + { + int tolua_ret = (int) self->GetChunkZ(); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetChunkZ'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: GetSlot of class cBlockEntityWithItems */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cBlockEntityWithItems_GetSlot00 static int tolua_AllToLua_cBlockEntityWithItems_GetSlot00(lua_State* tolua_S) @@ -26560,6 +26624,8 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"GetPosZ",tolua_AllToLua_cBlockEntity_GetPosZ00); tolua_function(tolua_S,"GetBlockType",tolua_AllToLua_cBlockEntity_GetBlockType00); tolua_function(tolua_S,"GetWorld",tolua_AllToLua_cBlockEntity_GetWorld00); + tolua_function(tolua_S,"GetChunkX",tolua_AllToLua_cBlockEntity_GetChunkX00); + tolua_function(tolua_S,"GetChunkZ",tolua_AllToLua_cBlockEntity_GetChunkZ00); tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cBlockEntityWithItems","cBlockEntityWithItems","cBlockEntity",NULL); tolua_beginmodule(tolua_S,"cBlockEntityWithItems"); diff --git a/source/Bindings.h b/source/Bindings.h index 3a62f5754..ca0f4e02a 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 05/26/13 16:21:49. +** Generated automatically by tolua++-1.0.92 on 05/26/13 17:28:14. */ /* Exported function */ diff --git a/source/BlockEntity.h b/source/BlockEntity.h index 0cc7f6077..05818437b 100644 --- a/source/BlockEntity.h +++ b/source/BlockEntity.h @@ -56,6 +56,9 @@ public: cWorld * GetWorld(void) const {return m_World; } + int GetChunkX(void) const { return FAST_FLOOR_DIV(m_PosX, cChunkDef::Width); } + int GetChunkZ(void) const { return FAST_FLOOR_DIV(m_PosZ, cChunkDef::Width); } + // tolua_end virtual void SaveToJson (Json::Value & a_Value) = 0; diff --git a/source/BlockEntityWithItems.h b/source/BlockEntityWithItems.h index e5753359d..b160b8ed4 100644 --- a/source/BlockEntityWithItems.h +++ b/source/BlockEntityWithItems.h @@ -19,6 +19,10 @@ // tolua_begin class cBlockEntityWithItems : public cBlockEntity + // tolua_end + // tolua doesn't seem to support multiple inheritance? + , public cItemGrid::cListener + // tolua_begin { typedef cBlockEntity super; @@ -34,6 +38,7 @@ public: super(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World), m_Contents(a_ItemGridWidth, a_ItemGridHeight) { + m_Contents.AddListener(*this); } virtual void Destroy(void) override @@ -64,6 +69,14 @@ public: protected: cItemGrid m_Contents; + + // cItemGrid::cListener overrides: + virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) + { + ASSERT(a_Grid == &m_Contents); + ASSERT(m_World != NULL); + m_World->MarkChunkDirty(GetChunkX(), GetChunkZ()); + } } ; // tolua_export diff --git a/source/WorldStorage/WSSAnvil.cpp b/source/WorldStorage/WSSAnvil.cpp index 2af36b1ad..b4b842bbd 100644 --- a/source/WorldStorage/WSSAnvil.cpp +++ b/source/WorldStorage/WSSAnvil.cpp @@ -11,11 +11,13 @@ #include "../BlockID.h" #include "../ChestEntity.h" #include "../DispenserEntity.h" +#include "../DropperEntity.h" #include "../FurnaceEntity.h" #include "../SignEntity.h" #include "../NoteEntity.h" #include "../JukeboxEntity.h" #include "../Item.h" +#include "../ItemGrid.h" #include "../StringCompression.h" #include "../Entity.h" #include "../OSSupport/MakeDir.h" @@ -558,18 +560,14 @@ 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) + else if (strncmp(a_NBT.GetData(sID), "Dropper", a_NBT.GetDataLength(sID)) == 0) { - LoadDispenserFromNBT(a_BlockEntities, a_NBT, Child); + LoadDropperFromNBT(a_BlockEntities, a_NBT, Child); } else if (strncmp(a_NBT.GetData(sID), "Furnace", a_NBT.GetDataLength(sID)) == 0) { LoadFurnaceFromNBT(a_BlockEntities, a_NBT, Child); } - else if (strncmp(a_NBT.GetData(sID), "Sign", a_NBT.GetDataLength(sID)) == 0) - { - LoadSignFromNBT(a_BlockEntities, a_NBT, Child); - } else if (strncmp(a_NBT.GetData(sID), "Music", a_NBT.GetDataLength(sID)) == 0) { LoadNoteFromNBT(a_BlockEntities, a_NBT, Child); @@ -578,6 +576,14 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con { LoadJukeboxFromNBT(a_BlockEntities, a_NBT, Child); } + else if (strncmp(a_NBT.GetData(sID), "Sign", a_NBT.GetDataLength(sID)) == 0) + { + LoadSignFromNBT(a_BlockEntities, a_NBT, Child); + } + else if (strncmp(a_NBT.GetData(sID), "Trap", a_NBT.GetDataLength(sID)) == 0) + { + LoadDispenserFromNBT(a_BlockEntities, a_NBT, Child); + } // TODO: Other block entities } // for Child - tag children } @@ -617,6 +623,34 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_ +void cWSSAnvil::LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a_NBT, int a_ItemsTagIdx, int a_SlotOffset) +{ + int NumSlots = a_ItemGrid.GetNumSlots(); + for (int Child = a_NBT.GetFirstChild(a_ItemsTagIdx); Child != -1; Child = a_NBT.GetNextSibling(Child)) + { + int SlotTag = a_NBT.FindChildByName(Child, "Slot"); + if ((SlotTag < 0) || (a_NBT.GetType(SlotTag) != TAG_Byte)) + { + continue; + } + int SlotNum = (int)(a_NBT.GetByte(SlotTag)) - a_SlotOffset; + if ((SlotNum < 0) || (SlotNum >= NumSlots)) + { + // SlotNum outside of the range + continue; + } + cItem Item; + if (LoadItemFromNBT(Item, a_NBT, Child)) + { + a_ItemGrid.SetSlot(SlotNum, Item); + } + } // for itr - ItemDefs[] +} + + + + + void cWSSAnvil::LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) { ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); @@ -631,19 +665,7 @@ void cWSSAnvil::LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cPars return; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this } std::auto_ptr Chest(new cChestEntity(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; - if (LoadItemFromNBT(Item, a_NBT, Child)) - { - Chest->SetSlot(a_NBT.GetByte(Slot), Item); - } - } // for itr - ItemDefs[] + LoadItemGridFromNBT(Chest->GetContents(), a_NBT, Items); a_BlockEntities.push_back(Chest.release()); } @@ -665,19 +687,7 @@ void cWSSAnvil::LoadDispenserFromNBT(cBlockEntityList & a_BlockEntities, const c 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; - if (LoadItemFromNBT(Item, a_NBT, Child)) - { - Dispenser->SetSlot(a_NBT.GetByte(Slot), Item); - } - } // for itr - ItemDefs[] + LoadItemGridFromNBT(Dispenser->GetContents(), a_NBT, Items); a_BlockEntities.push_back(Dispenser.release()); } @@ -685,6 +695,28 @@ void cWSSAnvil::LoadDispenserFromNBT(cBlockEntityList & a_BlockEntities, const c +void cWSSAnvil::LoadDropperFromNBT(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 Dropper(new cDropperEntity(x, y, z, m_World)); + LoadItemGridFromNBT(Dropper->GetContents(), a_NBT, Items); + a_BlockEntities.push_back(Dropper.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 640edd210..7281d687d 100644 --- a/source/WorldStorage/WSSAnvil.h +++ b/source/WorldStorage/WSSAnvil.h @@ -15,6 +15,13 @@ +// fwd: ItemGrid.h +class cItemGrid; + + + + + enum { /// Maximum number of chunks in an MCA file - also the count of the header items @@ -114,8 +121,15 @@ protected: /// Loads a cItem contents from the specified NBT tag; returns true if successful. Doesn't load the Slot tag bool LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_TagIdx); + /** Loads contentents of an Items[] list tag into a cItemGrid + ItemGrid begins at the specified slot offset + Slots outside the ItemGrid range are ignored + */ + void LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a_NBT, int a_ItemsTagIdx, int s_SlotOffset = 0); + 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 LoadDropperFromNBT (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);