Merge pull request #565 from mc-server/commandblockfixes
Command block fixes
This commit is contained in:
commit
fde8b0be60
@ -2497,6 +2497,7 @@ bool cConnection::HandleServerUpdateTileEntity(void)
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ);
|
||||
HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Action);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, DataLength);
|
||||
|
||||
AString Data;
|
||||
if ((DataLength > 0) && !m_ServerBuffer.ReadString(Data, DataLength))
|
||||
{
|
||||
@ -2506,6 +2507,18 @@ bool cConnection::HandleServerUpdateTileEntity(void)
|
||||
Log(" Block = {%d, %d, %d}", BlockX, BlockY, BlockZ);
|
||||
Log(" Action = %d", Action);
|
||||
DataLog(Data.data(), Data.size(), " Data (%u bytes)", Data.size());
|
||||
|
||||
// Save metadata to a file:
|
||||
AString fnam;
|
||||
Printf(fnam, "%s_item_%08x.nbt", m_LogNameBase.c_str(), m_ItemIdx++);
|
||||
FILE * f = fopen(fnam.c_str(), "wb");
|
||||
if (f != NULL)
|
||||
{
|
||||
fwrite(Data.data(), 1, Data.size(), f);
|
||||
fclose(f);
|
||||
Log("(saved to file \"%s\")", fnam.c_str());
|
||||
}
|
||||
|
||||
COPY_TO_CLIENT();
|
||||
return true;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "json/json.h"
|
||||
#include "CommandBlockEntity.h"
|
||||
#include "../Entities/Player.h"
|
||||
#include "../WorldStorage/FastNBT.h"
|
||||
|
||||
#include "../CommandOutput.h"
|
||||
#include "../Root.h"
|
||||
@ -40,6 +41,15 @@ void cCommandBlockEntity::UsedBy(cPlayer * a_Player)
|
||||
void cCommandBlockEntity::SetCommand(const AString & a_Cmd)
|
||||
{
|
||||
m_Command = a_Cmd;
|
||||
|
||||
/*
|
||||
Vanilla requires that the server send a Block Entity Update after a command has been set
|
||||
Therefore, command blocks don't support on-the-fly (when window is open) updating of a command and therefore...
|
||||
...the following code can't be put in UsedBy just before the window opens
|
||||
|
||||
Just documenting my experience in getting this to work :P
|
||||
*/
|
||||
m_World->BroadcastBlockEntity(GetPosX(), GetPosY(), GetPosZ());
|
||||
}
|
||||
|
||||
|
||||
@ -48,6 +58,7 @@ void cCommandBlockEntity::SetCommand(const AString & a_Cmd)
|
||||
|
||||
void cCommandBlockEntity::SetLastOutput(const AString & a_LastOut)
|
||||
{
|
||||
m_World->BroadcastBlockEntity(GetPosX(), GetPosY(), GetPosZ());
|
||||
m_LastOutput = a_LastOut;
|
||||
}
|
||||
|
||||
@ -131,8 +142,7 @@ bool cCommandBlockEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
|
||||
void cCommandBlockEntity::SendTo(cClientHandle & a_Client)
|
||||
{
|
||||
// Nothing needs to be sent
|
||||
UNUSED(a_Client);
|
||||
a_Client.SendUpdateBlockEntity(*this);
|
||||
}
|
||||
|
||||
|
||||
|
32
src/Blocks/BlockCommandBlock.h
Normal file
32
src/Blocks/BlockCommandBlock.h
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BlockEntity.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cBlockCommandBlockHandler :
|
||||
public cBlockEntityHandler
|
||||
{
|
||||
public:
|
||||
cBlockCommandBlockHandler(BLOCKTYPE a_BlockType)
|
||||
: cBlockEntityHandler(a_BlockType)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
|
||||
{
|
||||
a_Pickups.push_back(cItem(E_BLOCK_AIR, 8, 0));
|
||||
}
|
||||
|
||||
virtual const char * GetStepSound(void) override
|
||||
{
|
||||
return "step.stone";
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "BlockChest.h"
|
||||
#include "BlockCloth.h"
|
||||
#include "BlockCobWeb.h"
|
||||
#include "BlockCommandBlock.h"
|
||||
#include "BlockComparator.h"
|
||||
#include "BlockCrops.h"
|
||||
#include "BlockDeadBush.h"
|
||||
@ -116,6 +117,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
|
||||
case E_BLOCK_CAULDRON: return new cBlockCauldronHandler (a_BlockType);
|
||||
case E_BLOCK_CHEST: return new cBlockChestHandler (a_BlockType);
|
||||
case E_BLOCK_COAL_ORE: return new cBlockOreHandler (a_BlockType);
|
||||
case E_BLOCK_COMMAND_BLOCK: return new cBlockCommandBlockHandler (a_BlockType);
|
||||
case E_BLOCK_ACTIVE_COMPARATOR: return new cBlockComparatorHandler (a_BlockType);
|
||||
case E_BLOCK_COBBLESTONE: return new cBlockStoneHandler (a_BlockType);
|
||||
case E_BLOCK_COBBLESTONE_STAIRS: return new cBlockStairsHandler (a_BlockType);
|
||||
|
@ -542,12 +542,18 @@ 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
|
||||
if (a_Channel == "MC|AdvCdm") // Command block, set text, Client -> Server
|
||||
{
|
||||
const char* Data = a_Message.c_str();
|
||||
|
||||
HandleCommandBlockMessage(Data, a_Message.size());
|
||||
|
||||
return;
|
||||
}
|
||||
else if (a_Channel == "MC|Brand") // Client <-> Server branding exchange
|
||||
{
|
||||
// We are custom,
|
||||
// We are awesome,
|
||||
// We are MCServer.
|
||||
SendPluginMessage("MC|Brand", "MCServer");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -562,6 +568,7 @@ void cClientHandle::HandleCommandBlockMessage(const char* a_Data, unsigned int a
|
||||
{
|
||||
if (a_Length < 14)
|
||||
{
|
||||
SendChat(Printf("%s[INFO]%s Failure setting command block command; bad request", cChatColor::Red.c_str(), cChatColor::White.c_str()));
|
||||
LOGD("Malformed MC|AdvCdm packet.");
|
||||
return;
|
||||
}
|
||||
@ -591,6 +598,7 @@ void cClientHandle::HandleCommandBlockMessage(const char* a_Data, unsigned int a
|
||||
|
||||
default:
|
||||
{
|
||||
SendChat(Printf("%s[INFO]%s Failure setting command block command; unhandled mode", cChatColor::Red.c_str(), cChatColor::White.c_str()));
|
||||
LOGD("Unhandled MC|AdvCdm packet mode.");
|
||||
return;
|
||||
}
|
||||
@ -613,6 +621,8 @@ void cClientHandle::HandleCommandBlockMessage(const char* a_Data, unsigned int a
|
||||
cWorld * World = m_Player->GetWorld();
|
||||
|
||||
World->DoWithCommandBlockAt(BlockX, BlockY, BlockZ, CmdBlockCB);
|
||||
|
||||
SendChat(Printf("%s[INFO]%s Successfully set command block command", cChatColor::Green.c_str(), cChatColor::White.c_str()));
|
||||
}
|
||||
|
||||
|
||||
@ -2199,6 +2209,14 @@ void cClientHandle::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
|
||||
|
||||
|
||||
|
||||
void cClientHandle::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
|
||||
{
|
||||
m_Protocol->SendUpdateBlockEntity(a_BlockEntity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cClientHandle::SendUpdateSign(
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ,
|
||||
|
@ -136,6 +136,7 @@ public:
|
||||
void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||
void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay);
|
||||
void SendUnloadChunk (int a_ChunkX, int a_ChunkZ);
|
||||
void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity);
|
||||
void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4);
|
||||
void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ );
|
||||
void SendWeather (eWeather a_Weather);
|
||||
|
@ -103,6 +103,7 @@ public:
|
||||
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0;
|
||||
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) = 0;
|
||||
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) = 0;
|
||||
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) = 0;
|
||||
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) = 0;
|
||||
virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0;
|
||||
virtual void SendWeather (eWeather a_Weather) = 0;
|
||||
|
@ -79,6 +79,7 @@ public:
|
||||
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
|
||||
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override;
|
||||
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
|
||||
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override {};
|
||||
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override;
|
||||
virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override;
|
||||
virtual void SendWeather (eWeather a_Weather) override;
|
||||
|
@ -24,6 +24,7 @@ Implements the 1.7.x protocol classes:
|
||||
#include "../Entities/Player.h"
|
||||
#include "../Mobs/IncludeAllMonsters.h"
|
||||
#include "../UI/Window.h"
|
||||
#include "../BlockEntities/CommandBlockEntity.h"
|
||||
|
||||
|
||||
|
||||
@ -892,6 +893,28 @@ void cProtocol172::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
|
||||
|
||||
|
||||
|
||||
void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x35); // Update tile entity packet
|
||||
Pkt.WriteInt(a_BlockEntity.GetPosX());
|
||||
Pkt.WriteShort(a_BlockEntity.GetPosY());
|
||||
Pkt.WriteInt(a_BlockEntity.GetPosZ());
|
||||
|
||||
Byte Action = 0;
|
||||
switch (a_BlockEntity.GetBlockType())
|
||||
{
|
||||
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
|
||||
default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break;
|
||||
}
|
||||
Pkt.WriteByte(Action);
|
||||
|
||||
Pkt.WriteBlockEntity(a_BlockEntity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol172::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4)
|
||||
{
|
||||
@ -1819,6 +1842,51 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
|
||||
|
||||
|
||||
|
||||
void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEntity)
|
||||
{
|
||||
cFastNBTWriter Writer;
|
||||
|
||||
switch (a_BlockEntity.GetBlockType())
|
||||
{
|
||||
case E_BLOCK_COMMAND_BLOCK:
|
||||
{
|
||||
cCommandBlockEntity & CommandBlockEntity = (cCommandBlockEntity &)a_BlockEntity;
|
||||
|
||||
Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this
|
||||
Writer.AddInt("SuccessCount", CommandBlockEntity.GetResult());
|
||||
Writer.AddInt("x", CommandBlockEntity.GetPosX());
|
||||
Writer.AddInt("y", CommandBlockEntity.GetPosY());
|
||||
Writer.AddInt("z", CommandBlockEntity.GetPosZ());
|
||||
Writer.AddString("Command", CommandBlockEntity.GetCommand().c_str());
|
||||
// You can set custom names for windows in Vanilla
|
||||
// For a command block, this would be the 'name' prepended to anything it outputs into global chat
|
||||
// MCS doesn't have this, so just leave it @ '@'. (geddit?)
|
||||
Writer.AddString("CustomName", "@");
|
||||
Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
|
||||
|
||||
if (!CommandBlockEntity.GetLastOutput().empty())
|
||||
{
|
||||
AString Output;
|
||||
Printf(Output, "{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str());
|
||||
|
||||
Writer.AddString("LastOutput", Output.c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
Writer.Finish();
|
||||
|
||||
AString Compressed;
|
||||
CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
|
||||
WriteShort(Compressed.size());
|
||||
WriteBuf(Compressed.data(), Compressed.size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol172::cPacketizer::WriteByteAngle(double a_Angle)
|
||||
{
|
||||
|
@ -102,6 +102,7 @@ public:
|
||||
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
|
||||
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override;
|
||||
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
|
||||
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override;
|
||||
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override;
|
||||
virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override;
|
||||
virtual void SendWeather (eWeather a_Weather) override;
|
||||
@ -189,6 +190,7 @@ protected:
|
||||
void WriteEntityMetadata(const cEntity & a_Entity); // Writes the metadata for the specified entity, not including the terminating 0x7f
|
||||
void WriteMobMetadata(const cMonster & a_Mob); // Writes the mob-specific metadata for the specified mob
|
||||
void WriteEntityProperties(const cEntity & a_Entity); // Writes the entity properties for the specified entity, including the Count field
|
||||
void WriteBlockEntity(const cBlockEntity & a_BlockEntity);
|
||||
|
||||
protected:
|
||||
cProtocol172 & m_Protocol;
|
||||
|
@ -636,6 +636,16 @@ void cProtocolRecognizer::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
|
||||
|
||||
|
||||
|
||||
void cProtocolRecognizer::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
|
||||
{
|
||||
ASSERT(m_Protocol != NULL);
|
||||
m_Protocol->SendUpdateBlockEntity(a_BlockEntity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocolRecognizer::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4)
|
||||
{
|
||||
ASSERT(m_Protocol != NULL);
|
||||
|
@ -114,6 +114,7 @@ public:
|
||||
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
|
||||
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override;
|
||||
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
|
||||
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override;
|
||||
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override;
|
||||
virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override;
|
||||
virtual void SendWeather (eWeather a_Weather) override;
|
||||
|
Loading…
Reference in New Issue
Block a user