summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Bindings/AllToLua.pkg1
-rw-r--r--src/ClientHandle.cpp12
-rw-r--r--src/ClientHandle.h4
-rw-r--r--src/CompositeChat.cpp206
-rw-r--r--src/CompositeChat.h172
-rw-r--r--src/Defines.h9
-rw-r--r--src/Entities/Player.h1
-rw-r--r--src/Protocol/Protocol.h2
-rw-r--r--src/Protocol/Protocol125.cpp38
-rw-r--r--src/Protocol/Protocol125.h1
-rw-r--r--src/Protocol/Protocol17x.cpp153
-rw-r--r--src/Protocol/Protocol17x.h38
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp10
-rw-r--r--src/Protocol/ProtocolRecognizer.h1
-rw-r--r--src/Root.cpp14
-rw-r--r--src/Root.h6
-rw-r--r--src/World.cpp20
-rw-r--r--src/World.h4
18 files changed, 671 insertions, 21 deletions
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index f65aed9bb..6c295102f 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -70,6 +70,7 @@ $cfile "../Generating/ChunkDesc.h"
$cfile "../CraftingRecipes.h"
$cfile "../UI/Window.h"
$cfile "../Mobs/Monster.h"
+$cfile "../CompositeChat.h"
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 1b3ebc3d4..f8a707324 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -31,6 +31,7 @@
#include "MersenneTwister.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;
@@ -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)
{
ASSERT(m_Player != NULL);
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index d9a86d983..034fe07c2 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -34,6 +34,7 @@ class cWindow;
class cFallingBlock;
class cItemHandler;
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 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 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 SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player);
void SendDestroyEntity (const cEntity & a_Entity);
diff --git a/src/CompositeChat.cpp b/src/CompositeChat.cpp
new file mode 100644
index 000000000..16ae58f56
--- /dev/null
+++ b/src/CompositeChat.cpp
@@ -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)
+{
+}
+
+
+
+
diff --git a/src/CompositeChat.h b/src/CompositeChat.h
new file mode 100644
index 000000000..e220f6345
--- /dev/null
+++ b/src/CompositeChat.h
@@ -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
+
+
+
+
diff --git a/src/Defines.h b/src/Defines.h
index 290f862ef..f33d1ae56 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -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
// MessageType...
@@ -458,7 +461,9 @@ enum ChatPrefixCodes
mtLeave, // A player has left the server
};
-// tolua_begin
+
+
+
/** Normalizes an angle in degrees to the [-180, +180) range: */
inline double NormalizeAngleDegrees(const double a_Degrees)
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 7db9544cb..53e4b56db 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -203,6 +203,7 @@ public:
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 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; }
void SetName(const AString & a_Name) { m_PlayerName = a_Name; }
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index 791082537..f5b9fd403 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -28,6 +28,7 @@ class cWorld;
class cMonster;
class cChunkDataSerializer;
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 SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) = 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 SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) = 0;
virtual void SendDestroyEntity (const cEntity & a_Entity) = 0;
diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp
index 73d21161c..7020699d1 100644
--- a/src/Protocol/Protocol125.cpp
+++ b/src/Protocol/Protocol125.cpp
@@ -32,6 +32,8 @@ Documentation:
#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)
{
cCSLock Lock(m_CSPacket);
diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h
index cd15ab518..1a3209333 100644
--- a/src/Protocol/Protocol125.h
+++ b/src/Protocol/Protocol125.h
@@ -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 SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) 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 SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override;
virtual void SendDestroyEntity (const cEntity & a_Entity) override;
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 7eaf106cf..5aa18300c 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -8,6 +8,7 @@ Implements the 1.7.x protocol classes:
*/
#include "Globals.h"
+#include "json/json.h"
#include "Protocol17x.h"
#include "ChunkDataSerializer.h"
#include "../ClientHandle.h"
@@ -25,6 +26,7 @@ Implements the 1.7.x protocol classes:
#include "../Mobs/IncludeAllMonsters.h"
#include "../UI/Window.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)
{
// 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:
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index 6a75e41c8..d19be0f05 100644
--- a/src/Protocol/Protocol17x.h
+++ b/src/Protocol/Protocol17x.h
@@ -36,6 +36,16 @@ Declares the 1.7.x protocol classes:
+// fwd:
+namespace Json
+{
+ class Value;
+}
+
+
+
+
+
class cProtocol172 :
public cProtocol
{
@@ -45,16 +55,17 @@ public:
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;
- /// 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 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 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 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 SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override;
virtual void SendDestroyEntity (const cEntity & a_Entity) override;
@@ -117,7 +128,7 @@ public:
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
{
public:
@@ -206,16 +217,16 @@ protected:
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;
- /// Buffer for the received data
+ /** Buffer for the received data */
cByteBuffer m_ReceivedData;
- /// Buffer for composing the outgoing packets, through cPacketizer
+ /** Buffer for composing the outgoing packets, through cPacketizer */
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;
bool m_IsEncrypted;
@@ -227,7 +238,7 @@ protected:
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);
/** Reads and handles the packet. The packet length and type have already been read.
@@ -268,21 +279,24 @@ protected:
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);
- /// 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;
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);
- /// 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 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);
} ;
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 32409c2aa..6e51ee9cd 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -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)
{
ASSERT(m_Protocol != NULL);
diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h
index f58c66d10..800163be6 100644
--- a/src/Protocol/ProtocolRecognizer.h
+++ b/src/Protocol/ProtocolRecognizer.h
@@ -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 SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) 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 SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override;
virtual void SendDestroyEntity (const cEntity & a_Entity) override;
diff --git a/src/Root.cpp b/src/Root.cpp
index 749fbd288..415a26dd3 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -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)
{
@@ -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)
{
for (WorldMap::iterator itr = m_WorldsByName.begin(), itr2 = itr; itr != m_WorldsByName.end(); itr = itr2)
diff --git a/src/Root.h b/src/Root.h
index 13e208b8d..a1a3ca6a2 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -20,7 +20,8 @@ class cPluginManager;
class cServer;
class cWorld;
class cPlayer;
-class cCommandOutputCallback ;
+class cCommandOutputCallback;
+class cCompositeChat;
typedef cItemCallback<cPlayer> cPlayerListCallback;
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
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 BroadcastChatLeave (const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtLeave); }
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 BroadcastChatWarning(const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtWarning); }
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
static AString GetProtocolVersionTextFromInt(int a_ProtocolVersionNum);
diff --git a/src/World.cpp b/src/World.cpp
index cb07caa5d..d1a13794c 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -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);
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)
{
m_ChunkMap->BroadcastChunkData(a_ChunkX, a_ChunkZ, a_Serializer, a_Exclude);
diff --git a/src/World.h b/src/World.h
index ca1b7dcc5..2fbc51038 100644
--- a/src/World.h
+++ b/src/World.h
@@ -46,6 +46,7 @@ class cDispenserEntity;
class cFurnaceEntity;
class cNoteEntity;
class cMobCensus;
+class cCompositeChat;
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 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); }
// 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 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 BroadcastChat (const cCompositeChat & a_Message, const cClientHandle * a_Exclude = NULL);
// tolua_end
void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL);