diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Bindings/ManualBindings.cpp | 22 | ||||
-rw-r--r-- | src/BlockEntities/BlockEntity.cpp | 24 | ||||
-rw-r--r-- | src/BlockEntities/CommandBlockEntity.cpp | 227 | ||||
-rw-r--r-- | src/BlockEntities/CommandBlockEntity.h | 94 | ||||
-rw-r--r-- | src/Chunk.cpp | 34 | ||||
-rw-r--r-- | src/Chunk.h | 16 | ||||
-rw-r--r-- | src/ChunkMap.cpp | 17 | ||||
-rw-r--r-- | src/ChunkMap.h | 23 | ||||
-rw-r--r-- | src/ClientHandle.cpp | 64 | ||||
-rw-r--r-- | src/ClientHandle.h | 3 | ||||
-rw-r--r-- | src/Server.cpp | 2 | ||||
-rw-r--r-- | src/Simulator/RedstoneSimulator.cpp | 27 | ||||
-rw-r--r-- | src/Simulator/RedstoneSimulator.h | 4 | ||||
-rw-r--r-- | src/World.cpp | 9 | ||||
-rw-r--r-- | src/World.h | 16 | ||||
-rw-r--r-- | src/WorldStorage/NBTChunkSerializer.cpp | 37 | ||||
-rw-r--r-- | src/WorldStorage/NBTChunkSerializer.h | 2 | ||||
-rw-r--r-- | src/WorldStorage/WSSAnvil.cpp | 42 | ||||
-rw-r--r-- | src/WorldStorage/WSSAnvil.h | 17 |
19 files changed, 618 insertions, 62 deletions
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index ebee2d697..3ebe7b294 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -14,6 +14,7 @@ #include "../WebAdmin.h" #include "../ClientHandle.h" #include "../BlockEntities/ChestEntity.h" +#include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" #include "../BlockEntities/DropperEntity.h" #include "../BlockEntities/FurnaceEntity.h" @@ -2265,16 +2266,17 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cWorld"); - tolua_function(tolua_S, "DoWithBlockEntityAt", tolua_DoWithXYZ<cWorld, cBlockEntity, &cWorld::DoWithBlockEntityAt>); - 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>); - tolua_function(tolua_S, "DoWithDropperAt", tolua_DoWithXYZ<cWorld, cDropperEntity, &cWorld::DoWithDropperAt>); - tolua_function(tolua_S, "DoWithEntityByID", tolua_DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>); - tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>); - tolua_function(tolua_S, "DoWithNoteBlockAt", tolua_DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>); - tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>); - tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); + tolua_function(tolua_S, "DoWithBlockEntityAt", tolua_DoWithXYZ<cWorld, cBlockEntity, &cWorld::DoWithBlockEntityAt>); + 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>); + tolua_function(tolua_S, "DoWithDropperAt", tolua_DoWithXYZ<cWorld, cDropperEntity, &cWorld::DoWithDropperAt>); + tolua_function(tolua_S, "DoWithEntityByID", tolua_DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>); + tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>); + tolua_function(tolua_S, "DoWithNoteBlockAt", tolua_DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>); + tolua_function(tolua_S, "DoWithCommandBlockAt", tolua_DoWithXYZ<cWorld, cCommandBlockEntity, &cWorld::DoWithCommandBlockAt>); + tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>); + tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); tolua_function(tolua_S, "ForEachBlockEntityInChunk", tolua_ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>); tolua_function(tolua_S, "ForEachChestInChunk", tolua_ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>); tolua_function(tolua_S, "ForEachEntity", tolua_ForEach< cWorld, cEntity, &cWorld::ForEachEntity>); diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp index 5d7e4a37a..97b5c1a66 100644 --- a/src/BlockEntities/BlockEntity.cpp +++ b/src/BlockEntities/BlockEntity.cpp @@ -6,6 +6,7 @@ #include "Globals.h" #include "BlockEntity.h" #include "ChestEntity.h" +#include "CommandBlockEntity.h" #include "DispenserEntity.h" #include "DropperEntity.h" #include "EnderChestEntity.h" @@ -23,17 +24,18 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE { switch (a_BlockType) { - case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); - case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); - case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_WALLSIGN: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_NOTE_BLOCK: return new cNoteEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_COMMAND_BLOCK: return new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); + case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); + case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_WALLSIGN: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_NOTE_BLOCK: return new cNoteEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); } LOGD("%s: Requesting creation of an unknown block entity - block type %d (%s)", __FUNCTION__, a_BlockType, ItemTypeToString(a_BlockType).c_str() diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp new file mode 100644 index 000000000..c29e3dff8 --- /dev/null +++ b/src/BlockEntities/CommandBlockEntity.cpp @@ -0,0 +1,227 @@ + +// CommandBlockEntity.cpp + +// Implements the cCommandBlockEntity class representing a single command block in the world + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules +#include "json/json.h" +#include "CommandBlockEntity.h" +#include "../Entities/Player.h" + +#include "CommandOutput.h" +#include "Root.h" +#include "Server.h" // ExecuteConsoleCommand() + + + + + +cCommandBlockEntity::cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World) : + super(E_BLOCK_COMMAND_BLOCK, a_X, a_Y, a_Z, a_World), + m_ShouldExecute(false), + m_IsPowered(false) +{ + SetBlockEntity(this); // cBlockEntityWindowOwner +} + + + + + + +cCommandBlockEntity::~cCommandBlockEntity() +{ + // Tell window its owner is destroyed + cWindow * Window = GetWindow(); + if (Window != NULL) + { + Window->OwnerDestroyed(); + } +} + + + + + + +void cCommandBlockEntity::UsedBy(cPlayer * a_Player) +{ + cWindow * Window = GetWindow(); + if (Window == NULL) + { + // TODO 2014-01-18 xdot: Open the appropriate window. + // OpenWindow(new cCommandBlockWindow(m_PosX, m_PosY, m_PosZ, this)); + Window = GetWindow(); + } + + if (Window != NULL) + { + if (a_Player->GetWindow() != Window) + { + a_Player->OpenWindow(Window); + } + } +} + + + + + +void cCommandBlockEntity::SetCommand(const AString & a_Cmd) +{ + m_Command = a_Cmd; +} + + + + + +void cCommandBlockEntity::SetLastOutput(const AString & a_LastOut) +{ + m_LastOutput = a_LastOut; +} + + + + + +void cCommandBlockEntity::SetResult(const NIBBLETYPE a_Result) +{ + m_Result = a_Result; +} + + + + + +const AString & cCommandBlockEntity::GetCommand(void) const +{ + return m_Command; +} + + + + + +const AString & cCommandBlockEntity::GetLastOutput(void) const +{ + return m_LastOutput; +} + + + + + +NIBBLETYPE cCommandBlockEntity::GetResult(void) const +{ + return m_Result; +} + + + + + +void cCommandBlockEntity::Activate(void) +{ + m_ShouldExecute = true; +} + + + + + +void cCommandBlockEntity::SetRedstonePower(bool a_IsPowered) +{ + if (a_IsPowered && !m_IsPowered) + { + Activate(); + } + m_IsPowered = a_IsPowered; +} + + + + + +bool cCommandBlockEntity::Tick(float a_Dt, cChunk & a_Chunk) +{ + if (!m_ShouldExecute) + { + return false; + } + + m_ShouldExecute = false; + Execute(); + return true; +} + + + + + +void cCommandBlockEntity::SendTo(cClientHandle & a_Client) +{ + // Nothing needs to be sent + UNUSED(a_Client); +} + + + + + +bool cCommandBlockEntity::LoadFromJson(const Json::Value & a_Value) +{ + m_Command = a_Value.get("Command", "").asString(); + + m_LastOutput = a_Value.get("LastOutput", "").asString(); + + return true; +} + + + + + +void cCommandBlockEntity::SaveToJson(Json::Value & a_Value) +{ + a_Value["Command"] = m_Command; + + a_Value["LastOutput"] = m_LastOutput; +} + + + + + +void cCommandBlockEntity::Execute() +{ + class CommandBlockOutCb : + public cCommandOutputCallback + { + cCommandBlockEntity* m_CmdBlock; + + public: + CommandBlockOutCb(cCommandBlockEntity* a_CmdBlock) : m_CmdBlock(a_CmdBlock) {} + + virtual void Out(const AString & a_Text) + { + ASSERT(m_CmdBlock != NULL); + + // Overwrite field + m_CmdBlock->SetLastOutput(a_Text); + } + } CmdBlockOutCb(this); + + LOGD("cCommandBlockEntity: Executing command %s", m_Command.c_str()); + + cServer* Server = cRoot::Get()->GetServer(); + + Server->ExecuteConsoleCommand(m_Command, CmdBlockOutCb); + + // TODO 2014-01-18 xdot: Update the signal strength. + m_Result = 0; +} + + + + diff --git a/src/BlockEntities/CommandBlockEntity.h b/src/BlockEntities/CommandBlockEntity.h new file mode 100644 index 000000000..c4529a1e6 --- /dev/null +++ b/src/BlockEntities/CommandBlockEntity.h @@ -0,0 +1,94 @@ + +// CommandBlockEntity.h + +// Declares the cCommandBlockEntity class representing a single command block in the world + + + + + +#pragma once + +#include "BlockEntityWithItems.h" +#include "../UI/WindowOwner.h" + + + + + +namespace Json +{ + class Value; +} + + + + + +// tolua_begin + +class cCommandBlockEntity : + public cBlockEntity, + public cBlockEntityWindowOwner +{ + typedef cBlockEntity super; + +public: + + // tolua_end + + /// Creates a new empty command block entity + cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World); + virtual ~cCommandBlockEntity(); + + bool LoadFromJson( const Json::Value& a_Value ); + virtual void SaveToJson(Json::Value& a_Value ) override; + + virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; + virtual void SendTo(cClientHandle & a_Client) override; + virtual void UsedBy(cPlayer * a_Player) override; + + void SetLastOutput(const AString & a_LastOut); + + void SetResult(const NIBBLETYPE a_Result); + + // tolua_begin + + /// Sets the internal redstone power flag to "on" or "off", depending on the parameter. Calls Activate() if appropriate + void SetRedstonePower(bool a_IsPowered); + + /// Sets the command block to execute a command in the next tick + void Activate(void); + + /// Sets the command + void SetCommand(const AString & a_Cmd); + + /// Retrieves stored command + const AString & GetCommand(void) const; + + /// Retrieves the last line of output generated by the command block + const AString & GetLastOutput(void) const; + + /// Retrieves the result (signal strength) of the last operation + NIBBLETYPE GetResult(void) const; + + // tolua_end + +private: + + /// Executes the associated command + void Execute(); + + bool m_ShouldExecute; + bool m_IsPowered; + + AString m_Command; + + AString m_LastOutput; + + NIBBLETYPE m_Result; +} ; // tolua_export + + + + diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 0735c8144..a72464ec3 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -1298,6 +1298,7 @@ void cChunk::CreateBlockEntities(void) switch (BlockType) { case E_BLOCK_CHEST: + case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_DISPENSER: case E_BLOCK_DROPPER: case E_BLOCK_ENDER_CHEST: @@ -1425,6 +1426,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, switch (a_BlockType) { case E_BLOCK_CHEST: + case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_DISPENSER: case E_BLOCK_DROPPER: case E_BLOCK_ENDER_CHEST: @@ -2268,6 +2270,38 @@ bool cChunk::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBl +bool cChunk::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & 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_COMMAND_BLOCK) + { + // 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((cCommandBlockEntity *)*itr)) + { + return false; + } + return true; + } // for itr - m_BlockEntitites[] + + // Not found: + return false; +} + + + + + bool cChunk::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4) { // The blockentity list is locked by the parent chunkmap's CS diff --git a/src/Chunk.h b/src/Chunk.h index f0a50c3c4..4ac38c46c 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -40,12 +40,13 @@ class cFluidSimulatorData; class cMobCensus; class cMobSpawner; -typedef std::list<cClientHandle *> cClientHandleList; -typedef cItemCallback<cEntity> cEntityCallback; -typedef cItemCallback<cChestEntity> cChestCallback; -typedef cItemCallback<cDispenserEntity> cDispenserCallback; -typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; -typedef cItemCallback<cNoteEntity> cNoteBlockCallback; +typedef std::list<cClientHandle *> cClientHandleList; +typedef cItemCallback<cEntity> cEntityCallback; +typedef cItemCallback<cChestEntity> cChestCallback; +typedef cItemCallback<cDispenserEntity> cDispenserCallback; +typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; +typedef cItemCallback<cNoteEntity> cNoteBlockCallback; +typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback; @@ -237,6 +238,9 @@ public: /// Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); + /// Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found + bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); + /// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index e14090b18..5797eb453 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -1968,6 +1968,23 @@ bool cChunkMap::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNot +bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & 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->DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); +} + + + + bool cChunkMap::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4) { diff --git a/src/ChunkMap.h b/src/ChunkMap.h index e688d1f93..e9d8ee30b 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -23,6 +23,7 @@ class cDropperEntity; class cDropSpenserEntity; class cFurnaceEntity; class cNoteEntity; +class cCommandBlockEntity; class cPawn; class cPickup; class cChunkDataSerializer; @@ -32,15 +33,16 @@ class cMobSpawner; typedef std::list<cClientHandle *> cClientHandleList; typedef cChunk * cChunkPtr; -typedef cItemCallback<cEntity> cEntityCallback; -typedef cItemCallback<cBlockEntity> cBlockEntityCallback; -typedef cItemCallback<cChestEntity> cChestCallback; -typedef cItemCallback<cDispenserEntity> cDispenserCallback; -typedef cItemCallback<cDropperEntity> cDropperCallback; -typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback; -typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; -typedef cItemCallback<cNoteEntity> cNoteBlockCallback; -typedef cItemCallback<cChunk> cChunkCallback; +typedef cItemCallback<cEntity> cEntityCallback; +typedef cItemCallback<cBlockEntity> cBlockEntityCallback; +typedef cItemCallback<cChestEntity> cChestCallback; +typedef cItemCallback<cDispenserEntity> cDispenserCallback; +typedef cItemCallback<cDropperEntity> cDropperCallback; +typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback; +typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; +typedef cItemCallback<cNoteEntity> cNoteBlockCallback; +typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback; +typedef cItemCallback<cChunk> cChunkCallback; @@ -236,6 +238,9 @@ public: /// Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); // Lua-accessible + /// Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found + bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Lua-accessible + /// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index c8513d516..0a97ba6c8 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -8,6 +8,7 @@ #include "Entities/Player.h" #include "Inventory.h" #include "BlockEntities/ChestEntity.h" +#include "BlockEntities/CommandBlockEntity.h" #include "BlockEntities/SignEntity.h" #include "UI/Window.h" #include "Item.h" @@ -545,6 +546,15 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString & a_Message) { + if (a_Channel == "MC|AdvCdm") // Command block + { + const char* Data = a_Message.c_str(); + + HandleCommandBlockMessage(Data, a_Message.size()); + + return; + } + cPluginManager::Get()->CallHookPluginMessage(*this, a_Channel, a_Message); } @@ -552,6 +562,60 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString +void cClientHandle::HandleCommandBlockMessage(const char* a_Data, unsigned int a_Length) +{ + if (a_Length < 14) + { + LOGD("Malformed MC|AdvCdm packet."); + return; + } + + int BlockX, BlockY, BlockZ; + + AString Command; + + switch (a_Data[0]) + { + case 0x00: + { + BlockX = GetBEInt(a_Data + 1); + BlockY = GetBEInt(a_Data + 5); + BlockZ = GetBEInt(a_Data + 9); + + Command = AString(a_Data + 14, (int)a_Data[13]); + break; + } + + default: + { + LOGD("Unhandled MC|AdvCdm packet mode."); + return; + } + } + + class cUpdateCommandBlock : + public cCommandBlockCallback + { + AString m_Command; + public: + cUpdateCommandBlock(const AString & a_Command) : m_Command(a_Command) {} + + virtual bool Item(cCommandBlockEntity * a_CommandBlock) override + { + a_CommandBlock->SetCommand(m_Command); + return false; + } + } CmdBlockCB (Command); + + cWorld * World = m_Player->GetWorld(); + + World->DoWithCommandBlockAt(BlockX, BlockY, BlockZ, CmdBlockCB); +} + + + + + void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) { LOGD("HandleLeftClick: {%i, %i, %i}; Face: %i; Stat: %i", diff --git a/src/ClientHandle.h b/src/ClientHandle.h index da2704b72..373ca9e2e 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -324,6 +324,9 @@ private: /// Handles the DIG_FINISHED dig packet: void HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_OldBlock, NIBBLETYPE a_OldMeta); + + /// Handles the "MC|AdvCdm" plugin message + void HandleCommandBlockMessage(const char* a_Data, unsigned int a_Length); // cSocketThreads::cCallback overrides: virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client diff --git a/src/Server.cpp b/src/Server.cpp index 49067c17f..5280270b9 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -459,7 +459,7 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac { return; } - + // Special handling: "stop" and "restart" are built in if ((split[0].compare("stop") == 0) || (split[0].compare("restart") == 0)) { diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index 469680098..e361cbf49 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -4,6 +4,7 @@ #include "RedstoneSimulator.h" #include "../BlockEntities/DropSpenserEntity.h" #include "../BlockEntities/NoteEntity.h" +#include "../BlockEntities/CommandBlockEntity.h" #include "../Entities/TNTEntity.h" #include "../Blocks/BlockTorch.h" #include "../Blocks/BlockDoor.h" @@ -215,11 +216,12 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c { case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break; case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break; - case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break; + case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break; case E_BLOCK_TRAPDOOR: HandleTrapdoor(a_X, dataitr->y, a_Z); break; case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(a_X, dataitr->y, a_Z); break; case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(a_X, dataitr->y, a_Z); break; case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(a_X, dataitr->y, a_Z); break; + case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(a_X, dataitr->y, a_Z); break; case E_BLOCK_REDSTONE_TORCH_OFF: case E_BLOCK_REDSTONE_TORCH_ON: @@ -763,6 +765,29 @@ void cRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ) +void cRedstoneSimulator::HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + class cSetPowerToCommandBlock : + public cCommandBlockCallback + { + bool m_IsPowered; + public: + cSetPowerToCommandBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {} + + virtual bool Item(cCommandBlockEntity * a_CommandBlock) override + { + a_CommandBlock->SetRedstonePower(m_IsPowered); + return false; + } + } CmdBlockSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)); + + m_World.DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, CmdBlockSP); +} + + + + + void cRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType) { switch (a_MyType) diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h index 63a5be3d3..bb2efeb8a 100644 --- a/src/Simulator/RedstoneSimulator.h +++ b/src/Simulator/RedstoneSimulator.h @@ -110,6 +110,8 @@ private: void HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); /** Handles doords */ void HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ); + /** Handles command blocks */ + void HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ); /** Handles activator, detector, and powered rails */ void HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType); /** Handles trapdoors */ @@ -166,6 +168,7 @@ private: switch (Block) { case E_BLOCK_ACTIVATOR_RAIL: + case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_PISTON: case E_BLOCK_STICKY_PISTON: case E_BLOCK_DISPENSER: @@ -220,6 +223,7 @@ private: case E_BLOCK_ACTIVATOR_RAIL: case E_BLOCK_ACTIVE_COMPARATOR: case E_BLOCK_BLOCK_OF_REDSTONE: + case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_DETECTOR_RAIL: case E_BLOCK_DISPENSER: case E_BLOCK_DAYLIGHT_SENSOR: diff --git a/src/World.cpp b/src/World.cpp index 3e7c0ef74..7c56d2efb 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -1149,6 +1149,15 @@ bool cWorld::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBl +bool cWorld::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback) +{ + return m_ChunkMap->DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); +} + + + + + bool cWorld::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4) { return m_ChunkMap->GetSignLines(a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4); diff --git a/src/World.h b/src/World.h index ef74a65c7..1a7ad0cb1 100644 --- a/src/World.h +++ b/src/World.h @@ -46,12 +46,13 @@ class cMobCensus; typedef std::list< cPlayer * > cPlayerList; -typedef cItemCallback<cPlayer> cPlayerListCallback; -typedef cItemCallback<cEntity> cEntityCallback; -typedef cItemCallback<cChestEntity> cChestCallback; -typedef cItemCallback<cDispenserEntity> cDispenserCallback; -typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; -typedef cItemCallback<cNoteEntity> cNoteBlockCallback; +typedef cItemCallback<cPlayer> cPlayerListCallback; +typedef cItemCallback<cEntity> cEntityCallback; +typedef cItemCallback<cChestEntity> cChestCallback; +typedef cItemCallback<cDispenserEntity> cDispenserCallback; +typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; +typedef cItemCallback<cNoteEntity> cNoteBlockCallback; +typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback; @@ -466,6 +467,9 @@ public: /// Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); // Exported in ManualBindings.cpp + + /// Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found + bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Exported in ManualBindings.cpp /// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Exported in ManualBindings.cpp diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index e1205f2be..447296c7f 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -10,6 +10,7 @@ #include "FastNBT.h" #include "../BlockEntities/ChestEntity.h" +#include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" #include "../BlockEntities/DropperEntity.h" #include "../BlockEntities/FurnaceEntity.h" @@ -219,8 +220,23 @@ void cNBTChunkSerializer::AddJukeboxEntity(cJukeboxEntity * a_Jukebox) void cNBTChunkSerializer::AddNoteEntity(cNoteEntity * a_Note) { m_Writer.BeginCompound(""); - AddBasicTileEntity(a_Note, "Music"); - m_Writer.AddByte("note", a_Note->GetPitch()); + AddBasicTileEntity(a_Note, "Music"); + m_Writer.AddByte("note", a_Note->GetPitch()); + m_Writer.EndCompound(); +} + + + + + +void cNBTChunkSerializer::AddCommandBlockEntity(cCommandBlockEntity * a_CmdBlock) +{ + m_Writer.BeginCompound(""); + AddBasicTileEntity(a_CmdBlock, "Control"); + m_Writer.AddString("Command", a_CmdBlock->GetCommand()); + m_Writer.AddInt ("SuccessCount", a_CmdBlock->GetResult()); + m_Writer.AddString("LastOutput", a_CmdBlock->GetLastOutput()); + m_Writer.AddByte ("TrackOutput", 1); // TODO 2014-01-18 xdot: Figure out what TrackOutput is and save it. m_Writer.EndCompound(); } @@ -639,15 +655,16 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity) // Add tile-entity into NBT: switch (a_Entity->GetBlockType()) { - case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break; - case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break; - case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break; - case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break; - case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break; + case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break; + case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break; + case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break; + case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break; + case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) 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; + case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity((cCommandBlockEntity *) a_Entity); break; default: { ASSERT(!"Unhandled block entity saved into Anvil"); diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h index 9d4ac208c..245b68063 100644 --- a/src/WorldStorage/NBTChunkSerializer.h +++ b/src/WorldStorage/NBTChunkSerializer.h @@ -21,6 +21,7 @@ class cEntity; class cBlockEntity; class cBoat; class cChestEntity; +class cCommandBlockEntity; class cDispenserEntity; class cDropperEntity; class cFurnaceEntity; @@ -92,6 +93,7 @@ protected: void AddJukeboxEntity (cJukeboxEntity * a_Jukebox); void AddNoteEntity (cNoteEntity * a_Note); void AddSignEntity (cSignEntity * a_Sign); + void AddCommandBlockEntity(cCommandBlockEntity * a_CmdBlock); // Entities: void AddBasicEntity (cEntity * a_Entity, const AString & a_ClassName); diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 16513cd1b..96a77152b 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -15,6 +15,7 @@ #include "../StringCompression.h" #include "../BlockEntities/ChestEntity.h" +#include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" #include "../BlockEntities/DropperEntity.h" #include "../BlockEntities/FurnaceEntity.h" @@ -567,6 +568,10 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con { LoadChestFromNBT(a_BlockEntities, a_NBT, Child); } + else if (strncmp(a_NBT.GetData(sID), "Control", a_NBT.GetDataLength(sID)) == 0) + { + LoadCommandBlockFromNBT(a_BlockEntities, a_NBT, Child); + } else if (strncmp(a_NBT.GetData(sID), "Dropper", a_NBT.GetDataLength(sID)) == 0) { LoadDropperFromNBT(a_BlockEntities, a_NBT, Child); @@ -915,6 +920,43 @@ void cWSSAnvil::LoadSignFromNBT(cBlockEntityList & a_BlockEntities, const cParse +void cWSSAnvil::LoadCommandBlockFromNBT(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<cCommandBlockEntity> CmdBlock(new cCommandBlockEntity(x, y, z, m_World)); + + int currentLine = a_NBT.FindChildByName(a_TagIdx, "Command"); + if (currentLine >= 0) + { + CmdBlock->SetCommand(a_NBT.GetString(currentLine)); + } + + currentLine = a_NBT.FindChildByName(a_TagIdx, "SuccessCount"); + if (currentLine >= 0) + { + CmdBlock->SetResult(a_NBT.GetInt(currentLine)); + } + + currentLine = a_NBT.FindChildByName(a_TagIdx, "LastOutput"); + if (currentLine >= 0) + { + CmdBlock->SetLastOutput(a_NBT.GetString(currentLine)); + } + + // TODO 2014-01-18 xdot: Figure out what TrackOutput is and parse it. + + a_BlockEntities.push_back(CmdBlock.release()); +} + + + + + void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength) { if (strncmp(a_IDTag, "Boat", a_IDTagLength) == 0) diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index e66e63b08..5093ad083 100644 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -131,14 +131,15 @@ protected: */ 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, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas); - void LoadHopperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadJukeboxFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadNoteFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadSignFromNBT (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 LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadFurnaceFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas); + void LoadHopperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadJukeboxFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadNoteFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadSignFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength); |