mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-04-23 07:27:20 +00:00
Add Chat Formatting Support For Servers (#1483)
* add chat support for html formatting * html character serialization, normal color format support * change for chat input handling on color has a bug where the text after the cursor gets stripped of its color, need to make a function to backstep on a string and find the last used color codes, or get all color codes used before the string is split, and apply them to the start of the next string * expose jukebox label as action bar like java * prevent players from sending chat color * restore non styled chat size check
This commit is contained in:
parent
bfcb621808
commit
14f8d793dd
|
|
@ -148,8 +148,7 @@ void ChatScreen::keyPressed(wchar_t ch, int eventKey)
|
|||
cursorIndex--;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAllowedChatChar(ch) && static_cast<int>(message.length()) < SharedConstants::maxChatLength)
|
||||
if (isAllowedChatChar(ch) && static_cast<int>(message.length()) < SharedConstants::maxVisibleLength)
|
||||
{
|
||||
message.insert(cursorIndex, 1, ch);
|
||||
cursorIndex++;
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@
|
|||
#include "..\Minecraft.World\DurangoStats.h"
|
||||
#include "..\Minecraft.World\GenericStats.h"
|
||||
#endif
|
||||
#include <regex>
|
||||
|
||||
ClientConnection::ClientConnection(Minecraft *minecraft, const wstring& ip, int port)
|
||||
{
|
||||
|
|
@ -1546,17 +1547,35 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
|
|||
bool replaceEntitySource = false;
|
||||
bool replaceItem = false;
|
||||
|
||||
static std::wregex IDS_Pattern(LR"(\{\*IDS_(\d+)\*\})"); //maybe theres a better way to do translateable IDS
|
||||
|
||||
int stringArgsSize = packet->m_stringArgs.size();
|
||||
|
||||
wstring playerDisplayName = L"";
|
||||
wstring sourceDisplayName = L"";
|
||||
|
||||
// On platforms other than Xbox One this just sets display name to gamertag
|
||||
if (packet->m_stringArgs.size() >= 1) playerDisplayName = GetDisplayNameByGamertag(packet->m_stringArgs[0]);
|
||||
if (packet->m_stringArgs.size() >= 2) sourceDisplayName = GetDisplayNameByGamertag(packet->m_stringArgs[1]);
|
||||
if (stringArgsSize >= 1) playerDisplayName = GetDisplayNameByGamertag(packet->m_stringArgs[0]);
|
||||
if (stringArgsSize >= 2) sourceDisplayName = GetDisplayNameByGamertag(packet->m_stringArgs[1]);
|
||||
|
||||
switch(packet->m_messageType)
|
||||
{
|
||||
case ChatPacket::e_ChatCustom:
|
||||
message = (packet->m_stringArgs.size() >= 1) ? packet->m_stringArgs[0] : L"";
|
||||
case ChatPacket::e_ChatActionBar:
|
||||
if (stringArgsSize >= 1) {
|
||||
message = packet->m_stringArgs[0];
|
||||
|
||||
std::wsmatch match;
|
||||
while (std::regex_search(message, match, IDS_Pattern)) {
|
||||
message = replaceAll(message, match[0], app.GetString(std::stoi(match[1].str())));
|
||||
}
|
||||
|
||||
message = app.EscapeHTMLString(message); //do this to enforce escaped string
|
||||
message = app.FormatChatMessage(message); //this needs to be last cause it converts colors to html colors that would have been escaped
|
||||
} else {
|
||||
message = L"empty message";
|
||||
}
|
||||
displayOnGui = (packet->m_messageType == ChatPacket::e_ChatCustom);
|
||||
break;
|
||||
case ChatPacket::e_ChatBedOccupied:
|
||||
message = app.GetString(IDS_TILE_BED_OCCUPIED);
|
||||
|
|
@ -1906,7 +1925,7 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
|
|||
|
||||
if(replacePlayer)
|
||||
{
|
||||
message = replaceAll(message,L"{*PLAYER*}",playerDisplayName);
|
||||
message = replaceAll(message,L"{*PLAYER*}", playerDisplayName);
|
||||
}
|
||||
|
||||
if(replaceEntitySource)
|
||||
|
|
@ -1941,7 +1960,9 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
|
|||
// flag that a message is a death message
|
||||
bool bIsDeathMessage = (packet->m_messageType>=ChatPacket::e_ChatDeathInFire) && (packet->m_messageType<=ChatPacket::e_ChatDeathIndirectMagicItem);
|
||||
|
||||
if( displayOnGui ) minecraft->gui->addMessage(message,m_userIndex, bIsDeathMessage);
|
||||
if( displayOnGui ) minecraft->gui->addMessage(message, m_userIndex, bIsDeathMessage);
|
||||
|
||||
if (!displayOnGui && !message.empty()) minecraft->gui->setActionBarMessage(message);
|
||||
}
|
||||
|
||||
void ClientConnection::handleAnimate(shared_ptr<AnimatePacket> packet)
|
||||
|
|
|
|||
|
|
@ -6595,6 +6595,87 @@ wstring CMinecraftApp::FormatHTMLString(int iPad, const wstring &desc, int shado
|
|||
return text;
|
||||
}
|
||||
|
||||
//found list of html escapes at https://stackoverflow.com/questions/7381974/which-characters-need-to-be-escaped-in-html
|
||||
wstring CMinecraftApp::EscapeHTMLString(const wstring& desc)
|
||||
{
|
||||
static std::unordered_map<wchar_t, wchar_t*> replacementMap = {
|
||||
{L'&', L"&"},
|
||||
{L'<', L"<"},
|
||||
{L'>', L">"},
|
||||
{L'\"', L"""},
|
||||
{L'\'', L"'"},
|
||||
};
|
||||
|
||||
wstring finalString = L"";
|
||||
for (int i = 0; i < desc.size(); i++) {
|
||||
wchar_t _char = desc[i];
|
||||
auto it = replacementMap.find(_char);
|
||||
|
||||
if (it != replacementMap.end()) finalString += it->second;
|
||||
else finalString += _char;
|
||||
}
|
||||
|
||||
return finalString;
|
||||
}
|
||||
|
||||
wstring CMinecraftApp::FormatChatMessage(const wstring& desc, bool applyColor)
|
||||
{
|
||||
static std::wstring_view colorFormatString = L"<font color=\"#%08x\" shadowcolor=\"#%08x\">";
|
||||
|
||||
wstring results = desc;
|
||||
wchar_t replacements[64];
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_0), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§0", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_1), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§1", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_2), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§2", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_3), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§3", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_4), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§4", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_5), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§5", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_6), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§6", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_7), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§7", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_8), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§8", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_9), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§9", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_a), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§a", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_b), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§b", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_c), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§c", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_d), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§d", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_e), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§e", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_f), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§f", replacements);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
wstring CMinecraftApp::GetActionReplacement(int iPad, unsigned char ucAction)
|
||||
{
|
||||
unsigned int input = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal(iPad) ,ucAction);
|
||||
|
|
|
|||
|
|
@ -564,7 +564,9 @@ public:
|
|||
int GetHTMLColour(eMinecraftColour colour);
|
||||
int GetHTMLColor(eMinecraftColour colour) { return GetHTMLColour(colour); }
|
||||
int GetHTMLFontSize(EHTMLFontSize size);
|
||||
wstring FormatHTMLString(int iPad, const wstring &desc, int shadowColour = 0xFFFFFFFF);
|
||||
wstring FormatHTMLString(int iPad, const wstring& desc, int shadowColour = 0xFFFFFFFF);
|
||||
wstring EscapeHTMLString(const wstring &desc);
|
||||
wstring FormatChatMessage(const wstring& desc, bool applyColor = true);
|
||||
wstring GetActionReplacement(int iPad, unsigned char ucAction);
|
||||
wstring GetVKReplacement(unsigned int uiVKey);
|
||||
wstring GetIconReplacement(unsigned int uiIcon);
|
||||
|
|
|
|||
|
|
@ -24,8 +24,10 @@ UIScene_HUD::UIScene_HUD(int iPad, void *initData, UILayer *parentLayer) : UISce
|
|||
for(unsigned int i = 0; i < CHAT_LINES_COUNT; ++i)
|
||||
{
|
||||
m_labelChatText[i].init(L"");
|
||||
IggyValueSetBooleanRS(m_labelChatText[i].getIggyValuePath(), 0, "m_bUseHtmlText", true);
|
||||
}
|
||||
m_labelJukebox.init(L"");
|
||||
IggyValueSetBooleanRS(m_labelJukebox.getIggyValuePath(), 0, "m_bUseHtmlText", true);
|
||||
|
||||
addTimer(0, 100);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ private:
|
|||
bool m_bSplitscreen;
|
||||
|
||||
protected:
|
||||
UIControl_Label m_labelChatText[CHAT_LINES_COUNT];
|
||||
UIControl_HTMLLabel m_labelChatText[CHAT_LINES_COUNT];
|
||||
UIControl_Label m_labelJukebox;
|
||||
UIControl m_controlLabelBackground[CHAT_LINES_COUNT];
|
||||
UIControl_Label m_labelDisplayName;
|
||||
|
|
|
|||
|
|
@ -1591,6 +1591,13 @@ float Gui::getOpacity(int iPad, DWORD index)
|
|||
return opacityPercentage;
|
||||
}
|
||||
|
||||
//just like java functionality it overwrites the jukebox label
|
||||
void Gui::setActionBarMessage(wstring message)
|
||||
{
|
||||
overlayMessageString = message;
|
||||
overlayMessageTime = 20 * 4; //idk how long it should last, need to check java usage
|
||||
}
|
||||
|
||||
float Gui::getJukeboxOpacity(int iPad)
|
||||
{
|
||||
float t = overlayMessageTime - lastTickA;
|
||||
|
|
@ -1606,7 +1613,7 @@ void Gui::setNowPlaying(const wstring& string)
|
|||
// overlayMessageString = L"Now playing: " + string;
|
||||
overlayMessageString = app.GetString(IDS_NOWPLAYING) + string;
|
||||
overlayMessageTime = 20 * 3;
|
||||
animateOverlayMessageColor = true;
|
||||
animateOverlayMessageColor = true; //appears to be unused, @DrPerkyLegit plans to add in later pr
|
||||
}
|
||||
|
||||
void Gui::displayClientMessage(int messageId, int iPad)
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ public:
|
|||
wstring getMessage(int iPad, DWORD index) { return guiMessages[iPad].at(index).string; }
|
||||
float getOpacity(int iPad, DWORD index);
|
||||
|
||||
void setActionBarMessage(wstring message); //uses jukebox label
|
||||
|
||||
wstring getJukeboxMessage(int iPad) { return overlayMessageString; }
|
||||
float getJukeboxOpacity(int iPad);
|
||||
|
||||
|
|
|
|||
|
|
@ -679,7 +679,7 @@ void PlayerConnection::handleChat(shared_ptr<ChatPacket> packet)
|
|||
return;
|
||||
}
|
||||
wstring formatted = L"<" + player->name + L"> " + message;
|
||||
server->getPlayers()->broadcastAll(shared_ptr<ChatPacket>(new ChatPacket(formatted)));
|
||||
server->getPlayers()->broadcastAll(shared_ptr<ChatPacket>(new ChatPacket(app.FormatChatMessage(formatted, false))));
|
||||
chatSpamTickCount += SharedConstants::TICKS_PER_SECOND;
|
||||
if (chatSpamTickCount > SharedConstants::TICKS_PER_SECOND * 10)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ public:
|
|||
e_ChatCommandTeleportMe,
|
||||
e_ChatCommandTeleportToMe,
|
||||
|
||||
e_ChatActionBar,
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ class SharedConstants
|
|||
static wstring readAcceptableChars();
|
||||
|
||||
public:
|
||||
static const int maxChatLength = 100;
|
||||
static const int maxChatLength = 255;
|
||||
static const int maxVisibleLength = 100; //to be changed
|
||||
static wstring acceptableLetters;
|
||||
|
||||
static const int ILLEGAL_FILE_CHARACTERS_LENGTH = 15;
|
||||
|
|
|
|||
Loading…
Reference in a new issue