1
0

Implemented cCompositeChat.

This allows plugins to send composite chat messages, containing URLs, commands to run and cmdline suggestions.
Fixes #678.
This commit is contained in:
madmaxoft 2014-02-15 23:16:44 +01:00
parent 584f7bd806
commit 0f1f7583ae
18 changed files with 671 additions and 21 deletions

View File

@ -70,6 +70,7 @@ $cfile "../Generating/ChunkDesc.h"
$cfile "../CraftingRecipes.h" $cfile "../CraftingRecipes.h"
$cfile "../UI/Window.h" $cfile "../UI/Window.h"
$cfile "../Mobs/Monster.h" $cfile "../Mobs/Monster.h"
$cfile "../CompositeChat.h"

View File

@ -31,6 +31,7 @@
#include "MersenneTwister.h" #include "MersenneTwister.h"
#include "Protocol/ProtocolRecognizer.h" #include "Protocol/ProtocolRecognizer.h"
#include "CompositeChat.h"
@ -1729,7 +1730,7 @@ void cClientHandle::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlock
void cClientHandle::SendChat(const AString & a_Message, ChatPrefixCodes a_ChatPrefix, const AString & a_AdditionalData) void cClientHandle::SendChat(const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData)
{ {
bool ShouldAppendChatPrefixes = true; bool ShouldAppendChatPrefixes = true;
@ -1840,6 +1841,15 @@ void cClientHandle::SendChat(const AString & a_Message, ChatPrefixCodes a_ChatPr
void cClientHandle::SendChat(const cCompositeChat & a_Message)
{
m_Protocol->SendChat(a_Message);
}
void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer)
{ {
ASSERT(m_Player != NULL); ASSERT(m_Player != NULL);

View File

@ -34,6 +34,7 @@ class cWindow;
class cFallingBlock; class cFallingBlock;
class cItemHandler; class cItemHandler;
class cWorld; class cWorld;
class cCompositeChat;
@ -89,7 +90,8 @@ public:
void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage); void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage);
void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); // tolua_export void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); // tolua_export
void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes); void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes);
void SendChat (const AString & a_Message, ChatPrefixCodes a_ChatPrefix, const AString & a_AdditionalData = ""); void SendChat (const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData = "");
void SendChat (const cCompositeChat & a_Message);
void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer); void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer);
void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player); void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player);
void SendDestroyEntity (const cEntity & a_Entity); void SendDestroyEntity (const cEntity & a_Entity);

206
src/CompositeChat.cpp Normal file
View File

@ -0,0 +1,206 @@
// CompositeChat.cpp
// Implements the cCompositeChat class used to wrap a chat message with multiple parts (text, url, cmd)
#include "Globals.h"
#include "CompositeChat.h"
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cCompositeChat:
cCompositeChat::cCompositeChat(void) :
m_MessageType(mtCustom)
{
}
cCompositeChat::cCompositeChat(const AString & a_ParseText) :
m_MessageType(mtCustom)
{
ParseText(a_ParseText);
}
cCompositeChat::~cCompositeChat()
{
Clear();
}
void cCompositeChat::Clear(void)
{
for (cParts::iterator itr = m_Parts.begin(), end = m_Parts.end(); itr != end; ++itr)
{
delete *itr;
} // for itr - m_Parts[]
m_Parts.clear();
}
void cCompositeChat::AddTextPart(const AString & a_Message, const AString & a_Style)
{
m_Parts.push_back(new cTextPart(a_Message, a_Style));
}
void cCompositeChat::AddClientTranslatedPart(const AString & a_TranslationID, const AStringVector & a_Parameters, const AString & a_Style)
{
m_Parts.push_back(new cClientTranslatedPart(a_TranslationID, a_Parameters, a_Style));
}
void cCompositeChat::AddUrlPart(const AString & a_Text, const AString & a_Url, const AString & a_Style)
{
m_Parts.push_back(new cUrlPart(a_Text, a_Url, a_Style));
}
void cCompositeChat::AddRunCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style)
{
m_Parts.push_back(new cRunCommandPart(a_Text, a_Command, a_Style));
}
void cCompositeChat::AddSuggestCommandPart(const AString & a_Text, const AString & a_SuggestedCommand, const AString & a_Style)
{
m_Parts.push_back(new cSuggestCommandPart(a_Text, a_SuggestedCommand, a_Style));
}
void cCompositeChat::ParseText(const AString & a_ParseText)
{
// TODO
}
void cCompositeChat::SetMessageType(eMessageType a_MessageType)
{
m_MessageType = a_MessageType;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cCompositeChat::cBasePart:
cCompositeChat::cBasePart::cBasePart(cCompositeChat::ePartType a_PartType, const AString & a_Text, const AString & a_Style) :
m_PartType(a_PartType),
m_Text(a_Text),
m_Style(a_Style)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cCompositeChat::cTextPart:
cCompositeChat::cTextPart::cTextPart(const AString & a_Text, const AString &a_Style) :
super(ptText, a_Text, a_Style)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cCompositeChat::cClientTranslatedPart:
cCompositeChat::cClientTranslatedPart::cClientTranslatedPart(const AString & a_TranslationID, const AStringVector & a_Parameters, const AString & a_Style) :
super(ptClientTranslated, a_TranslationID, a_Style),
m_Parameters(a_Parameters)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cCompositeChat::cUrlPart:
cCompositeChat::cUrlPart::cUrlPart(const AString & a_Text, const AString & a_Url, const AString & a_Style) :
super(ptUrl, a_Text, a_Style),
m_Url(a_Url)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cCompositeChat::cCommandPart:
cCompositeChat::cCommandPart::cCommandPart(ePartType a_PartType, const AString & a_Text, const AString & a_Command, const AString & a_Style) :
super(a_PartType, a_Text, a_Style),
m_Command(a_Command)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cCompositeChat::cRunCommandPart:
cCompositeChat::cRunCommandPart::cRunCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style) :
super(ptRunCommand, a_Text, a_Command, a_Style)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cCompositeChat::cSuggestCommandPart:
cCompositeChat::cSuggestCommandPart::cSuggestCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style) :
super(ptSuggestCommand, a_Text, a_Command, a_Style)
{
}

172
src/CompositeChat.h Normal file
View File

@ -0,0 +1,172 @@
// CompositeChat.h
// Declares the cCompositeChat class used to wrap a chat message with multiple parts (text, url, cmd)
#include "Defines.h"
// tolua_begin
/** Container for a single chat message composed of multiple functional parts.
Each part corresponds roughly to the behavior supported by the client messaging:
- plain text, optionaly colorized / styled
- clickable URLs
- clickable commands (run)
- clickable commands (suggest)
Each part has a text assigned to it that can be styled. The style is specified using a string,
each character / character combination in the string specifies the style to use:
- b = bold
- i = italic
- u = underlined
- s = strikethrough
- o = obfuscated
- @X = color X (X is 0 - 9 or a - f, same as dye meta
If the protocol version doesn't support all the features, it degrades gracefully.
*/
class cCompositeChat
{
public:
// tolua_end
enum ePartType
{
ptText,
ptClientTranslated,
ptUrl,
ptRunCommand,
ptSuggestCommand,
} ;
class cBasePart
{
public:
ePartType m_PartType;
AString m_Text;
AString m_Style;
cBasePart(ePartType a_PartType, const AString & a_Text, const AString & a_Style = "");
} ;
class cTextPart :
public cBasePart
{
typedef cBasePart super;
public:
cTextPart(const AString & a_Text, const AString & a_Style = "");
} ;
class cClientTranslatedPart :
public cBasePart
{
typedef cBasePart super;
public:
AStringVector m_Parameters;
cClientTranslatedPart(const AString & a_TranslationID, const AStringVector & a_Parameters, const AString & a_Style = "");
} ;
class cUrlPart :
public cBasePart
{
typedef cBasePart super;
public:
AString m_Url;
cUrlPart(const AString & a_Text, const AString & a_Url, const AString & a_Style = "");
} ;
class cCommandPart :
public cBasePart
{
typedef cBasePart super;
public:
AString m_Command;
cCommandPart(ePartType a_PartType, const AString & a_Text, const AString & a_Command, const AString & a_Style = "");
} ;
class cRunCommandPart :
public cCommandPart
{
typedef cCommandPart super;
public:
cRunCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style = "");
} ;
class cSuggestCommandPart :
public cCommandPart
{
typedef cCommandPart super;
public:
cSuggestCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style = "");
} ;
typedef std::vector<cBasePart *> cParts;
// tolua_begin
/** Creates a new empty chat message */
cCompositeChat(void);
/** Creates a new chat message and parses the text into parts.
Recognizes "http:" and "https:" links and @color-codes.
Uses ParseText() for the actual parsing. */
cCompositeChat(const AString & a_ParseText);
~cCompositeChat();
/** Removes all parts from the object. */
void Clear(void);
/** Adds a plain text part, with optional style.
The default style is plain white text. */
void AddTextPart(const AString & a_Message, const AString & a_Style = "");
// tolua_end
/** Adds a part that is translated client-side, with the formatting parameters and optional style.
Exported in ManualBindings due to AStringVector usage - Lua uses an array-table of strings. */
void AddClientTranslatedPart(const AString & a_TranslationID, const AStringVector & a_Parameters, const AString & a_Style = "");
// tolua_begin
/** Adds a part that opens an URL when clicked.
The default style is underlined light blue text. */
void AddUrlPart(const AString & a_Text, const AString & a_Url, const AString & a_Style = "u@c");
/** Adds a part that runs a command when clicked.
The default style is underlined light green text. */
void AddRunCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style = "u@a");
/** Adds a part that suggests a command (enters it into the chat message area, but doesn't send) when clicked.
The default style is underlined yellow text. */
void AddSuggestCommandPart(const AString & a_Text, const AString & a_SuggestedCommand, const AString & a_Style = "u@b");
/** Parses text into various parts, adds those.
Recognizes "http:" and "https:" URLs and @color-codes. */
void ParseText(const AString & a_ParseText);
/** Sets the message type, which is indicated by prefixes added to the message when serializing. */
void SetMessageType(eMessageType a_MessageType);
/** Returns the message type set previously by SetMessageType(). */
eMessageType GetMessageType(void) const { return m_MessageType; }
// tolua_end
const cParts & GetParts(void) const { return m_Parts; }
protected:
/** All the parts that */
cParts m_Parts;
/** The message type, as indicated by prefixes. */
eMessageType m_MessageType;
} ; // tolua_export

View File

@ -441,7 +441,10 @@ inline float GetSpecialSignf( float a_Val )
enum ChatPrefixCodes
// tolua_begin
enum eMessageType
{ {
// http://forum.mc-server.org/showthread.php?tid=1212 // http://forum.mc-server.org/showthread.php?tid=1212
// MessageType... // MessageType...
@ -458,7 +461,9 @@ enum ChatPrefixCodes
mtLeave, // A player has left the server mtLeave, // A player has left the server
}; };
// tolua_begin
/** Normalizes an angle in degrees to the [-180, +180) range: */ /** Normalizes an angle in degrees to the [-180, +180) range: */
inline double NormalizeAngleDegrees(const double a_Degrees) inline double NormalizeAngleDegrees(const double a_Degrees)

View File

@ -203,6 +203,7 @@ public:
void SendMessageWarning (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtWarning); } void SendMessageWarning (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtWarning); }
void SendMessageFatal (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtFailure); } void SendMessageFatal (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtFailure); }
void SendMessagePrivateMsg(const AString & a_Message, const AString & a_Sender) { m_ClientHandle->SendChat(a_Message, mtPrivateMessage, a_Sender); } void SendMessagePrivateMsg(const AString & a_Message, const AString & a_Sender) { m_ClientHandle->SendChat(a_Message, mtPrivateMessage, a_Sender); }
void SendMessage (const cCompositeChat & a_Message) { m_ClientHandle->SendChat(a_Message); }
const AString & GetName(void) const { return m_PlayerName; } const AString & GetName(void) const { return m_PlayerName; }
void SetName(const AString & a_Name) { m_PlayerName = a_Name; } void SetName(const AString & a_Name) { m_PlayerName = a_Name; }

View File

@ -28,6 +28,7 @@ class cWorld;
class cMonster; class cMonster;
class cChunkDataSerializer; class cChunkDataSerializer;
class cFallingBlock; class cFallingBlock;
class cCompositeChat;
@ -58,6 +59,7 @@ public:
virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0;
virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) = 0; virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) = 0;
virtual void SendChat (const AString & a_Message) = 0; virtual void SendChat (const AString & a_Message) = 0;
virtual void SendChat (const cCompositeChat & a_Message) = 0;
virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) = 0; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) = 0;
virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) = 0; virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) = 0;
virtual void SendDestroyEntity (const cEntity & a_Entity) = 0; virtual void SendDestroyEntity (const cEntity & a_Entity) = 0;

View File

@ -32,6 +32,8 @@ Documentation:
#include "../Mobs/IncludeAllMonsters.h" #include "../Mobs/IncludeAllMonsters.h"
#include "../CompositeChat.h"
@ -233,6 +235,42 @@ void cProtocol125::SendChat(const AString & a_Message)
void cProtocol125::SendChat(const cCompositeChat & a_Message)
{
// This version doesn't support composite messages, just extract each part's text and use it:
AString Msg;
const cCompositeChat::cParts & Parts = a_Message.GetParts();
for (cCompositeChat::cParts::const_iterator itr = Parts.begin(), end = Parts.end(); itr != end; ++itr)
{
switch ((*itr)->m_PartType)
{
case cCompositeChat::ptText:
case cCompositeChat::ptClientTranslated:
case cCompositeChat::ptRunCommand:
case cCompositeChat::ptSuggestCommand:
{
Msg.append((*itr)->m_Text);
break;
}
case cCompositeChat::ptUrl:
{
Msg.append(((cCompositeChat::cUrlPart *)(*itr))->m_Url);
break;
}
} // switch (PartType)
} // for itr - Parts[]
// Send the message:
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_CHAT);
WriteString(Msg);
Flush();
}
void cProtocol125::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) void cProtocol125::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer)
{ {
cCSLock Lock(m_CSPacket); cCSLock Lock(m_CSPacket);

View File

@ -33,6 +33,7 @@ public:
virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override; virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override;
virtual void SendChat (const AString & a_Message) override; virtual void SendChat (const AString & a_Message) override;
virtual void SendChat (const cCompositeChat & a_Message) override;
virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override;
virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override; virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override;
virtual void SendDestroyEntity (const cEntity & a_Entity) override; virtual void SendDestroyEntity (const cEntity & a_Entity) override;

View File

@ -8,6 +8,7 @@ Implements the 1.7.x protocol classes:
*/ */
#include "Globals.h" #include "Globals.h"
#include "json/json.h"
#include "Protocol17x.h" #include "Protocol17x.h"
#include "ChunkDataSerializer.h" #include "ChunkDataSerializer.h"
#include "../ClientHandle.h" #include "../ClientHandle.h"
@ -25,6 +26,7 @@ Implements the 1.7.x protocol classes:
#include "../Mobs/IncludeAllMonsters.h" #include "../Mobs/IncludeAllMonsters.h"
#include "../UI/Window.h" #include "../UI/Window.h"
#include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/CommandBlockEntity.h"
#include "../CompositeChat.h"
@ -200,6 +202,78 @@ void cProtocol172::SendChat(const AString & a_Message)
void cProtocol172::SendChat(const cCompositeChat & a_Message)
{
// Compose the complete Json string to send:
Json::Value msg;
msg["text"] = ""; // The client crashes without this
const cCompositeChat::cParts & Parts = a_Message.GetParts();
for (cCompositeChat::cParts::const_iterator itr = Parts.begin(), end = Parts.end(); itr != end; ++itr)
{
Json::Value Part;
switch ((*itr)->m_PartType)
{
case cCompositeChat::ptText:
{
Part["text"] = (*itr)->m_Text;
AddChatPartStyle(Part, (*itr)->m_Style);
break;
}
case cCompositeChat::ptClientTranslated:
{
const cCompositeChat::cClientTranslatedPart & p = (const cCompositeChat::cClientTranslatedPart &)**itr;
Part["translate"] = p.m_Text;
Json::Value With;
for (AStringVector::const_iterator itrW = p.m_Parameters.begin(), endW = p.m_Parameters.end(); itrW != endW; ++itr)
{
With.append(*itrW);
}
if (!p.m_Parameters.empty())
{
Part["with"] = With;
}
AddChatPartStyle(Part, p.m_Style);
break;
}
case cCompositeChat::ptUrl:
{
const cCompositeChat::cUrlPart & p = (const cCompositeChat::cUrlPart &)**itr;
Part["text"] = p.m_Text;
Json::Value Url;
Url["action"] = "open_url";
Url["value"] = p.m_Url;
Part["clickEvent"] = Url;
AddChatPartStyle(Part, p.m_Style);
break;
}
case cCompositeChat::ptSuggestCommand:
case cCompositeChat::ptRunCommand:
{
const cCompositeChat::cCommandPart & p = (const cCompositeChat::cCommandPart &)**itr;
Part["text"] = p.m_Text;
Json::Value Cmd;
Cmd["action"] = (p.m_PartType == cCompositeChat::ptRunCommand) ? "run_command" : "suggest_command";
Cmd["value"] = p.m_Command;
Part["clickEvent"] = Cmd;
AddChatPartStyle(Part, p.m_Style);
break;
}
}
msg["extra"].append(Part);
} // for itr - Parts[]
// Send the message to the client:
cPacketizer Pkt(*this, 0x02);
Pkt.WriteString(msg.toStyledString());
}
void cProtocol172::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) void cProtocol172::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer)
{ {
// Serialize first, before creating the Packetizer (the packetizer locks a CS) // Serialize first, before creating the Packetizer (the packetizer locks a CS)
@ -1979,6 +2053,85 @@ void cProtocol172::StartEncryption(const Byte * a_Key)
void cProtocol172::AddChatPartStyle(Json::Value & a_Value, const AString & a_PartStyle)
{
size_t len = a_PartStyle.length();
for (size_t i = 0; i < len; i++)
{
switch (a_PartStyle[i])
{
case 'b':
{
// bold
a_Value["bold"] = Json::Value(true);
break;
}
case 'i':
{
// italic
a_Value["italic"] = Json::Value(true);
break;
}
case 'u':
{
// Underlined
a_Value["underlined"] = Json::Value(true);
break;
}
case 's':
{
// strikethrough
a_Value["strikethrough"] = Json::Value(true);
break;
}
case 'o':
{
// obfuscated
a_Value["obfuscated"] = Json::Value(true);
break;
}
case '@':
{
// Color, specified by the next char:
i++;
if (i >= len)
{
// String too short, didn't contain a color
break;
}
switch (a_PartStyle[i])
{
case '0': a_Value["color"] = Json::Value("black"); break;
case '1': a_Value["color"] = Json::Value("dark_blue"); break;
case '2': a_Value["color"] = Json::Value("dark_green"); break;
case '3': a_Value["color"] = Json::Value("dark_aqua"); break;
case '4': a_Value["color"] = Json::Value("dark_red"); break;
case '5': a_Value["color"] = Json::Value("dark_purple"); break;
case '6': a_Value["color"] = Json::Value("gold"); break;
case '7': a_Value["color"] = Json::Value("gray"); break;
case '8': a_Value["color"] = Json::Value("dark_gray"); break;
case '9': a_Value["color"] = Json::Value("blue"); break;
case 'a': a_Value["color"] = Json::Value("green"); break;
case 'b': a_Value["color"] = Json::Value("aqua"); break;
case 'c': a_Value["color"] = Json::Value("red"); break;
case 'd': a_Value["color"] = Json::Value("light_purple"); break;
case 'e': a_Value["color"] = Json::Value("yellow"); break;
case 'f': a_Value["color"] = Json::Value("white"); break;
} // switch (color)
} // case '@'
} // switch (Style[i])
} // for i - a_PartStyle[]
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cProtocol172::cPacketizer: // cProtocol172::cPacketizer:

View File

@ -36,6 +36,16 @@ Declares the 1.7.x protocol classes:
// fwd:
namespace Json
{
class Value;
}
class cProtocol172 : class cProtocol172 :
public cProtocol public cProtocol
{ {
@ -45,16 +55,17 @@ public:
cProtocol172(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State); cProtocol172(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State);
/// Called when client sends some data: /** Called when client sends some data: */
virtual void DataReceived(const char * a_Data, int a_Size) override; virtual void DataReceived(const char * a_Data, int a_Size) override;
/// Sending stuff to clients (alphabetically sorted): /** Sending stuff to clients (alphabetically sorted): */
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override; virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override; virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override;
virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override; virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override;
virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override; virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override;
virtual void SendChat (const AString & a_Message) override; virtual void SendChat (const AString & a_Message) override;
virtual void SendChat (const cCompositeChat & a_Message) override;
virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override;
virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override; virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override;
virtual void SendDestroyEntity (const cEntity & a_Entity) override; virtual void SendDestroyEntity (const cEntity & a_Entity) override;
@ -117,7 +128,7 @@ public:
protected: protected:
/// Composes individual packets in the protocol's m_OutPacketBuffer; sends them upon being destructed /** Composes individual packets in the protocol's m_OutPacketBuffer; sends them upon being destructed */
class cPacketizer class cPacketizer
{ {
public: public:
@ -206,16 +217,16 @@ protected:
AString m_AuthServerID; AString m_AuthServerID;
/// State of the protocol. 1 = status, 2 = login, 3 = game /** State of the protocol. 1 = status, 2 = login, 3 = game */
UInt32 m_State; UInt32 m_State;
/// Buffer for the received data /** Buffer for the received data */
cByteBuffer m_ReceivedData; cByteBuffer m_ReceivedData;
/// Buffer for composing the outgoing packets, through cPacketizer /** Buffer for composing the outgoing packets, through cPacketizer */
cByteBuffer m_OutPacketBuffer; cByteBuffer m_OutPacketBuffer;
/// Buffer for composing packet length (so that each cPacketizer instance doesn't allocate a new cPacketBuffer) /** Buffer for composing packet length (so that each cPacketizer instance doesn't allocate a new cPacketBuffer) */
cByteBuffer m_OutPacketLenBuffer; cByteBuffer m_OutPacketLenBuffer;
bool m_IsEncrypted; bool m_IsEncrypted;
@ -227,7 +238,7 @@ protected:
cFile m_CommLogFile; cFile m_CommLogFile;
/// Adds the received (unencrypted) data to m_ReceivedData, parses complete packets /** Adds the received (unencrypted) data to m_ReceivedData, parses complete packets */
void AddReceivedData(const char * a_Data, int a_Size); void AddReceivedData(const char * a_Data, int a_Size);
/** Reads and handles the packet. The packet length and type have already been read. /** Reads and handles the packet. The packet length and type have already been read.
@ -268,21 +279,24 @@ protected:
void HandlePacketWindowClose (cByteBuffer & a_ByteBuffer); void HandlePacketWindowClose (cByteBuffer & a_ByteBuffer);
/// Writes an entire packet into the output stream. a_Packet is expected to start with the packet type; data length is prepended here. /** Writes an entire packet into the output stream. a_Packet is expected to start with the packet type; data length is prepended here. */
void WritePacket(cByteBuffer & a_Packet); void WritePacket(cByteBuffer & a_Packet);
/// Sends the data to the client, encrypting them if needed. /** Sends the data to the client, encrypting them if needed. */
virtual void SendData(const char * a_Data, int a_Size) override; virtual void SendData(const char * a_Data, int a_Size) override;
void SendCompass(const cWorld & a_World); void SendCompass(const cWorld & a_World);
/// Reads an item out of the received data, sets a_Item to the values read. Returns false if not enough received data /** Reads an item out of the received data, sets a_Item to the values read. Returns false if not enough received data */
bool ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item); bool ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item);
/// Parses item metadata as read by ReadItem(), into the item enchantments. /** Parses item metadata as read by ReadItem(), into the item enchantments. */
void ParseItemMetadata(cItem & a_Item, const AString & a_Metadata); void ParseItemMetadata(cItem & a_Item, const AString & a_Metadata);
void StartEncryption(const Byte * a_Key); void StartEncryption(const Byte * a_Key);
/** Adds the chat part's style (represented by the part's stylestring) into the Json object. */
void AddChatPartStyle(Json::Value & a_Value, const AString & a_PartStyle);
} ; } ;

View File

@ -159,6 +159,16 @@ void cProtocolRecognizer::SendChat(const AString & a_Message)
void cProtocolRecognizer::SendChat(const cCompositeChat & a_Message)
{
ASSERT(m_Protocol != NULL);
m_Protocol->SendChat(a_Message);
}
void cProtocolRecognizer::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) void cProtocolRecognizer::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer)
{ {
ASSERT(m_Protocol != NULL); ASSERT(m_Protocol != NULL);

View File

@ -68,6 +68,7 @@ public:
virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override; virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override;
virtual void SendChat (const AString & a_Message) override; virtual void SendChat (const AString & a_Message) override;
virtual void SendChat (const cCompositeChat & a_Message) override;
virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override;
virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override; virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override;
virtual void SendDestroyEntity (const cEntity & a_Entity) override; virtual void SendDestroyEntity (const cEntity & a_Entity) override;

View File

@ -543,7 +543,7 @@ void cRoot::ReloadGroups(void)
void cRoot::LoopWorldsAndBroadcastChat(const AString & a_Message, ChatPrefixCodes a_ChatPrefix) void cRoot::LoopWorldsAndBroadcastChat(const AString & a_Message, eMessageType a_ChatPrefix)
{ {
for (WorldMap::iterator itr = m_WorldsByName.begin(), end = m_WorldsByName.end(); itr != end; ++itr) for (WorldMap::iterator itr = m_WorldsByName.begin(), end = m_WorldsByName.end(); itr != end; ++itr)
{ {
@ -555,6 +555,18 @@ void cRoot::LoopWorldsAndBroadcastChat(const AString & a_Message, ChatPrefixCode
void cRoot::BroadcastChat(const cCompositeChat & a_Message)
{
for (WorldMap::iterator itr = m_WorldsByName.begin(), end = m_WorldsByName.end(); itr != end; ++itr)
{
itr->second->BroadcastChat(a_Message);
} // for itr - m_WorldsByName[]
}
bool cRoot::ForEachPlayer(cPlayerListCallback & a_Callback) bool cRoot::ForEachPlayer(cPlayerListCallback & a_Callback)
{ {
for (WorldMap::iterator itr = m_WorldsByName.begin(), itr2 = itr; itr != m_WorldsByName.end(); itr = itr2) for (WorldMap::iterator itr = m_WorldsByName.begin(), itr2 = itr; itr != m_WorldsByName.end(); itr = itr2)

View File

@ -20,7 +20,8 @@ class cPluginManager;
class cServer; class cServer;
class cWorld; class cWorld;
class cPlayer; class cPlayer;
class cCommandOutputCallback ; class cCommandOutputCallback;
class cCompositeChat;
typedef cItemCallback<cPlayer> cPlayerListCallback; typedef cItemCallback<cPlayer> cPlayerListCallback;
typedef cItemCallback<cWorld> cWorldListCallback; typedef cItemCallback<cWorld> cWorldListCallback;
@ -108,7 +109,7 @@ public:
/// Finds a player from a partial or complete player name and calls the callback - case-insensitive /// Finds a player from a partial or complete player name and calls the callback - case-insensitive
bool FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << bool FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
void LoopWorldsAndBroadcastChat(const AString & a_Message, ChatPrefixCodes a_ChatPrefix); void LoopWorldsAndBroadcastChat(const AString & a_Message, eMessageType a_ChatPrefix);
void BroadcastChatJoin (const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtJoin); } void BroadcastChatJoin (const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtJoin); }
void BroadcastChatLeave (const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtLeave); } void BroadcastChatLeave (const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtLeave); }
void BroadcastChatDeath (const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtDeath); } void BroadcastChatDeath (const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtDeath); }
@ -122,6 +123,7 @@ public:
void BroadcastChatSuccess(const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtSuccess); } void BroadcastChatSuccess(const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtSuccess); }
void BroadcastChatWarning(const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtWarning); } void BroadcastChatWarning(const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtWarning); }
void BroadcastChatFatal (const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtFailure); } void BroadcastChatFatal (const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtFailure); }
void BroadcastChat (const cCompositeChat & a_Message);
/// Returns the textual description of the protocol version: 49 -> "1.4.4". Provided specifically for Lua API /// Returns the textual description of the protocol version: 49 -> "1.4.4". Provided specifically for Lua API
static AString GetProtocolVersionTextFromInt(int a_ProtocolVersionNum); static AString GetProtocolVersionTextFromInt(int a_ProtocolVersionNum);

View File

@ -1747,7 +1747,7 @@ void cWorld::BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cons
void cWorld::LoopPlayersAndBroadcastChat(const AString & a_Message, ChatPrefixCodes a_ChatPrefix, const cClientHandle * a_Exclude) void cWorld::LoopPlayersAndBroadcastChat(const AString & a_Message, eMessageType a_ChatPrefix, const cClientHandle * a_Exclude)
{ {
cCSLock Lock(m_CSPlayers); cCSLock Lock(m_CSPlayers);
for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
@ -1765,6 +1765,24 @@ void cWorld::LoopPlayersAndBroadcastChat(const AString & a_Message, ChatPrefixCo
void cWorld::BroadcastChat(const cCompositeChat & a_Message, const cClientHandle * a_Exclude)
{
cCSLock Lock(m_CSPlayers);
for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
cClientHandle * ch = (*itr)->GetClientHandle();
if ((ch == a_Exclude) || (ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed())
{
continue;
}
ch->SendChat(a_Message);
}
}
void cWorld::BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude) void cWorld::BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude)
{ {
m_ChunkMap->BroadcastChunkData(a_ChunkX, a_ChunkZ, a_Serializer, a_Exclude); m_ChunkMap->BroadcastChunkData(a_ChunkX, a_ChunkZ, a_Serializer, a_Exclude);

View File

@ -46,6 +46,7 @@ class cDispenserEntity;
class cFurnaceEntity; class cFurnaceEntity;
class cNoteEntity; class cNoteEntity;
class cMobCensus; class cMobCensus;
class cCompositeChat;
typedef std::list< cPlayer * > cPlayerList; typedef std::list< cPlayer * > cPlayerList;
@ -167,7 +168,7 @@ public:
void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = NULL); void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = NULL);
void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); ///< If there is a block entity at the specified coods, sends it to all clients except a_Exclude void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); ///< If there is a block entity at the specified coods, sends it to all clients except a_Exclude
void LoopPlayersAndBroadcastChat(const AString & a_Message, ChatPrefixCodes a_ChatPrefix, const cClientHandle * a_Exclude = NULL); void LoopPlayersAndBroadcastChat(const AString & a_Message, eMessageType a_ChatPrefix, const cClientHandle * a_Exclude = NULL);
void BroadcastChatDeath (const AString & a_Message, const cClientHandle * a_Exclude = NULL) { LoopPlayersAndBroadcastChat(a_Message, mtDeath, a_Exclude); } void BroadcastChatDeath (const AString & a_Message, const cClientHandle * a_Exclude = NULL) { LoopPlayersAndBroadcastChat(a_Message, mtDeath, a_Exclude); }
// tolua_begin // tolua_begin
@ -177,6 +178,7 @@ public:
void BroadcastChatSuccess(const AString & a_Message, const cClientHandle * a_Exclude = NULL) { LoopPlayersAndBroadcastChat(a_Message, mtSuccess, a_Exclude); } void BroadcastChatSuccess(const AString & a_Message, const cClientHandle * a_Exclude = NULL) { LoopPlayersAndBroadcastChat(a_Message, mtSuccess, a_Exclude); }
void BroadcastChatWarning(const AString & a_Message, const cClientHandle * a_Exclude = NULL) { LoopPlayersAndBroadcastChat(a_Message, mtWarning, a_Exclude); } void BroadcastChatWarning(const AString & a_Message, const cClientHandle * a_Exclude = NULL) { LoopPlayersAndBroadcastChat(a_Message, mtWarning, a_Exclude); }
void BroadcastChatFatal (const AString & a_Message, const cClientHandle * a_Exclude = NULL) { LoopPlayersAndBroadcastChat(a_Message, mtFailure, a_Exclude); } void BroadcastChatFatal (const AString & a_Message, const cClientHandle * a_Exclude = NULL) { LoopPlayersAndBroadcastChat(a_Message, mtFailure, a_Exclude); }
void BroadcastChat (const cCompositeChat & a_Message, const cClientHandle * a_Exclude = NULL);
// tolua_end // tolua_end
void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL); void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL);