From 973dcf6e3a3ea077ec1da5b70635a8d50dcbab69 Mon Sep 17 00:00:00 2001 From: DrPerkyLegit Date: Mon, 6 Apr 2026 22:21:44 -0400 Subject: [PATCH 1/6] add chat support for html formatting --- Minecraft.Client/ClientConnection.cpp | 30 ++++++++++++++++++---- Minecraft.Client/Common/UI/UIScene_HUD.cpp | 1 + Minecraft.Client/Common/UI/UIScene_HUD.h | 2 +- Minecraft.Client/PlayerConnection.cpp | 2 +- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/Minecraft.Client/ClientConnection.cpp b/Minecraft.Client/ClientConnection.cpp index a80af5d2c9..691b3d5765 100644 --- a/Minecraft.Client/ClientConnection.cpp +++ b/Minecraft.Client/ClientConnection.cpp @@ -65,6 +65,7 @@ #include "..\Minecraft.World\DurangoStats.h" #include "..\Minecraft.World\GenericStats.h" #endif +#include ClientConnection::ClientConnection(Minecraft *minecraft, const wstring& ip, int port) { @@ -1546,17 +1547,36 @@ void ClientConnection::handleChat(shared_ptr 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""; + if (stringArgsSize > 1) { + message = packet->m_stringArgs[0]; + + for (int i = 1; i < stringArgsSize; i++) { //skip the first string index, thats main message + message = replaceAll(message, L"{*ARGS_" + std::to_wstring(i) + L"*}", packet->m_stringArgs[i]); + } + + 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.FormatHTMLString(m_userIndex, message); + } else if (packet->m_stringArgs.size() == 1) { + message = (packet->m_stringArgs.size() >= 1) ? packet->m_stringArgs[0] : L""; + } break; case ChatPacket::e_ChatBedOccupied: message = app.GetString(IDS_TILE_BED_OCCUPIED); @@ -1906,7 +1926,7 @@ void ClientConnection::handleChat(shared_ptr packet) if(replacePlayer) { - message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + message = replaceAll(message,L"{*PLAYER*}", playerDisplayName); } if(replaceEntitySource) @@ -1941,7 +1961,7 @@ void ClientConnection::handleChat(shared_ptr 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); } void ClientConnection::handleAnimate(shared_ptr packet) diff --git a/Minecraft.Client/Common/UI/UIScene_HUD.cpp b/Minecraft.Client/Common/UI/UIScene_HUD.cpp index 213caa8dc6..06aea4fa27 100644 --- a/Minecraft.Client/Common/UI/UIScene_HUD.cpp +++ b/Minecraft.Client/Common/UI/UIScene_HUD.cpp @@ -23,6 +23,7 @@ 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""); diff --git a/Minecraft.Client/Common/UI/UIScene_HUD.h b/Minecraft.Client/Common/UI/UIScene_HUD.h index 04468c8ecd..caadb50afc 100644 --- a/Minecraft.Client/Common/UI/UIScene_HUD.h +++ b/Minecraft.Client/Common/UI/UIScene_HUD.h @@ -11,7 +11,7 @@ class UIScene_HUD : public UIScene, public IUIScene_HUD 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; diff --git a/Minecraft.Client/PlayerConnection.cpp b/Minecraft.Client/PlayerConnection.cpp index 1fb7c39888..546b77d825 100644 --- a/Minecraft.Client/PlayerConnection.cpp +++ b/Minecraft.Client/PlayerConnection.cpp @@ -678,7 +678,7 @@ void PlayerConnection::handleChat(shared_ptr packet) handleCommand(message); return; } - wstring formatted = L"<" + player->name + L"> " + message; + wstring formatted = L"<" + player->name + L"> " + message; server->getPlayers()->broadcastAll(shared_ptr(new ChatPacket(formatted))); chatSpamTickCount += SharedConstants::TICKS_PER_SECOND; if (chatSpamTickCount > SharedConstants::TICKS_PER_SECOND * 10) From af3df4c6363653c0ef303d326e0c92114210838d Mon Sep 17 00:00:00 2001 From: DrPerkyLegit Date: Thu, 9 Apr 2026 20:54:16 -0400 Subject: [PATCH 2/6] html character serialization, normal color format support --- Minecraft.Client/ClientConnection.cpp | 13 ++-- Minecraft.Client/Common/Consoles_App.cpp | 81 ++++++++++++++++++++++++ Minecraft.Client/Common/Consoles_App.h | 4 +- Minecraft.Client/PlayerConnection.cpp | 2 +- Minecraft.World/SharedConstants.h | 2 +- 5 files changed, 91 insertions(+), 11 deletions(-) diff --git a/Minecraft.Client/ClientConnection.cpp b/Minecraft.Client/ClientConnection.cpp index 691b3d5765..95b9d9fb26 100644 --- a/Minecraft.Client/ClientConnection.cpp +++ b/Minecraft.Client/ClientConnection.cpp @@ -1561,21 +1561,18 @@ void ClientConnection::handleChat(shared_ptr packet) switch(packet->m_messageType) { case ChatPacket::e_ChatCustom: - if (stringArgsSize > 1) { + if (stringArgsSize >= 1) { message = packet->m_stringArgs[0]; - for (int i = 1; i < stringArgsSize; i++) { //skip the first string index, thats main message - message = replaceAll(message, L"{*ARGS_" + std::to_wstring(i) + L"*}", packet->m_stringArgs[i]); - } - 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.FormatHTMLString(m_userIndex, message); - } else if (packet->m_stringArgs.size() == 1) { - message = (packet->m_stringArgs.size() >= 1) ? packet->m_stringArgs[0] : L""; + 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"; } break; case ChatPacket::e_ChatBedOccupied: diff --git a/Minecraft.Client/Common/Consoles_App.cpp b/Minecraft.Client/Common/Consoles_App.cpp index 0a2fd159a4..c736e545b6 100644 --- a/Minecraft.Client/Common/Consoles_App.cpp +++ b/Minecraft.Client/Common/Consoles_App.cpp @@ -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 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) +{ + static std::wstring_view colorFormatString = L""; + + wstring results = desc; + wchar_t replacements[64]; + + swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_0), 0xFFFFFFFF); + results = replaceAll(results, L"§0", replacements); + + swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_1), 0xFFFFFFFF); + results = replaceAll(results, L"§1", replacements); + + swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_2), 0xFFFFFFFF); + results = replaceAll(results, L"§2", replacements); + + swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_3), 0xFFFFFFFF); + results = replaceAll(results, L"§3", replacements); + + swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_4), 0xFFFFFFFF); + results = replaceAll(results, L"§4", replacements); + + swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_5), 0xFFFFFFFF); + results = replaceAll(results, L"§5", replacements); + + swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_6), 0xFFFFFFFF); + results = replaceAll(results, L"§6", replacements); + + swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_7), 0xFFFFFFFF); + results = replaceAll(results, L"§7", replacements); + + swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_8), 0xFFFFFFFF); + results = replaceAll(results, L"§8", replacements); + + swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_9), 0xFFFFFFFF); + results = replaceAll(results, L"§9", replacements); + + swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_a), 0xFFFFFFFF); + results = replaceAll(results, L"§a", replacements); + + swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_b), 0xFFFFFFFF); + results = replaceAll(results, L"§b", replacements); + + swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_c), 0xFFFFFFFF); + results = replaceAll(results, L"§c", replacements); + + swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_d), 0xFFFFFFFF); + results = replaceAll(results, L"§d", replacements); + + swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_e), 0xFFFFFFFF); + results = replaceAll(results, L"§e", replacements); + + swprintf(replacements, 64, colorFormatString.data(), 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); diff --git a/Minecraft.Client/Common/Consoles_App.h b/Minecraft.Client/Common/Consoles_App.h index 0c1c261efd..7634e59767 100644 --- a/Minecraft.Client/Common/Consoles_App.h +++ b/Minecraft.Client/Common/Consoles_App.h @@ -564,7 +564,9 @@ class CMinecraftApp 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); wstring GetActionReplacement(int iPad, unsigned char ucAction); wstring GetVKReplacement(unsigned int uiVKey); wstring GetIconReplacement(unsigned int uiIcon); diff --git a/Minecraft.Client/PlayerConnection.cpp b/Minecraft.Client/PlayerConnection.cpp index 546b77d825..1fb7c39888 100644 --- a/Minecraft.Client/PlayerConnection.cpp +++ b/Minecraft.Client/PlayerConnection.cpp @@ -678,7 +678,7 @@ void PlayerConnection::handleChat(shared_ptr packet) handleCommand(message); return; } - wstring formatted = L"<" + player->name + L"> " + message; + wstring formatted = L"<" + player->name + L"> " + message; server->getPlayers()->broadcastAll(shared_ptr(new ChatPacket(formatted))); chatSpamTickCount += SharedConstants::TICKS_PER_SECOND; if (chatSpamTickCount > SharedConstants::TICKS_PER_SECOND * 10) diff --git a/Minecraft.World/SharedConstants.h b/Minecraft.World/SharedConstants.h index a8924e47c0..0c91379cfb 100644 --- a/Minecraft.World/SharedConstants.h +++ b/Minecraft.World/SharedConstants.h @@ -20,7 +20,7 @@ class SharedConstants static wstring readAcceptableChars(); public: - static const int maxChatLength = 100; + static const int maxChatLength = 1024; static wstring acceptableLetters; static const int ILLEGAL_FILE_CHARACTERS_LENGTH = 15; From 2321135a1e08d4ab76f3c2ce15223b1a156917cd Mon Sep 17 00:00:00 2001 From: DrPerkyLegit Date: Fri, 10 Apr 2026 00:56:39 -0400 Subject: [PATCH 3/6] 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 --- Minecraft.Client/ChatScreen.cpp | 33 ++++++++++++++++++++++++++----- Minecraft.World/SharedConstants.h | 3 ++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/Minecraft.Client/ChatScreen.cpp b/Minecraft.Client/ChatScreen.cpp index 53c9072242..106095b363 100644 --- a/Minecraft.Client/ChatScreen.cpp +++ b/Minecraft.Client/ChatScreen.cpp @@ -17,6 +17,29 @@ bool ChatScreen::isAllowedChatChar(wchar_t c) return c >= 0x20 && (c == L'\u00A7' || allowedChars.empty() || allowedChars.find(c) != wstring::npos); } +int VisibleCharLength(wstring message) { + static std::unordered_set validStyleCharacters = { + L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', L'8', L'9', + L'a', L'b', L'c', L'd', L'e', L'f', + }; + int results = 0; + + + for (int i = 0; i < message.size(); i++) { + wchar_t _char = message[i]; + if (_char == L'§' && (i + 1) < message.size()) { + wchar_t colorChar = message[i + 1]; + if (validStyleCharacters.find(colorChar) != validStyleCharacters.end()) { + i++; //do this so it increments 2 instead of 1 + continue; + } + } + results++; + } + + return results; +} + ChatScreen::ChatScreen() { frame = 0; @@ -131,7 +154,7 @@ void ChatScreen::keyPressed(wchar_t ch, int eventKey) cursorIndex--; return; } - if (isAllowedChatChar(ch) && static_cast(message.length()) < SharedConstants::maxChatLength) + if (isAllowedChatChar(ch) && VisibleCharLength(message) < SharedConstants::maxVisibleLength) { message.insert(cursorIndex, 1, ch); cursorIndex++; @@ -147,12 +170,12 @@ void ChatScreen::render(int xm, int ym, float a) x += font->width(prefix); wstring beforeCursor = message.substr(0, cursorIndex); wstring afterCursor = message.substr(cursorIndex); - drawStringLiteral(font, beforeCursor, x, height - 12, 0xe0e0e0); - x += font->widthLiteral(beforeCursor); + drawString(font, beforeCursor, x, height - 12, 0xe0e0e0); + x += font->width(beforeCursor); if (frame / 6 % 2 == 0) - drawString(font, L"_", x, height - 12, 0xe0e0e0); + drawString(font, L"_", x, height - 12, 0xe0e0e0); //todo: fix this breaking the chat color in afterString x += font->width(L"_"); - drawStringLiteral(font, afterCursor, x, height - 12, 0xe0e0e0); + drawString(font, afterCursor, x, height - 12, 0xe0e0e0); Screen::render(xm, ym, a); } diff --git a/Minecraft.World/SharedConstants.h b/Minecraft.World/SharedConstants.h index 0c91379cfb..c4db88ae81 100644 --- a/Minecraft.World/SharedConstants.h +++ b/Minecraft.World/SharedConstants.h @@ -20,7 +20,8 @@ class SharedConstants static wstring readAcceptableChars(); public: - static const int maxChatLength = 1024; + static const int maxChatLength = 255; + static const int maxVisibleLength = 100; //to be changed static wstring acceptableLetters; static const int ILLEGAL_FILE_CHARACTERS_LENGTH = 15; From 1bbc90c18bda390464a5c94736b038b0a17d18e6 Mon Sep 17 00:00:00 2001 From: DrPerkyLegit Date: Fri, 10 Apr 2026 16:38:27 -0400 Subject: [PATCH 4/6] expose jukebox label as action bar like java --- Minecraft.Client/ClientConnection.cpp | 4 ++++ Minecraft.Client/Common/UI/UIScene_HUD.cpp | 1 + Minecraft.Client/Gui.cpp | 9 ++++++++- Minecraft.Client/Gui.h | 2 ++ Minecraft.World/ChatPacket.h | 1 + 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Minecraft.Client/ClientConnection.cpp b/Minecraft.Client/ClientConnection.cpp index 95b9d9fb26..603c8a0799 100644 --- a/Minecraft.Client/ClientConnection.cpp +++ b/Minecraft.Client/ClientConnection.cpp @@ -1561,6 +1561,7 @@ void ClientConnection::handleChat(shared_ptr packet) switch(packet->m_messageType) { case ChatPacket::e_ChatCustom: + case ChatPacket::e_ChatActionBar: if (stringArgsSize >= 1) { message = packet->m_stringArgs[0]; @@ -1574,6 +1575,7 @@ void ClientConnection::handleChat(shared_ptr packet) } else { message = L"empty message"; } + displayOnGui = (packet->m_messageType == ChatPacket::e_ChatCustom); break; case ChatPacket::e_ChatBedOccupied: message = app.GetString(IDS_TILE_BED_OCCUPIED); @@ -1959,6 +1961,8 @@ void ClientConnection::handleChat(shared_ptr packet) 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 && !message.empty()) minecraft->gui->setActionBarMessage(message); } void ClientConnection::handleAnimate(shared_ptr packet) diff --git a/Minecraft.Client/Common/UI/UIScene_HUD.cpp b/Minecraft.Client/Common/UI/UIScene_HUD.cpp index 06aea4fa27..4c8c66df42 100644 --- a/Minecraft.Client/Common/UI/UIScene_HUD.cpp +++ b/Minecraft.Client/Common/UI/UIScene_HUD.cpp @@ -26,6 +26,7 @@ UIScene_HUD::UIScene_HUD(int iPad, void *initData, UILayer *parentLayer) : UISce IggyValueSetBooleanRS(m_labelChatText[i].getIggyValuePath(), 0, "m_bUseHtmlText", true); } m_labelJukebox.init(L""); + IggyValueSetBooleanRS(m_labelJukebox.getIggyValuePath(), 0, "m_bUseHtmlText", true); addTimer(0, 100); } diff --git a/Minecraft.Client/Gui.cpp b/Minecraft.Client/Gui.cpp index 5e3a954fe3..103bfb7bf1 100644 --- a/Minecraft.Client/Gui.cpp +++ b/Minecraft.Client/Gui.cpp @@ -1575,6 +1575,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; @@ -1590,7 +1597,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) diff --git a/Minecraft.Client/Gui.h b/Minecraft.Client/Gui.h index 64b8dfbe8e..5397823bc4 100644 --- a/Minecraft.Client/Gui.h +++ b/Minecraft.Client/Gui.h @@ -63,6 +63,8 @@ class Gui : public GuiComponent 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); diff --git a/Minecraft.World/ChatPacket.h b/Minecraft.World/ChatPacket.h index ea9b38061d..7ffebc5e05 100644 --- a/Minecraft.World/ChatPacket.h +++ b/Minecraft.World/ChatPacket.h @@ -98,6 +98,7 @@ class ChatPacket : public Packet, public enable_shared_from_this e_ChatCommandTeleportMe, e_ChatCommandTeleportToMe, + e_ChatActionBar, }; public: From 7eef3b6069dd402c175d048291be542a423238de Mon Sep 17 00:00:00 2001 From: DrPerkyLegit Date: Fri, 10 Apr 2026 18:31:04 -0400 Subject: [PATCH 5/6] prevent players from sending chat color --- Minecraft.Client/ChatScreen.cpp | 8 +++--- Minecraft.Client/Common/Consoles_App.cpp | 34 ++++++++++++------------ Minecraft.Client/Common/Consoles_App.h | 2 +- Minecraft.Client/PlayerConnection.cpp | 2 +- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Minecraft.Client/ChatScreen.cpp b/Minecraft.Client/ChatScreen.cpp index 106095b363..dc62d0c43d 100644 --- a/Minecraft.Client/ChatScreen.cpp +++ b/Minecraft.Client/ChatScreen.cpp @@ -170,12 +170,12 @@ void ChatScreen::render(int xm, int ym, float a) x += font->width(prefix); wstring beforeCursor = message.substr(0, cursorIndex); wstring afterCursor = message.substr(cursorIndex); - drawString(font, beforeCursor, x, height - 12, 0xe0e0e0); - x += font->width(beforeCursor); + drawStringLiteral(font, beforeCursor, x, height - 12, 0xe0e0e0); + x += font->widthLiteral(beforeCursor); if (frame / 6 % 2 == 0) - drawString(font, L"_", x, height - 12, 0xe0e0e0); //todo: fix this breaking the chat color in afterString + drawString(font, L"_", x, height - 12, 0xe0e0e0); x += font->width(L"_"); - drawString(font, afterCursor, x, height - 12, 0xe0e0e0); + drawStringLiteral(font, afterCursor, x, height - 12, 0xe0e0e0); Screen::render(xm, ym, a); } diff --git a/Minecraft.Client/Common/Consoles_App.cpp b/Minecraft.Client/Common/Consoles_App.cpp index c736e545b6..21b032cef6 100644 --- a/Minecraft.Client/Common/Consoles_App.cpp +++ b/Minecraft.Client/Common/Consoles_App.cpp @@ -6618,59 +6618,59 @@ wstring CMinecraftApp::EscapeHTMLString(const wstring& desc) return finalString; } -wstring CMinecraftApp::FormatChatMessage(const wstring& desc) +wstring CMinecraftApp::FormatChatMessage(const wstring& desc, bool applyColor) { static std::wstring_view colorFormatString = L""; wstring results = desc; wchar_t replacements[64]; - swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_0), 0xFFFFFFFF); + swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_0), 0xFFFFFFFF); results = replaceAll(results, L"§0", replacements); - swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_1), 0xFFFFFFFF); + swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_1), 0xFFFFFFFF); results = replaceAll(results, L"§1", replacements); - swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_2), 0xFFFFFFFF); + swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_2), 0xFFFFFFFF); results = replaceAll(results, L"§2", replacements); - swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_3), 0xFFFFFFFF); + swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_3), 0xFFFFFFFF); results = replaceAll(results, L"§3", replacements); - swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_4), 0xFFFFFFFF); + swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_4), 0xFFFFFFFF); results = replaceAll(results, L"§4", replacements); - swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_5), 0xFFFFFFFF); + swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_5), 0xFFFFFFFF); results = replaceAll(results, L"§5", replacements); - swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_6), 0xFFFFFFFF); + swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_6), 0xFFFFFFFF); results = replaceAll(results, L"§6", replacements); - swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_7), 0xFFFFFFFF); + swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_7), 0xFFFFFFFF); results = replaceAll(results, L"§7", replacements); - swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_8), 0xFFFFFFFF); + swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_8), 0xFFFFFFFF); results = replaceAll(results, L"§8", replacements); - swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_9), 0xFFFFFFFF); + swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_9), 0xFFFFFFFF); results = replaceAll(results, L"§9", replacements); - swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_a), 0xFFFFFFFF); + swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_a), 0xFFFFFFFF); results = replaceAll(results, L"§a", replacements); - swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_b), 0xFFFFFFFF); + swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_b), 0xFFFFFFFF); results = replaceAll(results, L"§b", replacements); - swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_c), 0xFFFFFFFF); + swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_c), 0xFFFFFFFF); results = replaceAll(results, L"§c", replacements); - swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_d), 0xFFFFFFFF); + swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_d), 0xFFFFFFFF); results = replaceAll(results, L"§d", replacements); - swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_e), 0xFFFFFFFF); + swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_e), 0xFFFFFFFF); results = replaceAll(results, L"§e", replacements); - swprintf(replacements, 64, colorFormatString.data(), GetHTMLColour(eHTMLColor_f), 0xFFFFFFFF); + swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_f), 0xFFFFFFFF); results = replaceAll(results, L"§f", replacements); return results; diff --git a/Minecraft.Client/Common/Consoles_App.h b/Minecraft.Client/Common/Consoles_App.h index 7634e59767..eb59ded893 100644 --- a/Minecraft.Client/Common/Consoles_App.h +++ b/Minecraft.Client/Common/Consoles_App.h @@ -566,7 +566,7 @@ class CMinecraftApp int GetHTMLFontSize(EHTMLFontSize size); wstring FormatHTMLString(int iPad, const wstring& desc, int shadowColour = 0xFFFFFFFF); wstring EscapeHTMLString(const wstring &desc); - wstring FormatChatMessage(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); diff --git a/Minecraft.Client/PlayerConnection.cpp b/Minecraft.Client/PlayerConnection.cpp index 1fb7c39888..b23b699947 100644 --- a/Minecraft.Client/PlayerConnection.cpp +++ b/Minecraft.Client/PlayerConnection.cpp @@ -679,7 +679,7 @@ void PlayerConnection::handleChat(shared_ptr packet) return; } wstring formatted = L"<" + player->name + L"> " + message; - server->getPlayers()->broadcastAll(shared_ptr(new ChatPacket(formatted))); + server->getPlayers()->broadcastAll(shared_ptr(new ChatPacket(app.FormatChatMessage(formatted, false)))); chatSpamTickCount += SharedConstants::TICKS_PER_SECOND; if (chatSpamTickCount > SharedConstants::TICKS_PER_SECOND * 10) { From 15989a9ef61b581f37e8474b504d19fbaf914596 Mon Sep 17 00:00:00 2001 From: DrPerkyLegit Date: Fri, 10 Apr 2026 18:36:14 -0400 Subject: [PATCH 6/6] restore non styled chat size check --- Minecraft.Client/ChatScreen.cpp | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/Minecraft.Client/ChatScreen.cpp b/Minecraft.Client/ChatScreen.cpp index dc62d0c43d..fffa1562fb 100644 --- a/Minecraft.Client/ChatScreen.cpp +++ b/Minecraft.Client/ChatScreen.cpp @@ -17,29 +17,6 @@ bool ChatScreen::isAllowedChatChar(wchar_t c) return c >= 0x20 && (c == L'\u00A7' || allowedChars.empty() || allowedChars.find(c) != wstring::npos); } -int VisibleCharLength(wstring message) { - static std::unordered_set validStyleCharacters = { - L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', L'8', L'9', - L'a', L'b', L'c', L'd', L'e', L'f', - }; - int results = 0; - - - for (int i = 0; i < message.size(); i++) { - wchar_t _char = message[i]; - if (_char == L'§' && (i + 1) < message.size()) { - wchar_t colorChar = message[i + 1]; - if (validStyleCharacters.find(colorChar) != validStyleCharacters.end()) { - i++; //do this so it increments 2 instead of 1 - continue; - } - } - results++; - } - - return results; -} - ChatScreen::ChatScreen() { frame = 0; @@ -154,7 +131,7 @@ void ChatScreen::keyPressed(wchar_t ch, int eventKey) cursorIndex--; return; } - if (isAllowedChatChar(ch) && VisibleCharLength(message) < SharedConstants::maxVisibleLength) + if (isAllowedChatChar(ch) && static_cast(message.length()) < SharedConstants::maxVisibleLength) { message.insert(cursorIndex, 1, ch); cursorIndex++;