Implemented cCompositeChat.
This allows plugins to send composite chat messages, containing URLs, commands to run and cmdline suggestions. Fixes #678.master
parent
584f7bd806
commit
0f1f7583ae
|
@ -70,6 +70,7 @@ $cfile "../Generating/ChunkDesc.h"
|
|||
$cfile "../CraftingRecipes.h"
|
||||
$cfile "../UI/Window.h"
|
||||
$cfile "../Mobs/Monster.h"
|
||||
$cfile "../CompositeChat.h"
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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);
|
||||
} ;
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
14
src/Root.cpp
14
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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue