diff options
Diffstat (limited to '')
28 files changed, 891 insertions, 37 deletions
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index e65da1d16..2a592e1e1 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2244,6 +2244,7 @@ end DigBlock = { Params = "X, Y, Z", Return = "", Notes = "Replaces the specified block with air, without dropping the usual pickups for the block. Wakes up the simulators for the block and its neighbors." }, DoExplosionAt = { Params = "Force, X, Y, Z, CanCauseFire, Source, SourceData", Return = "", Notes = "Creates an explosion of the specified relative force in the specified position. If CanCauseFire is set, the explosion will set blocks on fire, too. The Source parameter specifies the source of the explosion, one of the esXXX constants. The SourceData parameter is specific to each source type, usually it provides more info about the source." }, DoWithBlockEntityAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a block entity at the specified coords, calls the CallbackFunction with the {{cBlockEntity}} parameter representing the block entity. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cBlockEntity|BlockEntity}}, [CallbackData])</pre> The function returns false if there is no block entity, or if there is, it returns the bool value that the callback has returned. Use {{tolua}}.cast() to cast the Callback's BlockEntity parameter to the correct {{cBlockEntity}} descendant." }, + DoWithBeaconAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a beacon at the specified coords, calls the CallbackFunction with the {{cBeaconEntity}} parameter representing the beacon. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cBeaconEntity|BeaconEntity}}, [CallbackData])</pre> The function returns false if there is no beacon, or if there is, it returns the bool value that the callback has returned." }, DoWithChestAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a chest at the specified coords, calls the CallbackFunction with the {{cChestEntity}} parameter representing the chest. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cChestEntity|ChestEntity}}, [CallbackData])</pre> The function returns false if there is no chest, or if there is, it returns the bool value that the callback has returned." }, DoWithCommandBlockAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a command block at the specified coords, calls the CallbackFunction with the {{cCommandBlockEntity}} parameter representing the command block. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cCommandBlockEntity|CommandBlockEntity}}, [CallbackData])</pre> The function returns false if there is no command block, or if there is, it returns the bool value that the callback has returned." }, DoWithDispenserAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dispenser at the specified coords, calls the CallbackFunction with the {{cDispenserEntity}} parameter representing the dispenser. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cDispenserEntity|DispenserEntity}}, [CallbackData])</pre> The function returns false if there is no dispenser, or if there is, it returns the bool value that the callback has returned." }, diff --git a/MCServer/Plugins/APIDump/Classes/BlockEntities.lua b/MCServer/Plugins/APIDump/Classes/BlockEntities.lua index de42f66df..90ebf12e6 100644 --- a/MCServer/Plugins/APIDump/Classes/BlockEntities.lua +++ b/MCServer/Plugins/APIDump/Classes/BlockEntities.lua @@ -50,6 +50,32 @@ return }, }, + cBeaconEntity = + { + Desc = [[ + A beacon entity is a {{cBlockEntityWithItems|cBlockEntityWithItems}} descendant that represents a beacon + in the world. + ]], + + Inherits = "cBlockEntityWithItems", + + Functions = + { + IsActive = { Params = "", Return = "bool", Notes = "Is the beacon active?" }, + GetBeaconLevel = { Params = "", Return = "number", Notes = "Returns the beacon level. (0 - 4)" }, + GetPrimaryEffect = { Params = "", Return = "EffectType", Notes = "Returns the primary effect." }, + GetSecondaryEffect = { Params = "", Return = "EffectType", Notes = "Returns the secondary effect." }, + SetPrimaryEffect = { Params = "EffectType", Return = "bool", Notes = "Select the primary effect. Returns false when the effect is invalid." }, + SetSecondaryEffect = { Params = "EffectType", Return = "bool", Notes = "Select the secondary effect. Returns false when the effect is invalid." }, + CalculatePyramidLevel = { Params = "", Return = "number", Notes = "Calculate the amount of layers the pyramid below the beacon has." }, + IsBeaconBlocked = { Params = "", Return = "bool", Notes = "Is the beacon blocked by non-transparent blocks that are higher than the beacon?" }, + UpdateBeacon = { Params = "", Return = "", Notes = "Update the beacon." }, + GiveEffects = { Params = "", Return = "", Notes = "Give the near-players the effects." }, + IsMineralBlock = { Params = "BLOCKTYPE", Return = "bool", Notes = "Returns true if the block is a diamond block, a golden block, an iron block or an emerald block." }, + IsValidEffect = { Params = "EffectType", Return = "bool", Notes = "Returns true if the effect can be used." }, + }, + }, + cChestEntity = { Desc = [[ diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg index 1e5dfd2fe..621358662 100644 --- a/src/Bindings/AllToLua.pkg +++ b/src/Bindings/AllToLua.pkg @@ -47,6 +47,7 @@ $cfile "../Inventory.h" $cfile "../Enchantments.h" $cfile "../Item.h" $cfile "../ItemGrid.h" +$cfile "../BlockEntities/BeaconEntity.h" $cfile "../BlockEntities/BlockEntity.h" $cfile "../BlockEntities/BlockEntityWithItems.h" $cfile "../BlockEntities/ChestEntity.h" diff --git a/src/Bindings/CMakeLists.txt b/src/Bindings/CMakeLists.txt index 48e7ce79c..a2b381a26 100644 --- a/src/Bindings/CMakeLists.txt +++ b/src/Bindings/CMakeLists.txt @@ -53,6 +53,7 @@ set(BINDING_DEPENDENCIES ../Bindings/WebPlugin.h ../BiomeDef.h ../BlockArea.h + ../BlockEntities/BeaconEntity.h ../BlockEntities/BlockEntity.h ../BlockEntities/BlockEntityWithItems.h ../BlockEntities/ChestEntity.h diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index df9687fc0..460d879d5 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -16,6 +16,7 @@ #include "../WebAdmin.h" #include "../ClientHandle.h" #include "../BlockArea.h" +#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" @@ -2996,6 +2997,7 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_beginmodule(tolua_S, "cWorld"); tolua_function(tolua_S, "ChunkStay", tolua_cWorld_ChunkStay); tolua_function(tolua_S, "DoWithBlockEntityAt", tolua_DoWithXYZ<cWorld, cBlockEntity, &cWorld::DoWithBlockEntityAt>); + tolua_function(tolua_S, "DoWithBeaconAt", tolua_DoWithXYZ<cWorld, cBeaconEntity, &cWorld::DoWithBeaconAt>); tolua_function(tolua_S, "DoWithChestAt", tolua_DoWithXYZ<cWorld, cChestEntity, &cWorld::DoWithChestAt>); tolua_function(tolua_S, "DoWithDispenserAt", tolua_DoWithXYZ<cWorld, cDispenserEntity, &cWorld::DoWithDispenserAt>); tolua_function(tolua_S, "DoWithDropSpenserAt", tolua_DoWithXYZ<cWorld, cDropSpenserEntity, &cWorld::DoWithDropSpenserAt>); diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp index 4b9662797..805e5e61f 100644 --- a/src/BlockEntities/BeaconEntity.cpp +++ b/src/BlockEntities/BeaconEntity.cpp @@ -3,33 +3,31 @@ #include "BeaconEntity.h" #include "../BlockArea.h" +#include "../Entities/Player.h" -cBeaconEntity::cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : - super(E_BLOCK_BEACON, a_BlockX, a_BlockY, a_BlockZ, a_World) +cBeaconEntity::cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) + : super(E_BLOCK_BEACON, a_BlockX, a_BlockY, a_BlockZ, 1, 1, a_World) + , m_IsActive(false) + , m_BeaconLevel(0) + , m_PrimaryEffect(cEntityEffect::effNoEffect) + , m_SecondaryEffect(cEntityEffect::effNoEffect) { + UpdateBeacon(); } -int cBeaconEntity::GetPyramidLevel(void) +char cBeaconEntity::CalculatePyramidLevel(void) { cBlockArea Area; - int MinY = GetPosY() - 4; - if (MinY < 0) - { - MinY = 0; - } - int MaxY = GetPosY() - 1; - if (MaxY < 0) - { - MaxY = 0; - } + int MinY = std::max(GetPosY() - 4, 0); + int MaxY = std::max(GetPosY() - 1, 0); Area.Read( m_World, @@ -42,7 +40,7 @@ int cBeaconEntity::GetPyramidLevel(void) int Layer = 1; int MiddleXZ = 4; - for (int Y = Area.GetSizeY() - 1; Y > 0; Y--) + for (int Y = (Area.GetSizeY() - 1); Y >= 0; Y--) { for (int X = MiddleXZ - Layer; X <= (MiddleXZ + Layer); X++) { @@ -50,14 +48,97 @@ int cBeaconEntity::GetPyramidLevel(void) { if (!IsMineralBlock(Area.GetRelBlockType(X, Y, Z))) { - return Layer - 1; + return (Layer - 1); } } } Layer++; } - return Layer - 1; + return (Layer - 1); +} + + + + + +bool cBeaconEntity::IsValidEffect(cEntityEffect::eType a_Effect, char a_BeaconLevel) +{ + switch (a_Effect) + { + case cEntityEffect::effRegeneration: return (a_BeaconLevel >= 4); + case cEntityEffect::effStrength: return (a_BeaconLevel >= 3); + case cEntityEffect::effResistance: return (a_BeaconLevel >= 2); + case cEntityEffect::effJumpBoost: return (a_BeaconLevel >= 2); + case cEntityEffect::effSpeed: return (a_BeaconLevel >= 1); + case cEntityEffect::effHaste: return (a_BeaconLevel >= 1); + case cEntityEffect::effNoEffect: return true; + + default: + { + LOGD("%s: Invalid beacon effect: %d", __FUNCTION__, (int)a_Effect); + return false; + } + } +} + + + + + +bool cBeaconEntity::SetPrimaryEffect(cEntityEffect::eType a_Effect) +{ + if (!IsValidEffect(a_Effect, m_BeaconLevel)) + { + return false; + } + + m_PrimaryEffect = a_Effect; + + // Send window update: + if (GetWindow() != NULL) + { + GetWindow()->SetProperty(1, m_PrimaryEffect); + } + return true; +} + + + + + +bool cBeaconEntity::SetSecondaryEffect(cEntityEffect::eType a_Effect) +{ + if (!IsValidEffect(a_Effect, m_BeaconLevel)) + { + return false; + } + + m_SecondaryEffect = a_Effect; + + // Send window update: + if (GetWindow() != NULL) + { + GetWindow()->SetProperty(2, m_SecondaryEffect); + } + return true; +} + + + + + +bool cBeaconEntity::IsBeaconBlocked(void) +{ + for (int Y = m_PosY; Y < cChunkDef::Height; ++Y) + { + BLOCKTYPE Block = m_World->GetBlock(m_PosX, Y, m_PosZ); + if (!cBlockInfo::IsTransparent(Block)) + { + return true; + } + } + return false; } @@ -83,8 +164,113 @@ bool cBeaconEntity::IsMineralBlock(BLOCKTYPE a_BlockType) +void cBeaconEntity::UpdateBeacon(void) +{ + int OldBeaconLevel = m_BeaconLevel; + + if (IsBeaconBlocked()) + { + m_IsActive = false; + m_BeaconLevel = 0; + } + else + { + m_BeaconLevel = CalculatePyramidLevel(); + m_IsActive = (m_BeaconLevel > 0); + } + + if (m_BeaconLevel != OldBeaconLevel) + { + // Send window update: + if (GetWindow() != NULL) + { + GetWindow()->SetProperty(0, m_BeaconLevel); + } + } + + // TODO: Add achievement +} + + + + + +void cBeaconEntity::GiveEffects(void) +{ + if (!m_IsActive || (m_BeaconLevel < 0)) + { + return; + } + + int Radius = m_BeaconLevel * 10 + 10; + short EffectLevel = 0; + if ((m_BeaconLevel >= 4) && (m_PrimaryEffect == m_SecondaryEffect)) + { + EffectLevel = 1; + } + + cEntityEffect::eType SecondaryEffect = cEntityEffect::effNoEffect; + if ((m_BeaconLevel >= 4) && (m_PrimaryEffect != m_SecondaryEffect) && (m_SecondaryEffect > 0)) + { + SecondaryEffect = m_SecondaryEffect; + } + + class cPlayerCallback : public cPlayerListCallback + { + int m_Radius; + int m_PosX, m_PosY, m_PosZ; + cEntityEffect::eType m_PrimaryEffect, m_SecondaryEffect; + short m_EffectLevel; + + virtual bool Item(cPlayer * a_Player) + { + Vector3d PlayerPosition = Vector3d(a_Player->GetPosition()); + if (PlayerPosition.y > (double)m_PosY) + { + PlayerPosition.y = (double)m_PosY; + } + + // TODO: Vanilla minecraft uses an AABB check instead of a radius one + Vector3d BeaconPosition = Vector3d(m_PosX, m_PosY, m_PosZ); + if ((PlayerPosition - BeaconPosition).Length() <= m_Radius) + { + a_Player->AddEntityEffect(m_PrimaryEffect, 180, m_EffectLevel); + + if (m_SecondaryEffect != cEntityEffect::effNoEffect) + { + a_Player->AddEntityEffect(m_SecondaryEffect, 180, 0); + } + } + return false; + } + + public: + cPlayerCallback(int a_Radius, int a_PosX, int a_PosY, int a_PosZ, cEntityEffect::eType a_PrimaryEffect, cEntityEffect::eType a_SecondaryEffect, short a_EffectLevel) + : m_Radius(a_Radius) + , m_PosX(a_PosX) + , m_PosY(a_PosY) + , m_PosZ(a_PosZ) + , m_PrimaryEffect(a_PrimaryEffect) + , m_SecondaryEffect(a_SecondaryEffect) + , m_EffectLevel(a_EffectLevel) + {}; + + } PlayerCallback(Radius, m_PosX, m_PosY, m_PosZ, m_PrimaryEffect, SecondaryEffect, EffectLevel); + GetWorld()->ForEachPlayer(PlayerCallback); +} + + + + + bool cBeaconEntity::Tick(float a_Dt, cChunk & a_Chunk) { + // Update the beacon every 4 seconds + if ((GetWorld()->GetWorldAge() % 80) == 0) + { + UpdateBeacon(); + GiveEffects(); + } return false; } @@ -92,23 +278,94 @@ bool cBeaconEntity::Tick(float a_Dt, cChunk & a_Chunk) -void cBeaconEntity::SaveToJson(Json::Value& a_Value) +void cBeaconEntity::UsedBy(cPlayer * a_Player) { + cWindow * Window = GetWindow(); + if (Window == NULL) + { + OpenWindow(new cBeaconWindow(m_PosX, m_PosY, m_PosZ, this)); + Window = GetWindow(); + } + + if (Window != NULL) + { + // if (a_Player->GetWindow() != Window) + // -> Because mojang doesn't send a 'close window' packet when you click the cancel button in the beacon inventory ... + { + a_Player->OpenWindow(Window); + } + } } -void cBeaconEntity::SendTo(cClientHandle & a_Client) + +bool cBeaconEntity::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++; + } + + m_BeaconLevel = (char)a_Value.get("Level", 0).asInt(); + int PrimaryEffect = a_Value.get("PrimaryEffect", 0).asInt(); + int SecondaryEffect = a_Value.get("SecondaryEffect", 0).asInt(); + + if ((PrimaryEffect >= 0) && (PrimaryEffect <= (int)cEntityEffect::effSaturation)) + { + m_PrimaryEffect = (cEntityEffect::eType)PrimaryEffect; + } + + if ((SecondaryEffect >= 0) && (SecondaryEffect <= (int)cEntityEffect::effSaturation)) + { + m_SecondaryEffect = (cEntityEffect::eType)SecondaryEffect; + } + + return true; +} + + + + + +void cBeaconEntity::SaveToJson(Json::Value& a_Value) { + a_Value["x"] = m_PosX; + a_Value["y"] = m_PosY; + a_Value["z"] = m_PosZ; + + Json::Value AllSlots; + int NumSlots = m_Contents.GetNumSlots(); + for (int i = 0; i < NumSlots; i++) + { + Json::Value Slot; + m_Contents.GetSlot(i).GetJson(Slot); + AllSlots.append(Slot); + } + a_Value["Slots"] = AllSlots; + + a_Value["Level"] = m_BeaconLevel; + a_Value["PrimaryEffect"] = (int)m_PrimaryEffect; + a_Value["SecondaryEffect"] = (int)m_SecondaryEffect; } -void cBeaconEntity::UsedBy(cPlayer * a_Player) +void cBeaconEntity::SendTo(cClientHandle & a_Client) { + a_Client.SendUpdateBlockEntity(*this); } diff --git a/src/BlockEntities/BeaconEntity.h b/src/BlockEntities/BeaconEntity.h index ee1eda391..0d7150aef 100644 --- a/src/BlockEntities/BeaconEntity.h +++ b/src/BlockEntities/BeaconEntity.h @@ -1,7 +1,14 @@ +// BeaconEntity.h + +// Declares the cBeaconEntity class representing a single beacon in the world + + + + #pragma once -#include "BlockEntity.h" +#include "BlockEntityWithItems.h" @@ -16,28 +23,70 @@ namespace Json +// tolua_begin class cBeaconEntity : - public cBlockEntity + public cBlockEntityWithItems { - typedef cBlockEntity super; + typedef cBlockEntityWithItems super; public: - - /** The initial constructor */ + // tolua_end + cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); - - /** Returns the amount of layers the pyramid below the beacon has. */ - int GetPyramidLevel(void); + + bool LoadFromJson(const Json::Value & a_Value); + // cBlockEntity overrides: + virtual void SaveToJson(Json::Value& a_Value) override; + virtual void SendTo(cClientHandle & a_Client) override; + virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; + virtual void UsedBy(cPlayer * a_Player) override; + + /** Modify the beacon level. (It is needed to load the beacon corectly) */ + void SetBeaconLevel(char a_Level) { m_BeaconLevel = a_Level; } + + // tolua_begin + + /** Is the beacon active? */ + bool IsActive(void) const { return m_IsActive; } + + /** Returns the beacon level. (0 - 4) */ + char GetBeaconLevel(void) const { return m_BeaconLevel; } + + cEntityEffect::eType GetPrimaryEffect(void) const { return m_PrimaryEffect; } + cEntityEffect::eType GetSecondaryEffect(void) const { return m_SecondaryEffect; } + + /** Sets the primary effect. Returns false when the effect is invalid. */ + bool SetPrimaryEffect(cEntityEffect::eType a_Effect); + + /** Sets the secondary effect. Returns false when the effect is invalid. */ + bool SetSecondaryEffect(cEntityEffect::eType a_Effect); + + /** Calculate the amount of layers the pyramid below the beacon has. */ + char CalculatePyramidLevel(void); + + /** Is the beacon blocked by non-transparent blocks that are higher than the beacon? */ + bool IsBeaconBlocked(void); + + /** Update the beacon. */ + void UpdateBeacon(void); + + /** Give the near-players the effects. */ + void GiveEffects(void); /** Returns true if the block is a diamond block, a golden block, an iron block or an emerald block. */ static bool IsMineralBlock(BLOCKTYPE a_BlockType); - - // cBlockEntity overrides: - virtual void SaveToJson(Json::Value& a_Value) override; - virtual void SendTo(cClientHandle & a_Client) override; - virtual void UsedBy(cPlayer * a_Player) override; - virtual bool Tick(float a_Dt, cChunk & /* a_Chunk */) override; -} ; + + /** Returns true if the effect can be used. */ + static bool IsValidEffect(cEntityEffect::eType a_Effect, char a_BeaconLevel); + + // tolua_end + +protected: + bool m_IsActive; + char m_BeaconLevel; + + cEntityEffect::eType m_PrimaryEffect, m_SecondaryEffect; +} ; // tolua_export diff --git a/src/BlockEntities/FlowerPotEntity.cpp b/src/BlockEntities/FlowerPotEntity.cpp index 87bf8b921..e001634b8 100644 --- a/src/BlockEntities/FlowerPotEntity.cpp +++ b/src/BlockEntities/FlowerPotEntity.cpp @@ -1,7 +1,7 @@ // FlowerPotEntity.cpp -// Implements the cFlowerPotEntity class representing a single sign in the world +// Implements the cFlowerPotEntity class representing a single flower pot in the world #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "json/json.h" diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index ddb0186c9..52f7dd608 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -181,6 +181,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType); case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType); + case E_BLOCK_BEACON: return new cBlockEntityHandler (a_BlockType); case E_BLOCK_BED: return new cBlockBedHandler (a_BlockType); case E_BLOCK_BIG_FLOWER: return new cBlockBigFlowerHandler (a_BlockType); case E_BLOCK_BIRCH_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType); diff --git a/src/Blocks/BlockPiston.h b/src/Blocks/BlockPiston.h index bbb8af75b..0bec603e3 100644 --- a/src/Blocks/BlockPiston.h +++ b/src/Blocks/BlockPiston.h @@ -94,6 +94,7 @@ private: switch (a_BlockType) { case E_BLOCK_ANVIL: + case E_BLOCK_BEACON: case E_BLOCK_BEDROCK: case E_BLOCK_BREWING_STAND: case E_BLOCK_CHEST: diff --git a/src/Chunk.cpp b/src/Chunk.cpp index b83036b6d..cd7dc698c 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -11,6 +11,7 @@ #include "Server.h" #include "zlib/zlib.h" #include "Defines.h" +#include "BlockEntities/BeaconEntity.h" #include "BlockEntities/ChestEntity.h" #include "BlockEntities/DispenserEntity.h" #include "BlockEntities/DropperEntity.h" @@ -2126,6 +2127,38 @@ bool cChunk::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBloc +bool cChunk::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback) +{ + // The blockentity list is locked by the parent chunkmap's CS + for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2) + { + ++itr2; + if (((*itr)->GetPosX() != a_BlockX) || ((*itr)->GetPosY() != a_BlockY) || ((*itr)->GetPosZ() != a_BlockZ)) + { + continue; + } + if ((*itr)->GetBlockType() != E_BLOCK_BEACON) + { + // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out + return false; + } + + // The correct block entity is here + if (a_Callback.Item((cBeaconEntity *)*itr)) + { + return false; + } + return true; + } // for itr - m_BlockEntitites[] + + // Not found: + return false; +} + + + + + bool cChunk::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback) { // The blockentity list is locked by the parent chunkmap's CS diff --git a/src/Chunk.h b/src/Chunk.h index 7eee3999c..5cde3f08f 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -28,6 +28,7 @@ class cServer; class MTRand; class cPlayer; class cChunkMap; +class cBeaconEntity; class cChestEntity; class cDispenserEntity; class cFurnaceEntity; @@ -45,6 +46,7 @@ class cMobSpawner; typedef std::list<cClientHandle *> cClientHandleList; typedef cItemCallback<cEntity> cEntityCallback; +typedef cItemCallback<cBeaconEntity> cBeaconCallback; typedef cItemCallback<cChestEntity> cChestCallback; typedef cItemCallback<cDispenserEntity> cDispenserCallback; typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; @@ -236,6 +238,9 @@ public: /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible + /** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */ + bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Lua-acessible + /** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */ bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 05d219918..dd8be0631 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -1839,6 +1839,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ } case E_BLOCK_OBSIDIAN: + case E_BLOCK_BEACON: case E_BLOCK_BEDROCK: case E_BLOCK_WATER: case E_BLOCK_LAVA: @@ -2115,6 +2116,24 @@ bool cChunkMap::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cB +bool cChunkMap::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback) +{ + int ChunkX, ChunkZ; + int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; + cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + if ((Chunk == NULL) || !Chunk->IsValid()) + { + return false; + } + return Chunk->DoWithBeaconAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); +} + + + + + bool cChunkMap::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback) { int ChunkX, ChunkZ; diff --git a/src/ChunkMap.h b/src/ChunkMap.h index e33d9f894..1e9a0f982 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -19,6 +19,7 @@ class MTRand; class cChunkStay; class cChunk; class cPlayer; +class cBeaconEntity; class cChestEntity; class cDispenserEntity; class cDropperEntity; @@ -40,6 +41,7 @@ typedef std::list<cClientHandle *> cClientHandleList; typedef cChunk * cChunkPtr; typedef cItemCallback<cEntity> cEntityCallback; typedef cItemCallback<cBlockEntity> cBlockEntityCallback; +typedef cItemCallback<cBeaconEntity> cBeaconCallback; typedef cItemCallback<cChestEntity> cChestCallback; typedef cItemCallback<cDispenserEntity> cDispenserCallback; typedef cItemCallback<cDropperEntity> cDropperCallback; @@ -234,6 +236,9 @@ public: /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible + /** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */ + bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Lua-acessible + /** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */ bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 30ec737be..3ce506e1e 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -7,6 +7,7 @@ #include "Bindings/PluginManager.h" #include "Entities/Player.h" #include "Inventory.h" +#include "BlockEntities/BeaconEntity.h" #include "BlockEntities/ChestEntity.h" #include "BlockEntities/CommandBlockEntity.h" #include "BlockEntities/SignEntity.h" @@ -659,6 +660,10 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString // Client <-> Server branding exchange SendPluginMessage("MC|Brand", "MCServer"); } + else if (a_Channel == "MC|Beacon") + { + HandleBeaconSelection(a_Message.c_str(), a_Message.size()); + } else if (a_Channel == "MC|ItemName") { HandleAnvilItemName(a_Message.c_str(), a_Message.size()); @@ -746,6 +751,55 @@ void cClientHandle::UnregisterPluginChannels(const AStringVector & a_ChannelList +void cClientHandle::HandleBeaconSelection(const char * a_Data, size_t a_Length) +{ + if (a_Length < 14) + { + SendChat("Failure setting beacon selection; bad request", mtFailure); + LOGD("Malformed MC|Beacon packet."); + return; + } + + cWindow * Window = m_Player->GetWindow(); + if ((Window == NULL) || (Window->GetWindowType() != cWindow::wtBeacon)) + { + return; + } + cBeaconWindow * BeaconWindow = (cBeaconWindow *) Window; + + if (Window->GetSlot(*m_Player, 0)->IsEmpty()) + { + return; + } + + cByteBuffer Buffer(a_Length); + Buffer.Write(a_Data, a_Length); + + int PrimaryEffectID, SecondaryEffectID; + Buffer.ReadBEInt(PrimaryEffectID); + Buffer.ReadBEInt(SecondaryEffectID); + + cEntityEffect::eType PrimaryEffect = cEntityEffect::effNoEffect; + if ((PrimaryEffectID >= 0) && (PrimaryEffectID <= (int)cEntityEffect::effSaturation)) + { + PrimaryEffect = (cEntityEffect::eType)PrimaryEffectID; + } + + cEntityEffect::eType SecondaryEffect = cEntityEffect::effNoEffect; + if ((SecondaryEffectID >= 0) && (SecondaryEffectID <= (int)cEntityEffect::effSaturation)) + { + SecondaryEffect = (cEntityEffect::eType)SecondaryEffectID; + } + + Window->SetSlot(*m_Player, 0, cItem()); + BeaconWindow->GetBeaconEntity()->SetPrimaryEffect(PrimaryEffect); + BeaconWindow->GetBeaconEntity()->SetSecondaryEffect(SecondaryEffect); +} + + + + + void cClientHandle::HandleCommandBlockMessage(const char * a_Data, size_t a_Length) { if (a_Length < 14) diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 48eba4de1..f3f1da417 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -399,7 +399,10 @@ private: /** Removes all of the channels from the list of current plugin channels. Ignores channels that are not found. */ void UnregisterPluginChannels(const AStringVector & a_ChannelList); - + + /** Handles the "MC|Beacon" plugin message */ + void HandleBeaconSelection(const char * a_Data, size_t a_Length); + /** Handles the "MC|AdvCdm" plugin message */ void HandleCommandBlockMessage(const char * a_Data, size_t a_Length); diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 45d39e0e9..8e31e211c 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -37,6 +37,7 @@ Implements the 1.7.x protocol classes: #include "../Mobs/IncludeAllMonsters.h" #include "../UI/Window.h" +#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/FlowerPotEntity.h" @@ -1328,6 +1329,7 @@ void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) { 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 + case E_BLOCK_BEACON: Action = 3; break; // Update beacon entity case E_BLOCK_HEAD: Action = 4; break; // Update Mobhead entity case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break; @@ -2581,6 +2583,19 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt switch (a_BlockEntity.GetBlockType()) { + case E_BLOCK_BEACON: + { + cBeaconEntity & BeaconEntity = (cBeaconEntity &)a_BlockEntity; + + Writer.AddInt("x", BeaconEntity.GetPosX()); + Writer.AddInt("y", BeaconEntity.GetPosY()); + Writer.AddInt("z", BeaconEntity.GetPosZ()); + Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect()); + Writer.AddInt("Secondary", BeaconEntity.GetSecondaryEffect()); + Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel()); + Writer.AddString("id", "Beacon"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though + break; + } case E_BLOCK_COMMAND_BLOCK: { cCommandBlockEntity & CommandBlockEntity = (cCommandBlockEntity &)a_BlockEntity; diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index b5f84c24c..4199bbf56 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -5,6 +5,7 @@ #include "Globals.h" #include "SlotArea.h" #include "../Entities/Player.h" +#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/DropSpenserEntity.h" #include "../BlockEntities/EnderChestEntity.h" @@ -1190,6 +1191,200 @@ void cSlotAreaAnvil::UpdateResult(cPlayer & a_Player) +//////////////////////////////////////////////////////////////////////////////// +// cSlotAreaBeacon: + +cSlotAreaBeacon::cSlotAreaBeacon(cBeaconEntity * a_Beacon, cWindow & a_ParentWindow) : + cSlotArea(1, a_ParentWindow), + m_Beacon(a_Beacon) +{ + m_Beacon->GetContents().AddListener(*this); +} + + + + + +cSlotAreaBeacon::~cSlotAreaBeacon() +{ + m_Beacon->GetContents().RemoveListener(*this); +} + + + + +bool cSlotAreaBeacon::IsPlaceableItem(short a_ItemType) +{ + switch (a_ItemType) + { + case E_ITEM_EMERALD: + case E_ITEM_DIAMOND: + case E_ITEM_GOLD: + case E_ITEM_IRON: + { + return true; + } + } + return false; +} + + + + + +void cSlotAreaBeacon::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) +{ + ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots())); + + bool bAsync = false; + if (GetSlot(a_SlotNum, a_Player) == NULL) + { + LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); + return; + } + + switch (a_ClickAction) + { + case caShiftLeftClick: + case caShiftRightClick: + { + ShiftClicked(a_Player, a_SlotNum, a_ClickedItem); + return; + } + case caMiddleClick: + { + MiddleClicked(a_Player, a_SlotNum); + return; + } + case caDropKey: + case caCtrlDropKey: + { + DropClicked(a_Player, a_SlotNum, false); + return; + } + case caNumber1: + case caNumber2: + case caNumber3: + case caNumber4: + case caNumber5: + case caNumber6: + case caNumber7: + case caNumber8: + case caNumber9: + { + NumberClicked(a_Player, a_SlotNum, a_ClickAction); + return; + } + default: + { + break; + } + } + + cItem Slot(*GetSlot(a_SlotNum, a_Player)); + if (!Slot.IsSameType(a_ClickedItem)) + { + LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots); + LOGWARNING("My item: %s", ItemToFullString(Slot).c_str()); + LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str()); + bAsync = true; + } + cItem & DraggingItem = a_Player.GetDraggingItem(); + + if (DraggingItem.IsEmpty()) + { + DraggingItem = Slot; + Slot.Empty(); + } + else if (Slot.IsEmpty()) + { + if (!IsPlaceableItem(DraggingItem.m_ItemType)) + { + return; + } + + Slot = DraggingItem.CopyOne(); + DraggingItem.m_ItemCount -= 1; + if (DraggingItem.m_ItemCount <= 0) + { + DraggingItem.Empty(); + } + } + else if (DraggingItem.m_ItemCount == 1) + { + if (!IsPlaceableItem(DraggingItem.m_ItemCount)) + { + return; + } + + // Switch contents + cItem tmp(DraggingItem); + DraggingItem = Slot; + Slot = tmp; + } + + SetSlot(a_SlotNum, a_Player, Slot); + if (bAsync) + { + m_ParentWindow.BroadcastWholeWindow(); + } +} + + + + + +void cSlotAreaBeacon::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) +{ + const cItem * Slot = GetSlot(0, a_Player); + if (!Slot->IsEmpty() || !IsPlaceableItem(a_ItemStack.m_ItemType) || (a_ItemStack.m_ItemCount != 1)) + { + return; + } + + if (a_ShouldApply) + { + SetSlot(0, a_Player, a_ItemStack.CopyOne()); + } + a_ItemStack.Empty(); +} + + + + + +const cItem * cSlotAreaBeacon::GetSlot(int a_SlotNum, cPlayer & a_Player) const +{ + UNUSED(a_Player); + return &(m_Beacon->GetSlot(a_SlotNum)); +} + + + + + +void cSlotAreaBeacon::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) +{ + UNUSED(a_Player); + m_Beacon->SetSlot(a_SlotNum, a_Item); +} + + + + + +void cSlotAreaBeacon::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) +{ + UNUSED(a_SlotNum); + // Something has changed in the window, broadcast the entire window to all clients + ASSERT(a_ItemGrid == &(m_Beacon->GetContents())); + + m_ParentWindow.BroadcastWholeWindow(); +} + + + + //////////////////////////////////////////////////////////////////////////////// // cSlotAreaEnchanting: diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h index fa842bb81..9a96f2f3c 100644 --- a/src/UI/SlotArea.h +++ b/src/UI/SlotArea.h @@ -15,6 +15,7 @@ class cWindow; class cPlayer; +class cBeaconEntity; class cChestEntity; class cDropSpenserEntity; class cEnderChestEntity; @@ -314,6 +315,34 @@ protected: +class cSlotAreaBeacon : + public cSlotArea, + public cItemGrid::cListener +{ + typedef cSlotArea super; + +public: + cSlotAreaBeacon(cBeaconEntity * a_Beacon, cWindow & a_ParentWindow); + virtual ~cSlotAreaBeacon(); + + bool IsPlaceableItem(short a_ItemType); + + virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + virtual const cItem * GetSlot(int a_SlotNum, cPlayer & a_Player) const override; + virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override; + +protected: + cBeaconEntity * m_Beacon; + + // cItemGrid::cListener overrides: + virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override; +} ; + + + + + class cSlotAreaEnchanting : public cSlotAreaTemporary { diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp index 4731f282b..8f4913030 100644 --- a/src/UI/Window.cpp +++ b/src/UI/Window.cpp @@ -9,6 +9,7 @@ #include "../Entities/Pickup.h" #include "../Inventory.h" #include "../Items/ItemHandler.h" +#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/DropSpenserEntity.h" #include "../BlockEntities/EnderChestEntity.h" @@ -841,6 +842,36 @@ void cAnvilWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ) //////////////////////////////////////////////////////////////////////////////// +// cBeaconWindow: + +cBeaconWindow::cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon) : + cWindow(wtBeacon, "Beacon"), + m_Beacon(a_Beacon) +{ + m_ShouldDistributeToHotbarFirst = true; + m_SlotAreas.push_back(new cSlotAreaBeacon(m_Beacon, *this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + +void cBeaconWindow::OpenedByPlayer(cPlayer & a_Player) +{ + super::OpenedByPlayer(a_Player); + + a_Player.GetClientHandle()->SendWindowProperty(*this, 0, m_Beacon->GetBeaconLevel()); + a_Player.GetClientHandle()->SendWindowProperty(*this, 1, m_Beacon->GetPrimaryEffect()); + a_Player.GetClientHandle()->SendWindowProperty(*this, 2, m_Beacon->GetSecondaryEffect()); +} + + + + + +//////////////////////////////////////////////////////////////////////////////// // cEnchantingWindow: cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : diff --git a/src/UI/Window.h b/src/UI/Window.h index 97db0ca88..9fb0e3b38 100644 --- a/src/UI/Window.h +++ b/src/UI/Window.h @@ -23,6 +23,7 @@ class cDropSpenserEntity; class cEnderChestEntity; class cFurnaceEntity; class cHopperEntity; +class cBeaconEntity; class cSlotArea; class cSlotAreaAnvil; class cWorld; @@ -258,6 +259,26 @@ protected: +class cBeaconWindow : + public cWindow +{ + typedef cWindow super; +public: + cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon); + + cBeaconEntity * GetBeaconEntity(void) const { return m_Beacon; } + + // cWindow Overrides: + virtual void OpenedByPlayer(cPlayer & a_Player) override; + +protected: + cBeaconEntity * m_Beacon; +} ; + + + + + class cEnchantingWindow : public cWindow { diff --git a/src/World.cpp b/src/World.cpp index 7500b163d..865ddfcc6 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -25,6 +25,7 @@ #include "Entities/TNTEntity.h" #include "BlockEntities/CommandBlockEntity.h" +#include "BlockEntities/BeaconEntity.h" // Simulators: #include "Simulator/SimulatorManager.h" @@ -1232,6 +1233,15 @@ bool cWorld::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBloc +bool cWorld::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback& a_Callback) +{ + return m_ChunkMap->DoWithBeaconAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); +} + + + + + bool cWorld::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback) { return m_ChunkMap->DoWithChestAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); diff --git a/src/World.h b/src/World.h index 4d0ccf2dd..90b798e8e 100644 --- a/src/World.h +++ b/src/World.h @@ -41,6 +41,7 @@ class cEntity; class cBlockEntity; class cWorldGenerator; // The generator that actually generates the chunks for a single world class cChunkGenerator; // The thread responsible for generating chunks +class cBeaconEntity; class cChestEntity; class cDispenserEntity; class cFlowerPotEntity; @@ -59,6 +60,7 @@ typedef std::vector<cSetChunkDataPtr> cSetChunkDataPtrs; typedef cItemCallback<cPlayer> cPlayerListCallback; typedef cItemCallback<cEntity> cEntityCallback; +typedef cItemCallback<cBeaconEntity> cBeaconCallback; typedef cItemCallback<cChestEntity> cChestCallback; typedef cItemCallback<cDispenserEntity> cDispenserCallback; typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; @@ -523,6 +525,9 @@ public: /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ virtual bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback) override; // Exported in ManualBindings.cpp + /** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */ + bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Exported in ManualBindings.cpp + /** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */ bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 4857da1b6..601cd8833 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -10,6 +10,7 @@ #include "../StringCompression.h" #include "FastNBT.h" +#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" @@ -176,6 +177,23 @@ void cNBTChunkSerializer::AddBasicTileEntity(cBlockEntity * a_Entity, const char +void cNBTChunkSerializer::AddBeaconEntity(cBeaconEntity * a_Entity) +{ + m_Writer.BeginCompound(""); + AddBasicTileEntity(a_Entity, "Beacon"); + m_Writer.AddInt("Levels", a_Entity->GetBeaconLevel()); + m_Writer.AddInt("Primary", (int)a_Entity->GetPrimaryEffect()); + m_Writer.AddInt("Secondary", (int)a_Entity->GetSecondaryEffect()); + m_Writer.BeginList("Items", TAG_Compound); + AddItemGrid(a_Entity->GetContents()); + m_Writer.EndList(); + m_Writer.EndCompound(); +} + + + + + void cNBTChunkSerializer::AddChestEntity(cChestEntity * a_Entity, BLOCKTYPE a_ChestType) { m_Writer.BeginCompound(""); @@ -825,6 +843,7 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity) // Add tile-entity into NBT: switch (a_Entity->GetBlockType()) { + case E_BLOCK_BEACON: AddBeaconEntity ((cBeaconEntity *) a_Entity); break; case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity, a_Entity->GetBlockType()); break; case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity((cCommandBlockEntity *)a_Entity); break; case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break; diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h index 710a06a70..4c229a65c 100644 --- a/src/WorldStorage/NBTChunkSerializer.h +++ b/src/WorldStorage/NBTChunkSerializer.h @@ -20,6 +20,7 @@ class cFastNBTWriter; class cEntity; class cBlockEntity; class cBoat; +class cBeaconEntity; class cChestEntity; class cCommandBlockEntity; class cDispenserEntity; @@ -93,6 +94,7 @@ protected: // Block entities: void AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID); + void AddBeaconEntity (cBeaconEntity * a_Entity); void AddChestEntity (cChestEntity * a_Entity, BLOCKTYPE a_ChestType); void AddDispenserEntity(cDispenserEntity * a_Entity); void AddDropperEntity (cDropperEntity * a_Entity); diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 71ff3ef99..d3a156ee1 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -16,6 +16,7 @@ #include "../StringCompression.h" #include "../SetChunkData.h" +#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" @@ -582,7 +583,11 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con { continue; } - if (strncmp(a_NBT.GetData(sID), "Chest", a_NBT.GetDataLength(sID)) == 0) + if (strncmp(a_NBT.GetData(sID), "Beacon", a_NBT.GetDataLength(sID)) == 0) + { + LoadBeaconFromNBT(a_BlockEntities, a_NBT, Child); + } + else if (strncmp(a_NBT.GetData(sID), "Chest", a_NBT.GetDataLength(sID)) == 0) { LoadChestFromNBT(a_BlockEntities, a_NBT, Child, E_BLOCK_CHEST); } @@ -746,6 +751,49 @@ void cWSSAnvil::LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a +void cWSSAnvil::LoadBeaconFromNBT(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; + } + + std::auto_ptr<cBeaconEntity> Beacon(new cBeaconEntity(x, y, z, m_World)); + + int CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Levels"); + if (CurrentLine >= 0) + { + Beacon->SetBeaconLevel((char)a_NBT.GetInt(CurrentLine)); + } + + CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Primary"); + if (CurrentLine >= 0) + { + Beacon->SetPrimaryEffect((cEntityEffect::eType)a_NBT.GetInt(CurrentLine)); + } + + CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Secondary"); + if (CurrentLine >= 0) + { + Beacon->SetSecondaryEffect((cEntityEffect::eType)a_NBT.GetInt(CurrentLine)); + } + + // We are better than mojang, we load/save the beacon inventory! + int Items = a_NBT.FindChildByName(a_TagIdx, "Items"); + if ((Items >= 0) && (a_NBT.GetType(Items) == TAG_List)) + { + LoadItemGridFromNBT(Beacon->GetContents(), a_NBT, Items); + } + + a_BlockEntities.push_back(Beacon.release()); +} + + + + + void cWSSAnvil::LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_ChestType) { ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index 9f8714404..f8eeb8247 100644 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -133,6 +133,7 @@ protected: */ void LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a_NBT, int a_ItemsTagIdx, int s_SlotOffset = 0); + void LoadBeaconFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_ChestType); void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp index ee47047a0..58f9e3cab 100644 --- a/src/WorldStorage/WSSCompact.cpp +++ b/src/WorldStorage/WSSCompact.cpp @@ -9,6 +9,7 @@ #include "zlib/zlib.h" #include "json/json.h" #include "../StringCompression.h" +#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" @@ -75,6 +76,7 @@ void cJsonChunkSerializer::BlockEntity(cBlockEntity * a_BlockEntity) const char * SaveInto = NULL; switch (a_BlockEntity->GetBlockType()) { + case E_BLOCK_BEACON: SaveInto = "Beacons"; break; case E_BLOCK_CHEST: SaveInto = "Chests"; break; case E_BLOCK_DISPENSER: SaveInto = "Dispensers"; break; case E_BLOCK_DROPPER: SaveInto = "Droppers"; break; @@ -268,6 +270,24 @@ bool cWSSCompact::EraseChunkData(const cChunkCoords & a_Chunk) void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities, cWorld * a_World) { + // Load beacon: + Json::Value AllBeacons = a_Value.get("Beacons", Json::nullValue); + if (!AllBeacons.empty()) + { + for (Json::Value::iterator itr = AllBeacons.begin(); itr != AllBeacons.end(); ++itr) + { + std::auto_ptr<cBeaconEntity> BeaconEntity(new cBeaconEntity(0, 0, 0, a_World)); + if (!BeaconEntity->LoadFromJson(*itr)) + { + LOGWARNING("ERROR READING BEACON FROM JSON!"); + } + else + { + a_BlockEntities.push_back(BeaconEntity.release()); + } + } // for itr - AllBeacons[] + } + // Load chests: Json::Value AllChests = a_Value.get("Chests", Json::nullValue); if (!AllChests.empty()) |