Add Chat / Pastes / Formatting (#682)
* Initial fixes for ContainerSetSlotPacket and CraftItemPacket * Chat: paste, history, § formatting, 1-9 block when open (Windows64) Made-with: Cursor * static_cast refactor
This commit is contained in:
@@ -1,14 +1,27 @@
|
|||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "ChatScreen.h"
|
#include "ChatScreen.h"
|
||||||
|
#include "ClientConnection.h"
|
||||||
|
#include "Font.h"
|
||||||
#include "MultiplayerLocalPlayer.h"
|
#include "MultiplayerLocalPlayer.h"
|
||||||
#include "..\Minecraft.World\SharedConstants.h"
|
#include "..\Minecraft.World\SharedConstants.h"
|
||||||
#include "..\Minecraft.World\StringHelpers.h"
|
#include "..\Minecraft.World\StringHelpers.h"
|
||||||
|
#include "..\Minecraft.World\ChatPacket.h"
|
||||||
|
|
||||||
const wstring ChatScreen::allowedChars = SharedConstants::acceptableLetters;
|
const wstring ChatScreen::allowedChars = SharedConstants::acceptableLetters;
|
||||||
|
vector<wstring> ChatScreen::s_chatHistory;
|
||||||
|
int ChatScreen::s_historyIndex = -1;
|
||||||
|
wstring ChatScreen::s_historyDraft;
|
||||||
|
|
||||||
|
bool ChatScreen::isAllowedChatChar(wchar_t c)
|
||||||
|
{
|
||||||
|
return c >= 0x20 && (c == L'\u00A7' || allowedChars.empty() || allowedChars.find(c) != wstring::npos);
|
||||||
|
}
|
||||||
|
|
||||||
ChatScreen::ChatScreen()
|
ChatScreen::ChatScreen()
|
||||||
{
|
{
|
||||||
frame = 0;
|
frame = 0;
|
||||||
|
cursorIndex = 0;
|
||||||
|
s_historyIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatScreen::init()
|
void ChatScreen::init()
|
||||||
@@ -24,6 +37,50 @@ void ChatScreen::removed()
|
|||||||
void ChatScreen::tick()
|
void ChatScreen::tick()
|
||||||
{
|
{
|
||||||
frame++;
|
frame++;
|
||||||
|
if (cursorIndex > static_cast<int>(message.length()))
|
||||||
|
cursorIndex = static_cast<int>(message.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatScreen::handlePasteRequest()
|
||||||
|
{
|
||||||
|
wstring pasted = Screen::getClipboard();
|
||||||
|
for (size_t i = 0; i < pasted.length() && static_cast<int>(message.length()) < SharedConstants::maxChatLength; i++)
|
||||||
|
{
|
||||||
|
if (isAllowedChatChar(pasted[i]))
|
||||||
|
{
|
||||||
|
message.insert(cursorIndex, 1, pasted[i]);
|
||||||
|
cursorIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatScreen::applyHistoryMessage()
|
||||||
|
{
|
||||||
|
message = s_historyIndex >= 0 ? s_chatHistory[s_historyIndex] : s_historyDraft;
|
||||||
|
cursorIndex = static_cast<int>(message.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatScreen::handleHistoryUp()
|
||||||
|
{
|
||||||
|
if (s_chatHistory.empty()) return;
|
||||||
|
if (s_historyIndex == -1)
|
||||||
|
{
|
||||||
|
s_historyDraft = message;
|
||||||
|
s_historyIndex = static_cast<int>(s_chatHistory.size()) - 1;
|
||||||
|
}
|
||||||
|
else if (s_historyIndex > 0)
|
||||||
|
s_historyIndex--;
|
||||||
|
applyHistoryMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatScreen::handleHistoryDown()
|
||||||
|
{
|
||||||
|
if (s_chatHistory.empty()) return;
|
||||||
|
if (s_historyIndex < static_cast<int>(s_chatHistory.size()) - 1)
|
||||||
|
s_historyIndex++;
|
||||||
|
else
|
||||||
|
s_historyIndex = -1;
|
||||||
|
applyHistoryMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatScreen::keyPressed(wchar_t ch, int eventKey)
|
void ChatScreen::keyPressed(wchar_t ch, int eventKey)
|
||||||
@@ -35,31 +92,67 @@ void ChatScreen::keyPressed(wchar_t ch, int eventKey)
|
|||||||
}
|
}
|
||||||
if (eventKey == Keyboard::KEY_RETURN)
|
if (eventKey == Keyboard::KEY_RETURN)
|
||||||
{
|
{
|
||||||
wstring msg = trimString(message);
|
wstring trim = trimString(message);
|
||||||
if (msg.length() > 0)
|
if (trim.length() > 0)
|
||||||
{
|
{
|
||||||
wstring trim = trimString(message);
|
|
||||||
if (!minecraft->handleClientSideCommand(trim))
|
if (!minecraft->handleClientSideCommand(trim))
|
||||||
{
|
{
|
||||||
minecraft->player->chat(trim);
|
MultiplayerLocalPlayer* mplp = dynamic_cast<MultiplayerLocalPlayer*>(minecraft->player.get());
|
||||||
|
if (mplp && mplp->connection)
|
||||||
|
mplp->connection->send(shared_ptr<ChatPacket>(new ChatPacket(trim)));
|
||||||
|
}
|
||||||
|
if (s_chatHistory.empty() || s_chatHistory.back() != trim)
|
||||||
|
{
|
||||||
|
s_chatHistory.push_back(trim);
|
||||||
|
if (s_chatHistory.size() > CHAT_HISTORY_MAX)
|
||||||
|
s_chatHistory.erase(s_chatHistory.begin());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
minecraft->setScreen(NULL);
|
minecraft->setScreen(NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (eventKey == Keyboard::KEY_BACK && message.length() > 0) message = message.substr(0, message.length() - 1);
|
if (eventKey == Keyboard::KEY_UP) { handleHistoryUp(); return; }
|
||||||
if (allowedChars.find(ch) >= 0 && message.length() < SharedConstants::maxChatLength)
|
if (eventKey == Keyboard::KEY_DOWN) { handleHistoryDown(); return; }
|
||||||
|
if (eventKey == Keyboard::KEY_LEFT)
|
||||||
{
|
{
|
||||||
message += ch;
|
if (cursorIndex > 0)
|
||||||
|
cursorIndex--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (eventKey == Keyboard::KEY_RIGHT)
|
||||||
|
{
|
||||||
|
if (cursorIndex < static_cast<int>(message.length()))
|
||||||
|
cursorIndex++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (eventKey == Keyboard::KEY_BACK && cursorIndex > 0)
|
||||||
|
{
|
||||||
|
message.erase(cursorIndex - 1, 1);
|
||||||
|
cursorIndex--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isAllowedChatChar(ch) && static_cast<int>(message.length()) < SharedConstants::maxChatLength)
|
||||||
|
{
|
||||||
|
message.insert(cursorIndex, 1, ch);
|
||||||
|
cursorIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatScreen::render(int xm, int ym, float a)
|
void ChatScreen::render(int xm, int ym, float a)
|
||||||
{
|
{
|
||||||
fill(2, height - 14, width - 2, height - 2, 0x80000000);
|
fill(2, height - 14, width - 2, height - 2, 0x80000000);
|
||||||
drawString(font, L"> " + message + (frame / 6 % 2 == 0 ? L"_" : L""), 4, height - 12, 0xe0e0e0);
|
const wstring prefix = L"> ";
|
||||||
|
int x = 4;
|
||||||
|
drawString(font, prefix, x, height - 12, 0xe0e0e0);
|
||||||
|
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);
|
||||||
|
if (frame / 6 % 2 == 0)
|
||||||
|
drawString(font, L"_", x, height - 12, 0xe0e0e0);
|
||||||
|
x += font->width(L"_");
|
||||||
|
drawStringLiteral(font, afterCursor, x, height - 12, 0xe0e0e0);
|
||||||
Screen::render(xm, ym, a);
|
Screen::render(xm, ym, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,13 +164,15 @@ void ChatScreen::mouseClicked(int x, int y, int buttonNum)
|
|||||||
{
|
{
|
||||||
if (message.length() > 0 && message[message.length()-1]!=L' ')
|
if (message.length() > 0 && message[message.length()-1]!=L' ')
|
||||||
{
|
{
|
||||||
message += L" ";
|
message = message.substr(0, cursorIndex) + L" " + message.substr(cursorIndex);
|
||||||
|
cursorIndex++;
|
||||||
}
|
}
|
||||||
message += minecraft->gui->selectedName;
|
size_t nameLen = minecraft->gui->selectedName.length();
|
||||||
unsigned int maxLength = SharedConstants::maxChatLength;
|
size_t insertLen = (message.length() + nameLen <= SharedConstants::maxChatLength) ? nameLen : (SharedConstants::maxChatLength - message.length());
|
||||||
if (message.length() > maxLength)
|
if (insertLen > 0)
|
||||||
{
|
{
|
||||||
message = message.substr(0, maxLength);
|
message = message.substr(0, cursorIndex) + minecraft->gui->selectedName.substr(0, insertLen) + message.substr(cursorIndex);
|
||||||
|
cursorIndex += static_cast<int>(insertLen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -85,5 +180,4 @@ void ChatScreen::mouseClicked(int x, int y, int buttonNum)
|
|||||||
Screen::mouseClicked(x, y, buttonNum);
|
Screen::mouseClicked(x, y, buttonNum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,21 +1,33 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Screen.h"
|
#include "Screen.h"
|
||||||
|
#include <vector>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
class ChatScreen : public Screen
|
class ChatScreen : public Screen
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
wstring message;
|
wstring message;
|
||||||
|
int cursorIndex;
|
||||||
|
void applyHistoryMessage();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int frame;
|
int frame;
|
||||||
|
static const size_t CHAT_HISTORY_MAX = 100;
|
||||||
|
static std::vector<wstring> s_chatHistory;
|
||||||
|
static int s_historyIndex;
|
||||||
|
static wstring s_historyDraft;
|
||||||
|
static const wstring allowedChars;
|
||||||
|
static bool isAllowedChatChar(wchar_t c);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ChatScreen(); //4J added
|
ChatScreen();
|
||||||
virtual void init();
|
virtual void init();
|
||||||
virtual void removed();
|
virtual void removed();
|
||||||
virtual void tick();
|
virtual void tick();
|
||||||
private:
|
virtual void handlePasteRequest();
|
||||||
static const wstring allowedChars;
|
virtual void handleHistoryUp();
|
||||||
|
virtual void handleHistoryDown();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void keyPressed(wchar_t ch, int eventKey);
|
void keyPressed(wchar_t ch, int eventKey);
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -1441,6 +1441,9 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
|
|||||||
|
|
||||||
switch(packet->m_messageType)
|
switch(packet->m_messageType)
|
||||||
{
|
{
|
||||||
|
case ChatPacket::e_ChatCustom:
|
||||||
|
message = (packet->m_stringArgs.size() >= 1) ? packet->m_stringArgs[0] : L"";
|
||||||
|
break;
|
||||||
case ChatPacket::e_ChatBedOccupied:
|
case ChatPacket::e_ChatBedOccupied:
|
||||||
message = app.GetString(IDS_TILE_BED_OCCUPIED);
|
message = app.GetString(IDS_TILE_BED_OCCUPIED);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -55,10 +55,16 @@ void UIComponent_Chat::handleTimerComplete(int id)
|
|||||||
float opacity = pGui->getOpacity(m_iPad, i);
|
float opacity = pGui->getOpacity(m_iPad, i);
|
||||||
if( opacity > 0 )
|
if( opacity > 0 )
|
||||||
{
|
{
|
||||||
|
#ifdef _WINDOWS64
|
||||||
|
// Chat drawn by Gui::render with color codes. Hides Iggy chat to avoid double chats.
|
||||||
|
m_controlLabelBackground[i].setOpacity(0);
|
||||||
|
m_labelChatText[i].setOpacity(0);
|
||||||
|
m_labelChatText[i].setLabel(L"");
|
||||||
|
#else
|
||||||
m_controlLabelBackground[i].setOpacity(opacity);
|
m_controlLabelBackground[i].setOpacity(opacity);
|
||||||
m_labelChatText[i].setOpacity(opacity);
|
m_labelChatText[i].setOpacity(opacity);
|
||||||
m_labelChatText[i].setLabel( pGui->getMessage(m_iPad,i) );
|
m_labelChatText[i].setLabel( pGui->getMessage(m_iPad,i) );
|
||||||
|
#endif
|
||||||
anyVisible = true;
|
anyVisible = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -753,10 +753,16 @@ void UIScene_HUD::handleTimerComplete(int id)
|
|||||||
float opacity = pGui->getOpacity(m_iPad, i);
|
float opacity = pGui->getOpacity(m_iPad, i);
|
||||||
if( opacity > 0 )
|
if( opacity > 0 )
|
||||||
{
|
{
|
||||||
|
#ifdef _WINDOWS64
|
||||||
|
// Chat drawn by Gui::render with color codes. Hides Iggy chat to avoid double chats.
|
||||||
|
m_controlLabelBackground[i].setOpacity(0);
|
||||||
|
m_labelChatText[i].setOpacity(0);
|
||||||
|
m_labelChatText[i].setLabel(L"");
|
||||||
|
#else
|
||||||
m_controlLabelBackground[i].setOpacity(opacity);
|
m_controlLabelBackground[i].setOpacity(opacity);
|
||||||
m_labelChatText[i].setOpacity(opacity);
|
m_labelChatText[i].setOpacity(opacity);
|
||||||
m_labelChatText[i].setLabel( pGui->getMessagesCount(m_iPad) ? pGui->getMessage(m_iPad,i) : L"" );
|
m_labelChatText[i].setLabel( pGui->getMessagesCount(m_iPad) ? pGui->getMessage(m_iPad,i) : L"" );
|
||||||
|
#endif
|
||||||
anyVisible = true;
|
anyVisible = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ Font::Font(Options *options, const wstring& name, Textures* textures, bool enfor
|
|||||||
enforceUnicodeSheet = false;
|
enforceUnicodeSheet = false;
|
||||||
bidirectional = false;
|
bidirectional = false;
|
||||||
xPos = yPos = 0.0f;
|
xPos = yPos = 0.0f;
|
||||||
|
m_bold = false;
|
||||||
|
m_italic = false;
|
||||||
|
m_underline = false;
|
||||||
|
m_strikethrough = false;
|
||||||
|
|
||||||
// Set up member variables
|
// Set up member variables
|
||||||
m_cols = cols;
|
m_cols = cols;
|
||||||
@@ -126,6 +130,22 @@ Font::~Font()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void Font::renderStyleLine(float x0, float y0, float x1, float y1)
|
||||||
|
{
|
||||||
|
Tesselator* t = Tesselator::getInstance();
|
||||||
|
float u = 0.0f, v = 0.0f;
|
||||||
|
t->begin();
|
||||||
|
t->tex(u, v);
|
||||||
|
t->vertex(x0, y1, 0.0f);
|
||||||
|
t->tex(u, v);
|
||||||
|
t->vertex(x1, y1, 0.0f);
|
||||||
|
t->tex(u, v);
|
||||||
|
t->vertex(x1, y0, 0.0f);
|
||||||
|
t->tex(u, v);
|
||||||
|
t->vertex(x0, y0, 0.0f);
|
||||||
|
t->end();
|
||||||
|
}
|
||||||
|
|
||||||
void Font::renderCharacter(wchar_t c)
|
void Font::renderCharacter(wchar_t c)
|
||||||
{
|
{
|
||||||
float xOff = c % m_cols * m_charWidth;
|
float xOff = c % m_cols * m_charWidth;
|
||||||
@@ -137,37 +157,47 @@ void Font::renderCharacter(wchar_t c)
|
|||||||
float fontWidth = m_cols * m_charWidth;
|
float fontWidth = m_cols * m_charWidth;
|
||||||
float fontHeight = m_rows * m_charHeight;
|
float fontHeight = m_rows * m_charHeight;
|
||||||
|
|
||||||
Tesselator *t = Tesselator::getInstance();
|
const float shear = m_italic ? (height * 0.25f) : 0.0f;
|
||||||
// 4J Stu - Changed to a quad so that we can use within a command buffer
|
float x0 = xPos, x1 = xPos + width + shear;
|
||||||
#if 1
|
float y0 = yPos, y1 = yPos + height;
|
||||||
|
|
||||||
|
Tesselator *t = Tesselator::getInstance();
|
||||||
t->begin();
|
t->begin();
|
||||||
t->tex(xOff / fontWidth, (yOff + 7.99f) / fontHeight);
|
t->tex(xOff / fontWidth, (yOff + 7.99f) / fontHeight);
|
||||||
t->vertex(xPos, yPos + height, 0.0f);
|
t->vertex(x0, y1, 0.0f);
|
||||||
|
|
||||||
t->tex((xOff + width) / fontWidth, (yOff + 7.99f) / fontHeight);
|
t->tex((xOff + width) / fontWidth, (yOff + 7.99f) / fontHeight);
|
||||||
t->vertex(xPos + width, yPos + height, 0.0f);
|
t->vertex(x1, y1, 0.0f);
|
||||||
|
|
||||||
t->tex((xOff + width) / fontWidth, yOff / fontHeight);
|
t->tex((xOff + width) / fontWidth, yOff / fontHeight);
|
||||||
t->vertex(xPos + width, yPos, 0.0f);
|
t->vertex(x1, y0, 0.0f);
|
||||||
|
|
||||||
t->tex(xOff / fontWidth, yOff / fontHeight);
|
t->tex(xOff / fontWidth, yOff / fontHeight);
|
||||||
t->vertex(xPos, yPos, 0.0f);
|
t->vertex(x0, y0, 0.0f);
|
||||||
|
|
||||||
t->end();
|
t->end();
|
||||||
#else
|
|
||||||
t->begin(GL_TRIANGLE_STRIP);
|
|
||||||
t->tex(xOff / 128.0F, yOff / 128.0F);
|
|
||||||
t->vertex(xPos, yPos, 0.0f);
|
|
||||||
t->tex(xOff / 128.0F, (yOff + 7.99f) / 128.0F);
|
|
||||||
t->vertex(xPos, yPos + 7.99f, 0.0f);
|
|
||||||
t->tex((xOff + width) / 128.0F, yOff / 128.0F);
|
|
||||||
t->vertex(xPos + width, yPos, 0.0f);
|
|
||||||
t->tex((xOff + width) / 128.0F, (yOff + 7.99f) / 128.0F);
|
|
||||||
t->vertex(xPos + width, yPos + 7.99f, 0.0f);
|
|
||||||
t->end();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
xPos += (float) charWidths[c];
|
if (m_bold)
|
||||||
|
{
|
||||||
|
float dx = 1.0f;
|
||||||
|
t->begin();
|
||||||
|
t->tex(xOff / fontWidth, (yOff + 7.99f) / fontHeight);
|
||||||
|
t->vertex(x0 + dx, y1, 0.0f);
|
||||||
|
t->tex((xOff + width) / fontWidth, (yOff + 7.99f) / fontHeight);
|
||||||
|
t->vertex(x1 + dx, y1, 0.0f);
|
||||||
|
t->tex((xOff + width) / fontWidth, yOff / fontHeight);
|
||||||
|
t->vertex(x1 + dx, y0, 0.0f);
|
||||||
|
t->tex(xOff / fontWidth, yOff / fontHeight);
|
||||||
|
t->vertex(x0 + dx, y0, 0.0f);
|
||||||
|
t->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_underline)
|
||||||
|
renderStyleLine(x0, y1 - 1.0f, xPos + static_cast<float>(charWidths[c]), y1);
|
||||||
|
|
||||||
|
if (m_strikethrough)
|
||||||
|
{
|
||||||
|
float mid = y0 + height * 0.5f;
|
||||||
|
renderStyleLine(x0, mid - 0.5f, xPos + static_cast<float>(charWidths[c]), mid + 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
xPos += static_cast<float>(charWidths[c]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Font::drawShadow(const wstring& str, int x, int y, int color)
|
void Font::drawShadow(const wstring& str, int x, int y, int color)
|
||||||
@@ -176,6 +206,26 @@ void Font::drawShadow(const wstring& str, int x, int y, int color)
|
|||||||
draw(str, x, y, color, false);
|
draw(str, x, y, color, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Font::drawShadowLiteral(const wstring& str, int x, int y, int color)
|
||||||
|
{
|
||||||
|
int shadowColor = (color & 0xFCFCFC) >> 2 | (color & 0xFF000000);
|
||||||
|
drawLiteral(str, x + 1, y + 1, shadowColor);
|
||||||
|
drawLiteral(str, x, y, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Font::drawLiteral(const wstring& str, int x, int y, int color)
|
||||||
|
{
|
||||||
|
if (str.empty()) return;
|
||||||
|
if ((color & 0xFC000000) == 0) color |= 0xFF000000;
|
||||||
|
textures->bindTexture(m_textureLocation);
|
||||||
|
glColor4f((color >> 16 & 255) / 255.0F, (color >> 8 & 255) / 255.0F, (color & 255) / 255.0F, (color >> 24 & 255) / 255.0F);
|
||||||
|
xPos = static_cast<float>(x);
|
||||||
|
yPos = static_cast<float>(y);
|
||||||
|
wstring cleanStr = sanitize(str);
|
||||||
|
for (size_t i = 0; i < cleanStr.length(); ++i)
|
||||||
|
renderCharacter(cleanStr.at(i));
|
||||||
|
}
|
||||||
|
|
||||||
void Font::drawShadowWordWrap(const wstring &str, int x, int y, int w, int color, int h)
|
void Font::drawShadowWordWrap(const wstring &str, int x, int y, int w, int color, int h)
|
||||||
{
|
{
|
||||||
drawWordWrapInternal(str, x + 1, y + 1, w, color, true, h);
|
drawWordWrapInternal(str, x + 1, y + 1, w, color, true, h);
|
||||||
@@ -193,24 +243,38 @@ wstring Font::reorderBidi(const wstring &str)
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isSectionFormatCode(wchar_t ca)
|
||||||
|
{
|
||||||
|
if ((ca >= L'0' && ca <= L'9') || (ca >= L'a' && ca <= L'f') || (ca >= L'A' && ca <= L'F'))
|
||||||
|
return true;
|
||||||
|
wchar_t l = static_cast<wchar_t>(ca | 32);
|
||||||
|
return l == L'l' || l == L'o' || l == L'n' || l == L'm' || l == L'r' || l == L'k';
|
||||||
|
}
|
||||||
|
|
||||||
void Font::draw(const wstring &str, bool dropShadow)
|
void Font::draw(const wstring &str, bool dropShadow)
|
||||||
{
|
{
|
||||||
// Bind the texture
|
// Bind the texture
|
||||||
textures->bindTexture(m_textureLocation);
|
textures->bindTexture(m_textureLocation);
|
||||||
|
|
||||||
bool noise = false;
|
bool noise = false;
|
||||||
|
m_bold = m_italic = m_underline = m_strikethrough = false;
|
||||||
wstring cleanStr = sanitize(str);
|
wstring cleanStr = sanitize(str);
|
||||||
|
|
||||||
for (int i = 0; i < (int)cleanStr.length(); ++i)
|
for (int i = 0; i < static_cast<int>(cleanStr.length()); ++i)
|
||||||
{
|
{
|
||||||
// Map character
|
// Map character
|
||||||
wchar_t c = cleanStr.at(i);
|
wchar_t c = cleanStr.at(i);
|
||||||
|
|
||||||
if (c == 167 && i + 1 < cleanStr.length())
|
if (c == 167 && i + 1 < cleanStr.length())
|
||||||
{
|
{
|
||||||
// 4J - following block was:
|
|
||||||
// int colorN = L"0123456789abcdefk".indexOf(str.toLowerCase().charAt(i + 1));
|
|
||||||
wchar_t ca = cleanStr[i+1];
|
wchar_t ca = cleanStr[i+1];
|
||||||
|
if (!isSectionFormatCode(ca))
|
||||||
|
{
|
||||||
|
renderCharacter(167);
|
||||||
|
renderCharacter(ca);
|
||||||
|
i += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
int colorN = 16;
|
int colorN = 16;
|
||||||
if(( ca >= L'0' ) && (ca <= L'9')) colorN = ca - L'0';
|
if(( ca >= L'0' ) && (ca <= L'9')) colorN = ca - L'0';
|
||||||
else if(( ca >= L'a' ) && (ca <= L'f')) colorN = (ca - L'a') + 10;
|
else if(( ca >= L'a' ) && (ca <= L'f')) colorN = (ca - L'a') + 10;
|
||||||
@@ -218,7 +282,13 @@ void Font::draw(const wstring &str, bool dropShadow)
|
|||||||
|
|
||||||
if (colorN == 16)
|
if (colorN == 16)
|
||||||
{
|
{
|
||||||
noise = true;
|
wchar_t l = static_cast<wchar_t>(ca | 32);
|
||||||
|
if (l == L'l') m_bold = true;
|
||||||
|
else if (l == L'o') m_italic = true;
|
||||||
|
else if (l == L'n') m_underline = true;
|
||||||
|
else if (l == L'm') m_strikethrough = true;
|
||||||
|
else if (l == L'r') m_bold = m_italic = m_underline = m_strikethrough = noise = false;
|
||||||
|
else if (l == L'k') noise = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -280,20 +350,34 @@ int Font::width(const wstring& str)
|
|||||||
{
|
{
|
||||||
wchar_t c = cleanStr.at(i);
|
wchar_t c = cleanStr.at(i);
|
||||||
|
|
||||||
if(c == 167)
|
if (c == 167)
|
||||||
{
|
{
|
||||||
// Ignore the character used to define coloured text
|
if (i + 1 < cleanStr.length() && isSectionFormatCode(cleanStr[i+1]))
|
||||||
++i;
|
++i;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
len += charWidths[167];
|
||||||
|
if (i + 1 < cleanStr.length())
|
||||||
|
len += charWidths[static_cast<unsigned>(cleanStr[++i])];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
len += charWidths[c];
|
len += charWidths[c];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Font::widthLiteral(const wstring& str)
|
||||||
|
{
|
||||||
|
wstring cleanStr = sanitize(str);
|
||||||
|
if (cleanStr == L"") return 0;
|
||||||
|
int len = 0;
|
||||||
|
for (size_t i = 0; i < cleanStr.length(); ++i)
|
||||||
|
len += charWidths[static_cast<unsigned>(cleanStr.at(i))];
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
wstring Font::sanitize(const wstring& str)
|
wstring Font::sanitize(const wstring& str)
|
||||||
{
|
{
|
||||||
wstring sb = str;
|
wstring sb = str;
|
||||||
@@ -467,7 +551,7 @@ void Font::setBidirectional(bool bidirectional)
|
|||||||
|
|
||||||
bool Font::AllCharactersValid(const wstring &str)
|
bool Font::AllCharactersValid(const wstring &str)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < (int)str.length(); ++i)
|
for (int i = 0; i < static_cast<int>(str.length()); ++i)
|
||||||
{
|
{
|
||||||
wchar_t c = str.at(i);
|
wchar_t c = str.at(i);
|
||||||
|
|
||||||
@@ -512,15 +596,15 @@ void Font::renderFakeCB(IntBuffer *ib)
|
|||||||
float uo = (0.0f) / 128.0f;
|
float uo = (0.0f) / 128.0f;
|
||||||
float vo = (0.0f) / 128.0f;
|
float vo = (0.0f) / 128.0f;
|
||||||
|
|
||||||
t->vertexUV((float)(0), (float)( 0 + s), (float)( 0), (float)( ix / 128.0f + uo), (float)( (iy + s) / 128.0f + vo));
|
t->vertexUV(static_cast<float>(0), static_cast<float>(0 + s), static_cast<float>(0), static_cast<float>(ix / 128.0f + uo), static_cast<float>((iy + s) / 128.0f + vo));
|
||||||
t->vertexUV((float)(0 + s), (float)( 0 + s), (float)( 0), (float)( (ix + s) / 128.0f + uo), (float)( (iy + s) / 128.0f + vo));
|
t->vertexUV(static_cast<float>(0 + s), static_cast<float>(0 + s), static_cast<float>(0), static_cast<float>((ix + s) / 128.0f + uo), static_cast<float>((iy + s) / 128.0f + vo));
|
||||||
t->vertexUV((float)(0 + s), (float)( 0), (float)( 0), (float)( (ix + s) / 128.0f + uo), (float)( iy / 128.0f + vo));
|
t->vertexUV(static_cast<float>(0 + s), static_cast<float>(0), static_cast<float>(0), static_cast<float>((ix + s) / 128.0f + uo), static_cast<float>(iy / 128.0f + vo));
|
||||||
t->vertexUV((float)(0), (float)( 0), (float)( 0), (float)( ix / 128.0f + uo), (float)( iy / 128.0f + vo));
|
t->vertexUV(static_cast<float>(0), static_cast<float>(0), static_cast<float>(0), static_cast<float>(ix / 128.0f + uo), static_cast<float>(iy / 128.0f + vo));
|
||||||
// target.colorBlit(texture, x + xo, y, color, ix, iy,
|
// target.colorBlit(texture, x + xo, y, color, ix, iy,
|
||||||
// charWidths[chars[i]], 8);
|
// charWidths[chars[i]], 8);
|
||||||
t->end();
|
t->end();
|
||||||
|
|
||||||
glTranslatef((float)charWidths[i], 0, 0);
|
glTranslatef(static_cast<float>(charWidths[i]), 0, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ private:
|
|||||||
float xPos;
|
float xPos;
|
||||||
float yPos;
|
float yPos;
|
||||||
|
|
||||||
|
// § format state (bold, italic, underline, strikethrough); set during draw(), reset by §r
|
||||||
|
bool m_bold;
|
||||||
|
bool m_italic;
|
||||||
|
bool m_underline;
|
||||||
|
bool m_strikethrough;
|
||||||
|
|
||||||
bool enforceUnicodeSheet; // use unicode sheet for ascii
|
bool enforceUnicodeSheet; // use unicode sheet for ascii
|
||||||
bool bidirectional; // use bidi to flip strings
|
bool bidirectional; // use bidi to flip strings
|
||||||
|
|
||||||
@@ -41,9 +47,11 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void renderCharacter(wchar_t c); // 4J added
|
void renderCharacter(wchar_t c); // 4J added
|
||||||
|
void renderStyleLine(float x0, float y0, float x1, float y1); // solid line for underline/strikethrough
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void drawShadow(const wstring& str, int x, int y, int color);
|
void drawShadow(const wstring& str, int x, int y, int color);
|
||||||
|
void drawShadowLiteral(const wstring& str, int x, int y, int color); // draw without interpreting § codes
|
||||||
void drawShadowWordWrap(const wstring &str, int x, int y, int w, int color, int h); // 4J Added h param
|
void drawShadowWordWrap(const wstring &str, int x, int y, int w, int color, int h); // 4J Added h param
|
||||||
void draw(const wstring &str, int x, int y, int color);
|
void draw(const wstring &str, int x, int y, int color);
|
||||||
/**
|
/**
|
||||||
@@ -58,11 +66,13 @@ private:
|
|||||||
|
|
||||||
void draw(const wstring &str, bool dropShadow);
|
void draw(const wstring &str, bool dropShadow);
|
||||||
void draw(const wstring& str, int x, int y, int color, bool dropShadow);
|
void draw(const wstring& str, int x, int y, int color, bool dropShadow);
|
||||||
|
void drawLiteral(const wstring& str, int x, int y, int color); // no § parsing
|
||||||
int MapCharacter(wchar_t c); // 4J added
|
int MapCharacter(wchar_t c); // 4J added
|
||||||
bool CharacterExists(wchar_t c); // 4J added
|
bool CharacterExists(wchar_t c); // 4J added
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int width(const wstring& str);
|
int width(const wstring& str);
|
||||||
|
int widthLiteral(const wstring& str); // width without skipping § codes (for chat input)
|
||||||
wstring sanitize(const wstring& str);
|
wstring sanitize(const wstring& str);
|
||||||
void drawWordWrap(const wstring &string, int x, int y, int w, int col, int h); // 4J Added h param
|
void drawWordWrap(const wstring &string, int x, int y, int w, int col, int h); // 4J Added h param
|
||||||
|
|
||||||
|
|||||||
@@ -971,15 +971,10 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
|
|||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glDisable(GL_ALPHA_TEST);
|
glDisable(GL_ALPHA_TEST);
|
||||||
|
|
||||||
// 4J Stu - We have moved the chat text to a xui
|
#if defined(_WINDOWS64)
|
||||||
#if 0
|
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
// 4J-PB we need to move this up a bit because we've moved the quick select
|
glTranslatef(0.0f, static_cast<float>(screenHeight - iSafezoneYHalf - iTooltipsYOffset - 16 - 3 + 22) - 24.0f, 0.0f);
|
||||||
//glTranslatef(0, ((float)screenHeight) - 48, 0);
|
|
||||||
glTranslatef(0.0f, (float)(screenHeight - iSafezoneYHalf - iTooltipsYOffset - 16 - 3 + 22) - 24.0f, 0.0f);
|
|
||||||
// glScalef(1.0f / ssc.scale, 1.0f / ssc.scale, 1);
|
|
||||||
|
|
||||||
// 4J-PB - we need gui messages for each of the possible 4 splitscreen players
|
|
||||||
if(bDisplayGui)
|
if(bDisplayGui)
|
||||||
{
|
{
|
||||||
int iPad=minecraft->player->GetXboxPad();
|
int iPad=minecraft->player->GetXboxPad();
|
||||||
@@ -993,23 +988,21 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
|
|||||||
if (t < 0) t = 0;
|
if (t < 0) t = 0;
|
||||||
if (t > 1) t = 1;
|
if (t > 1) t = 1;
|
||||||
t = t * t;
|
t = t * t;
|
||||||
int alpha = (int) (255 * t);
|
int alpha = static_cast<int>(255 * t);
|
||||||
if (isChatting) alpha = 255;
|
if (isChatting) alpha = 255;
|
||||||
|
|
||||||
if (alpha > 0)
|
if (alpha > 0)
|
||||||
{
|
{
|
||||||
int x = iSafezoneXHalf+2;
|
int x = iSafezoneXHalf+2;
|
||||||
int y = -((int)i) * 9;
|
int y = -(static_cast<int>(i)) * 9;
|
||||||
if(bTwoPlayerSplitscreen)
|
if(bTwoPlayerSplitscreen)
|
||||||
{
|
{
|
||||||
y+= iHeightOffset;
|
y+= iHeightOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
wstring msg = guiMessages[iPad][i].string;
|
wstring msg = guiMessages[iPad][i].string;
|
||||||
// 4J-PB - fill the black bar across the whole screen, otherwise it looks odd due to the safe area
|
|
||||||
this->fill(0, y - 1, screenWidth/fScaleFactorWidth, y + 8, (alpha / 2) << 24);
|
this->fill(0, y - 1, screenWidth/fScaleFactorWidth, y + 8, (alpha / 2) << 24);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
|
|
||||||
font->drawShadow(msg, iSafezoneXHalf+4, y, 0xffffff + (alpha << 24));
|
font->drawShadow(msg, iSafezoneXHalf+4, y, 0xffffff + (alpha << 24));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,10 +48,10 @@ void GuiComponent::fill(int x0, int y0, int x1, int y1, int col)
|
|||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glColor4f(r, g, b, a);
|
glColor4f(r, g, b, a);
|
||||||
t->begin();
|
t->begin();
|
||||||
t->vertex((float)(x0), (float)( y1), (float)( 0));
|
t->vertex(static_cast<float>(x0), static_cast<float>(y1), static_cast<float>(0));
|
||||||
t->vertex((float)(x1), (float)( y1), (float)( 0));
|
t->vertex(static_cast<float>(x1), static_cast<float>(y1), static_cast<float>(0));
|
||||||
t->vertex((float)(x1), (float)( y0), (float)( 0));
|
t->vertex(static_cast<float>(x1), static_cast<float>(y0), static_cast<float>(0));
|
||||||
t->vertex((float)(x0), (float)( y0), (float)( 0));
|
t->vertex(static_cast<float>(x0), static_cast<float>(y0), static_cast<float>(0));
|
||||||
t->end();
|
t->end();
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
@@ -77,11 +77,11 @@ void GuiComponent::fillGradient(int x0, int y0, int x1, int y1, int col1, int co
|
|||||||
Tesselator *t = Tesselator::getInstance();
|
Tesselator *t = Tesselator::getInstance();
|
||||||
t->begin();
|
t->begin();
|
||||||
t->color(r1, g1, b1, a1);
|
t->color(r1, g1, b1, a1);
|
||||||
t->vertex((float)(x1), (float)( y0), blitOffset);
|
t->vertex(static_cast<float>(x1), static_cast<float>(y0), blitOffset);
|
||||||
t->vertex((float)(x0), (float)( y0), blitOffset);
|
t->vertex(static_cast<float>(x0), static_cast<float>(y0), blitOffset);
|
||||||
t->color(r2, g2, b2, a2);
|
t->color(r2, g2, b2, a2);
|
||||||
t->vertex((float)(x0), (float)( y1), blitOffset);
|
t->vertex(static_cast<float>(x0), static_cast<float>(y1), blitOffset);
|
||||||
t->vertex((float)(x1), (float)( y1), blitOffset);
|
t->vertex(static_cast<float>(x1), static_cast<float>(y1), blitOffset);
|
||||||
t->end();
|
t->end();
|
||||||
|
|
||||||
glShadeModel(GL_FLAT);
|
glShadeModel(GL_FLAT);
|
||||||
@@ -105,6 +105,11 @@ void GuiComponent::drawString(Font *font, const wstring& str, int x, int y, int
|
|||||||
font->drawShadow(str, x, y, color);
|
font->drawShadow(str, x, y, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GuiComponent::drawStringLiteral(Font *font, const wstring& str, int x, int y, int color)
|
||||||
|
{
|
||||||
|
font->drawShadowLiteral(str, x, y, color);
|
||||||
|
}
|
||||||
|
|
||||||
void GuiComponent::blit(int x, int y, int sx, int sy, int w, int h)
|
void GuiComponent::blit(int x, int y, int sx, int sy, int w, int h)
|
||||||
{
|
{
|
||||||
float us = 1 / 256.0f;
|
float us = 1 / 256.0f;
|
||||||
@@ -117,20 +122,20 @@ void GuiComponent::blit(int x, int y, int sx, int sy, int w, int h)
|
|||||||
const float extraShift = 0.75f;
|
const float extraShift = 0.75f;
|
||||||
|
|
||||||
// 4J - subtracting extraShift (actual screen pixels, so need to compensate for physical & game width) from each x & y coordinate to compensate for centre of pixels in directx vs openGL
|
// 4J - subtracting extraShift (actual screen pixels, so need to compensate for physical & game width) from each x & y coordinate to compensate for centre of pixels in directx vs openGL
|
||||||
float dx = ( extraShift * (float)Minecraft::GetInstance()->width ) / (float)Minecraft::GetInstance()->width_phys;
|
float dx = ( extraShift * static_cast<float>(Minecraft::GetInstance()->width) ) / static_cast<float>(Minecraft::GetInstance()->width_phys);
|
||||||
// 4J - Also factor in the scaling from gui coordinate space to the screen. This varies based on user-selected gui scale, and whether we are in a viewport mode or not
|
// 4J - Also factor in the scaling from gui coordinate space to the screen. This varies based on user-selected gui scale, and whether we are in a viewport mode or not
|
||||||
dx /= Gui::currentGuiScaleFactor;
|
dx /= Gui::currentGuiScaleFactor;
|
||||||
float dy = extraShift / Gui::currentGuiScaleFactor;
|
float dy = extraShift / Gui::currentGuiScaleFactor;
|
||||||
// Ensure that the x/y, width and height are actually pixel aligned at our current scale factor - in particular, for split screen mode with the default (3X)
|
// Ensure that the x/y, width and height are actually pixel aligned at our current scale factor - in particular, for split screen mode with the default (3X)
|
||||||
// scale, we have an overall scale factor of 3 * 0.5 = 1.5, and so any odd pixels won't align
|
// scale, we have an overall scale factor of 3 * 0.5 = 1.5, and so any odd pixels won't align
|
||||||
float fx = (floorf((float)x * Gui::currentGuiScaleFactor)) / Gui::currentGuiScaleFactor;
|
float fx = (floorf(static_cast<float>(x) * Gui::currentGuiScaleFactor)) / Gui::currentGuiScaleFactor;
|
||||||
float fy = (floorf((float)y * Gui::currentGuiScaleFactor)) / Gui::currentGuiScaleFactor;
|
float fy = (floorf(static_cast<float>(y) * Gui::currentGuiScaleFactor)) / Gui::currentGuiScaleFactor;
|
||||||
float fw = (floorf((float)w * Gui::currentGuiScaleFactor)) / Gui::currentGuiScaleFactor;
|
float fw = (floorf(static_cast<float>(w) * Gui::currentGuiScaleFactor)) / Gui::currentGuiScaleFactor;
|
||||||
float fh = (floorf((float)h * Gui::currentGuiScaleFactor)) / Gui::currentGuiScaleFactor;
|
float fh = (floorf(static_cast<float>(h) * Gui::currentGuiScaleFactor)) / Gui::currentGuiScaleFactor;
|
||||||
|
|
||||||
t->vertexUV(fx + 0 - dx, fy + fh - dy, (float)( blitOffset), (float)( (sx + 0) * us), (float)( (sy + h) * vs));
|
t->vertexUV(fx + 0 - dx, fy + fh - dy, static_cast<float>(blitOffset), static_cast<float>((sx + 0) * us), static_cast<float>((sy + h) * vs));
|
||||||
t->vertexUV(fx + fw - dx, fy + fh - dy, (float)( blitOffset), (float)( (sx + w) * us), (float)( (sy + h) * vs));
|
t->vertexUV(fx + fw - dx, fy + fh - dy, static_cast<float>(blitOffset), static_cast<float>((sx + w) * us), static_cast<float>((sy + h) * vs));
|
||||||
t->vertexUV(fx + fw - dx, fy + 0 - dy, (float)( blitOffset), (float)( (sx + w) * us), (float)( (sy + 0) * vs));
|
t->vertexUV(fx + fw - dx, fy + 0 - dy, static_cast<float>(blitOffset), static_cast<float>((sx + w) * us), static_cast<float>((sy + 0) * vs));
|
||||||
t->vertexUV(fx + 0 - dx, fy + 0 - dy, (float)( blitOffset), (float)( (sx + 0) * us), (float)( (sy + 0) * vs));
|
t->vertexUV(fx + 0 - dx, fy + 0 - dy, static_cast<float>(blitOffset), static_cast<float>((sx + 0) * us), static_cast<float>((sy + 0) * vs));
|
||||||
t->end();
|
t->end();
|
||||||
}
|
}
|
||||||
@@ -15,5 +15,6 @@ public:
|
|||||||
GuiComponent(); // 4J added
|
GuiComponent(); // 4J added
|
||||||
void drawCenteredString(Font *font, const wstring& str, int x, int y, int color);
|
void drawCenteredString(Font *font, const wstring& str, int x, int y, int color);
|
||||||
void drawString(Font *font, const wstring& str, int x, int y, int color);
|
void drawString(Font *font, const wstring& str, int x, int y, int color);
|
||||||
|
void drawStringLiteral(Font* font, const wstring& str, int x, int y, int color);
|
||||||
void blit(int x, int y, int sx, int sy, int w, int h);
|
void blit(int x, int y, int sx, int sy, int w, int h);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
#include "..\Minecraft.World\AABB.h"
|
#include "..\Minecraft.World\AABB.h"
|
||||||
#include "..\Minecraft.World\Pos.h"
|
#include "..\Minecraft.World\Pos.h"
|
||||||
#include "..\Minecraft.World\SharedConstants.h"
|
#include "..\Minecraft.World\SharedConstants.h"
|
||||||
|
#include "..\Minecraft.World\ChatPacket.h"
|
||||||
|
#include "..\Minecraft.World\StringHelpers.h"
|
||||||
#include "..\Minecraft.World\Socket.h"
|
#include "..\Minecraft.World\Socket.h"
|
||||||
#include "..\Minecraft.World\Achievements.h"
|
#include "..\Minecraft.World\Achievements.h"
|
||||||
#include "..\Minecraft.World\net.minecraft.h"
|
#include "..\Minecraft.World\net.minecraft.h"
|
||||||
@@ -607,38 +609,26 @@ void PlayerConnection::handleSetCarriedItem(shared_ptr<SetCarriedItemPacket> pac
|
|||||||
|
|
||||||
void PlayerConnection::handleChat(shared_ptr<ChatPacket> packet)
|
void PlayerConnection::handleChat(shared_ptr<ChatPacket> packet)
|
||||||
{
|
{
|
||||||
// 4J - TODO
|
if (packet->m_stringArgs.empty()) return;
|
||||||
#if 0
|
wstring message = trimString(packet->m_stringArgs[0]);
|
||||||
wstring message = packet->message;
|
|
||||||
if (message.length() > SharedConstants::maxChatLength)
|
if (message.length() > SharedConstants::maxChatLength)
|
||||||
{
|
{
|
||||||
disconnect(L"Chat message too long");
|
disconnect(DisconnectPacket::eDisconnect_None); // or a specific reason
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
message = message.trim();
|
// Optional: validate characters (acceptableLetters)
|
||||||
for (int i = 0; i < message.length(); i++)
|
if (message.length() > 0 && message[0] == L'/')
|
||||||
{
|
|
||||||
if (SharedConstants.acceptableLetters.indexOf(message.charAt(i)) < 0 && (int) message.charAt(i) < 32)
|
|
||||||
{
|
|
||||||
disconnect(L"Illegal characters in chat");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message.startsWith("/"))
|
|
||||||
{
|
{
|
||||||
handleCommand(message);
|
handleCommand(message);
|
||||||
} else {
|
return;
|
||||||
message = "<" + player.name + "> " + message;
|
|
||||||
logger.info(message);
|
|
||||||
server.players.broadcastAll(new ChatPacket(message));
|
|
||||||
}
|
}
|
||||||
|
wstring formatted = L"<" + player->name + L"> " + message;
|
||||||
|
server->getPlayers()->broadcastAll(shared_ptr<ChatPacket>(new ChatPacket(formatted)));
|
||||||
chatSpamTickCount += SharedConstants::TICKS_PER_SECOND;
|
chatSpamTickCount += SharedConstants::TICKS_PER_SECOND;
|
||||||
if (chatSpamTickCount > SharedConstants::TICKS_PER_SECOND * 10)
|
if (chatSpamTickCount > SharedConstants::TICKS_PER_SECOND * 10)
|
||||||
{
|
{
|
||||||
disconnect("disconnect.spam");
|
disconnect(DisconnectPacket::eDisconnect_None); // spam
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerConnection::handleCommand(const wstring& message)
|
void PlayerConnection::handleCommand(const wstring& message)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "Screen.h"
|
#include "Screen.h"
|
||||||
#include "Button.h"
|
#include "Button.h"
|
||||||
|
#include "ChatScreen.h"
|
||||||
#include "GuiParticles.h"
|
#include "GuiParticles.h"
|
||||||
#include "Tesselator.h"
|
#include "Tesselator.h"
|
||||||
#include "Textures.h"
|
#include "Textures.h"
|
||||||
@@ -42,13 +43,32 @@ void Screen::keyPressed(wchar_t eventCharacter, int eventKey)
|
|||||||
|
|
||||||
wstring Screen::getClipboard()
|
wstring Screen::getClipboard()
|
||||||
{
|
{
|
||||||
// 4J - removed
|
#ifdef _WINDOWS64
|
||||||
return NULL;
|
if (!OpenClipboard(NULL)) return wstring();
|
||||||
|
HANDLE h = GetClipboardData(CF_UNICODETEXT);
|
||||||
|
wstring out;
|
||||||
|
if (h)
|
||||||
|
{
|
||||||
|
const wchar_t *p = reinterpret_cast<const wchar_t*>(GlobalLock(h));
|
||||||
|
if (p) { out = p; GlobalUnlock(h); }
|
||||||
|
}
|
||||||
|
CloseClipboard();
|
||||||
|
return out;
|
||||||
|
#else
|
||||||
|
return wstring();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::setClipboard(const wstring& str)
|
void Screen::setClipboard(const wstring& str)
|
||||||
{
|
{
|
||||||
// 4J - removed
|
#ifdef _WINDOWS64
|
||||||
|
if (!OpenClipboard(NULL)) return;
|
||||||
|
EmptyClipboard();
|
||||||
|
size_t len = (str.length() + 1) * sizeof(wchar_t);
|
||||||
|
HGLOBAL h = GlobalAlloc(GMEM_MOVEABLE, len);
|
||||||
|
if (h) { memcpy(GlobalLock(h), str.c_str(), len); GlobalUnlock(h); SetClipboardData(CF_UNICODETEXT, h); }
|
||||||
|
CloseClipboard();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::mouseClicked(int x, int y, int buttonNum)
|
void Screen::mouseClicked(int x, int y, int buttonNum)
|
||||||
@@ -121,34 +141,88 @@ void Screen::updateEvents()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Poll keyboard events
|
// Only drain WM_CHAR when this screen wants text input (e.g. ChatScreen); otherwise we'd steal keys from the game
|
||||||
|
if (dynamic_cast<ChatScreen*>(this) != nullptr)
|
||||||
|
{
|
||||||
|
wchar_t ch;
|
||||||
|
while (g_KBMInput.ConsumeChar(ch))
|
||||||
|
{
|
||||||
|
if (ch >= 0x20)
|
||||||
|
keyPressed(ch, -1);
|
||||||
|
else if (ch == 0x08)
|
||||||
|
keyPressed(0, Keyboard::KEY_BACK);
|
||||||
|
else if (ch == 0x0D)
|
||||||
|
keyPressed(0, Keyboard::KEY_RETURN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arrow key repeat: deliver on first press (when key down and last==0) and while held (throttled)
|
||||||
|
static DWORD s_arrowLastTime[2] = { 0, 0 };
|
||||||
|
static bool s_arrowFirstRepeat[2] = { false, false };
|
||||||
|
const DWORD ARROW_REPEAT_DELAY_MS = 250;
|
||||||
|
const DWORD ARROW_REPEAT_INTERVAL_MS = 50;
|
||||||
|
DWORD now = GetTickCount();
|
||||||
|
|
||||||
|
// Poll keyboard events (special keys that may not come through WM_CHAR, e.g. Escape, arrows)
|
||||||
for (int vk = 0; vk < 256; vk++)
|
for (int vk = 0; vk < 256; vk++)
|
||||||
{
|
{
|
||||||
if (g_KBMInput.IsKeyPressed(vk))
|
bool deliver = g_KBMInput.IsKeyPressed(vk);
|
||||||
|
if (vk == VK_LEFT || vk == VK_RIGHT)
|
||||||
{
|
{
|
||||||
// Map Windows virtual key to the Keyboard constants used by Screen::keyPressed
|
int idx = (vk == VK_LEFT) ? 0 : 1;
|
||||||
int mappedKey = -1;
|
if (!g_KBMInput.IsKeyDown(vk))
|
||||||
wchar_t ch = 0;
|
|
||||||
if (vk == VK_ESCAPE) mappedKey = Keyboard::KEY_ESCAPE;
|
|
||||||
else if (vk == VK_RETURN) mappedKey = Keyboard::KEY_RETURN;
|
|
||||||
else if (vk == VK_BACK) mappedKey = Keyboard::KEY_BACK;
|
|
||||||
else if (vk == VK_UP) mappedKey = Keyboard::KEY_UP;
|
|
||||||
else if (vk == VK_DOWN) mappedKey = Keyboard::KEY_DOWN;
|
|
||||||
else if (vk == VK_LEFT) mappedKey = Keyboard::KEY_LEFT;
|
|
||||||
else if (vk == VK_RIGHT) mappedKey = Keyboard::KEY_RIGHT;
|
|
||||||
else if (vk == VK_LSHIFT || vk == VK_RSHIFT) mappedKey = Keyboard::KEY_LSHIFT;
|
|
||||||
else if (vk == VK_TAB) mappedKey = Keyboard::KEY_TAB;
|
|
||||||
else if (vk >= 'A' && vk <= 'Z')
|
|
||||||
{
|
{
|
||||||
ch = (wchar_t)(vk - 'A' + L'a');
|
s_arrowLastTime[idx] = 0;
|
||||||
if (g_KBMInput.IsKeyDown(VK_LSHIFT) || g_KBMInput.IsKeyDown(VK_RSHIFT)) ch = (wchar_t)vk;
|
s_arrowFirstRepeat[idx] = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DWORD last = s_arrowLastTime[idx];
|
||||||
|
if (last == 0)
|
||||||
|
deliver = true;
|
||||||
|
else if (!deliver)
|
||||||
|
{
|
||||||
|
DWORD interval = s_arrowFirstRepeat[idx] ? ARROW_REPEAT_INTERVAL_MS : ARROW_REPEAT_DELAY_MS;
|
||||||
|
if ((now - last) >= interval)
|
||||||
|
{
|
||||||
|
deliver = true;
|
||||||
|
s_arrowFirstRepeat[idx] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (deliver)
|
||||||
|
s_arrowLastTime[idx] = now;
|
||||||
}
|
}
|
||||||
else if (vk >= '0' && vk <= '9') ch = (wchar_t)vk;
|
|
||||||
else if (vk == VK_SPACE) ch = L' ';
|
|
||||||
|
|
||||||
if (mappedKey != -1) keyPressed(ch, mappedKey);
|
|
||||||
else if (ch != 0) keyPressed(ch, -1);
|
|
||||||
}
|
}
|
||||||
|
// Escape: deliver when key is down so we don't miss it (IsKeyPressed can be one frame late)
|
||||||
|
if (vk == VK_ESCAPE && g_KBMInput.IsKeyDown(VK_ESCAPE))
|
||||||
|
deliver = true;
|
||||||
|
if (!deliver) continue;
|
||||||
|
|
||||||
|
if (dynamic_cast<ChatScreen*>(this) != nullptr &&
|
||||||
|
(vk >= 'A' && vk <= 'Z' || vk >= '0' && vk <= '9' || vk == VK_SPACE || vk == VK_RETURN || vk == VK_BACK))
|
||||||
|
continue;
|
||||||
|
// Map to Screen::keyPressed
|
||||||
|
int mappedKey = -1;
|
||||||
|
wchar_t ch = 0;
|
||||||
|
if (vk == VK_ESCAPE) mappedKey = Keyboard::KEY_ESCAPE;
|
||||||
|
else if (vk == VK_RETURN) mappedKey = Keyboard::KEY_RETURN;
|
||||||
|
else if (vk == VK_BACK) mappedKey = Keyboard::KEY_BACK;
|
||||||
|
else if (vk == VK_UP) mappedKey = Keyboard::KEY_UP;
|
||||||
|
else if (vk == VK_DOWN) mappedKey = Keyboard::KEY_DOWN;
|
||||||
|
else if (vk == VK_LEFT) mappedKey = Keyboard::KEY_LEFT;
|
||||||
|
else if (vk == VK_RIGHT) mappedKey = Keyboard::KEY_RIGHT;
|
||||||
|
else if (vk == VK_LSHIFT || vk == VK_RSHIFT) mappedKey = Keyboard::KEY_LSHIFT;
|
||||||
|
else if (vk == VK_TAB) mappedKey = Keyboard::KEY_TAB;
|
||||||
|
else if (vk >= 'A' && vk <= 'Z')
|
||||||
|
{
|
||||||
|
ch = static_cast<wchar_t>(vk - 'A' + L'a');
|
||||||
|
if (g_KBMInput.IsKeyDown(VK_LSHIFT) || g_KBMInput.IsKeyDown(VK_RSHIFT)) ch = static_cast<wchar_t>(vk);
|
||||||
|
}
|
||||||
|
else if (vk >= '0' && vk <= '9') ch = static_cast<wchar_t>(vk);
|
||||||
|
else if (vk == VK_SPACE) ch = L' ';
|
||||||
|
|
||||||
|
if (mappedKey != -1) keyPressed(ch, mappedKey);
|
||||||
|
else if (ch != 0) keyPressed(ch, -1);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* 4J - TODO
|
/* 4J - TODO
|
||||||
@@ -232,10 +306,10 @@ void Screen::renderDirtBackground(int vo)
|
|||||||
float s = 32;
|
float s = 32;
|
||||||
t->begin();
|
t->begin();
|
||||||
t->color(0x404040);
|
t->color(0x404040);
|
||||||
t->vertexUV((float)(0), (float)( height), (float)( 0), (float)( 0), (float)( height / s + vo));
|
t->vertexUV(static_cast<float>(0), static_cast<float>(height), static_cast<float>(0), static_cast<float>(0), static_cast<float>(height / s + vo));
|
||||||
t->vertexUV((float)(width), (float)( height), (float)( 0), (float)( width / s), (float)( height / s + vo));
|
t->vertexUV(static_cast<float>(width), static_cast<float>(height), static_cast<float>(0), static_cast<float>(width / s), static_cast<float>(height / s + vo));
|
||||||
t->vertexUV((float)(width), (float)( 0), (float)( 0), (float)( width / s), (float)( 0 + vo));
|
t->vertexUV(static_cast<float>(width), static_cast<float>(0), static_cast<float>(0), static_cast<float>(width / s), static_cast<float>(0 + vo));
|
||||||
t->vertexUV((float)(0), (float)( 0), (float)( 0), (float)( 0), (float)( 0 + vo));
|
t->vertexUV(static_cast<float>(0), static_cast<float>(0), static_cast<float>(0), static_cast<float>(0), static_cast<float>(0 + vo));
|
||||||
t->end();
|
t->end();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,9 +36,12 @@ protected:
|
|||||||
virtual void mouseReleased(int x, int y, int buttonNum);
|
virtual void mouseReleased(int x, int y, int buttonNum);
|
||||||
virtual void buttonClicked(Button *button);
|
virtual void buttonClicked(Button *button);
|
||||||
public:
|
public:
|
||||||
virtual void init(Minecraft *minecraft, int width, int height);
|
virtual void init(Minecraft *minecraft, int width, int height);
|
||||||
virtual void setSize(int width, int height);
|
virtual void setSize(int width, int height);
|
||||||
virtual void init();
|
virtual void init();
|
||||||
|
virtual void handlePasteRequest() {}
|
||||||
|
virtual void handleHistoryUp() {}
|
||||||
|
virtual void handleHistoryDown() {}
|
||||||
virtual void updateEvents();
|
virtual void updateEvents();
|
||||||
virtual void mouseEvent();
|
virtual void mouseEvent();
|
||||||
virtual void keyboardEvent();
|
virtual void keyboardEvent();
|
||||||
|
|||||||
@@ -257,8 +257,8 @@ bool KeyboardMouseInput::IsMouseButtonReleased(int button) const
|
|||||||
|
|
||||||
void KeyboardMouseInput::ConsumeMouseDelta(float &dx, float &dy)
|
void KeyboardMouseInput::ConsumeMouseDelta(float &dx, float &dy)
|
||||||
{
|
{
|
||||||
dx = (float)m_mouseDeltaAccumX;
|
dx = static_cast<float>(m_mouseDeltaAccumX);
|
||||||
dy = (float)m_mouseDeltaAccumY;
|
dy = static_cast<float>(m_mouseDeltaAccumY);
|
||||||
m_mouseDeltaAccumX = 0;
|
m_mouseDeltaAccumX = 0;
|
||||||
m_mouseDeltaAccumY = 0;
|
m_mouseDeltaAccumY = 0;
|
||||||
}
|
}
|
||||||
@@ -375,12 +375,12 @@ float KeyboardMouseInput::GetMoveY() const
|
|||||||
|
|
||||||
float KeyboardMouseInput::GetLookX(float sensitivity) const
|
float KeyboardMouseInput::GetLookX(float sensitivity) const
|
||||||
{
|
{
|
||||||
return (float)m_mouseDeltaX * sensitivity;
|
return static_cast<float>(m_mouseDeltaX) * sensitivity;
|
||||||
}
|
}
|
||||||
|
|
||||||
float KeyboardMouseInput::GetLookY(float sensitivity) const
|
float KeyboardMouseInput::GetLookY(float sensitivity) const
|
||||||
{
|
{
|
||||||
return (float)(-m_mouseDeltaY) * sensitivity;
|
return static_cast<float>(-m_mouseDeltaY) * sensitivity;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyboardMouseInput::OnChar(wchar_t c)
|
void KeyboardMouseInput::OnChar(wchar_t c)
|
||||||
|
|||||||
@@ -143,4 +143,4 @@ private:
|
|||||||
|
|
||||||
extern KeyboardMouseInput g_KBMInput;
|
extern KeyboardMouseInput g_KBMInput;
|
||||||
|
|
||||||
#endif // _WINDOWS64
|
#endif
|
||||||
|
|||||||
@@ -22,6 +22,9 @@
|
|||||||
#include "..\..\Minecraft.World\net.minecraft.world.level.tile.h"
|
#include "..\..\Minecraft.World\net.minecraft.world.level.tile.h"
|
||||||
|
|
||||||
#include "..\ClientConnection.h"
|
#include "..\ClientConnection.h"
|
||||||
|
#include "..\Minecraft.h"
|
||||||
|
#include "..\ChatScreen.h"
|
||||||
|
#include "KeyboardMouseInput.h"
|
||||||
#include "..\User.h"
|
#include "..\User.h"
|
||||||
#include "..\..\Minecraft.World\Socket.h"
|
#include "..\..\Minecraft.World\Socket.h"
|
||||||
#include "..\..\Minecraft.World\ThreadName.h"
|
#include "..\..\Minecraft.World\ThreadName.h"
|
||||||
@@ -572,14 +575,28 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
case WM_CHAR:
|
case WM_CHAR:
|
||||||
// Buffer typed characters so UIScene_Keyboard can dispatch them to the Iggy Flash player
|
// Buffer typed characters so UIScene_Keyboard can dispatch them to the Iggy Flash player
|
||||||
if (wParam >= 0x20 || wParam == 0x08 || wParam == 0x0D) // printable chars + backspace + enter
|
if (wParam >= 0x20 || wParam == 0x08 || wParam == 0x0D) // printable chars + backspace + enter
|
||||||
g_KBMInput.OnChar((wchar_t)wParam);
|
g_KBMInput.OnChar(static_cast<wchar_t>(wParam));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_KEYDOWN:
|
case WM_KEYDOWN:
|
||||||
case WM_SYSKEYDOWN:
|
case WM_SYSKEYDOWN:
|
||||||
{
|
{
|
||||||
int vk = (int)wParam;
|
int vk = static_cast<int>(wParam);
|
||||||
if (lParam & 0x40000000) break; // ignore auto-repeat
|
if ((lParam & 0x40000000) && vk != VK_LEFT && vk != VK_RIGHT && vk != VK_BACK)
|
||||||
|
break;
|
||||||
|
#ifdef _WINDOWS64
|
||||||
|
Minecraft* pm = Minecraft::GetInstance();
|
||||||
|
ChatScreen* chat = pm && pm->screen ? dynamic_cast<ChatScreen*>(pm->screen) : nullptr;
|
||||||
|
if (chat)
|
||||||
|
{
|
||||||
|
if (vk == 'V' && (GetKeyState(VK_CONTROL) & 0x8000))
|
||||||
|
{ chat->handlePasteRequest(); break; }
|
||||||
|
if ((vk == VK_UP || vk == VK_DOWN) && !(lParam & 0x40000000))
|
||||||
|
{ if (vk == VK_UP) chat->handleHistoryUp(); else chat->handleHistoryDown(); break; }
|
||||||
|
if (vk >= '1' && vk <= '9') // Prevent hotkey conflicts
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (vk == VK_SHIFT)
|
if (vk == VK_SHIFT)
|
||||||
vk = (MapVirtualKey((lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX) == VK_RSHIFT) ? VK_RSHIFT : VK_LSHIFT;
|
vk = (MapVirtualKey((lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX) == VK_RSHIFT) ? VK_RSHIFT : VK_LSHIFT;
|
||||||
else if (vk == VK_CONTROL)
|
else if (vk == VK_CONTROL)
|
||||||
@@ -592,7 +609,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
case WM_KEYUP:
|
case WM_KEYUP:
|
||||||
case WM_SYSKEYUP:
|
case WM_SYSKEYUP:
|
||||||
{
|
{
|
||||||
int vk = (int)wParam;
|
int vk = static_cast<int>(wParam);
|
||||||
if (vk == VK_SHIFT)
|
if (vk == VK_SHIFT)
|
||||||
vk = (MapVirtualKey((lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX) == VK_RSHIFT) ? VK_RSHIFT : VK_LSHIFT;
|
vk = (MapVirtualKey((lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX) == VK_RSHIFT) ? VK_RSHIFT : VK_LSHIFT;
|
||||||
else if (vk == VK_CONTROL)
|
else if (vk == VK_CONTROL)
|
||||||
@@ -1612,6 +1629,14 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open chat
|
||||||
|
if (g_KBMInput.IsKeyPressed('T') && app.GetGameStarted() && !ui.GetMenuDisplayed(0) && pMinecraft->screen == NULL)
|
||||||
|
{
|
||||||
|
g_KBMInput.ClearCharBuffer();
|
||||||
|
pMinecraft->setScreen(new ChatScreen());
|
||||||
|
SetFocus(g_hWnd);
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// has the game defined profile data been changed (by a profile load)
|
// has the game defined profile data been changed (by a profile load)
|
||||||
if(app.uiGameDefinedDataChangedBitmask!=0)
|
if(app.uiGameDefinedDataChangedBitmask!=0)
|
||||||
|
|||||||
Reference in New Issue
Block a user