Merge remote-tracking branch 'itsRevela/main' into upstream-merge
# Conflicts: # .github/ISSUE_TEMPLATE/config.yml # .github/workflows/nightly.yml # Minecraft.Client/Windows64/4JLibs/libs/4J_Profile.lib # README.md
This commit is contained in:
@@ -66,7 +66,6 @@
|
||||
#include "../Minecraft.World/DurangoStats.h"
|
||||
#include "../Minecraft.World/GenericStats.h"
|
||||
#endif
|
||||
#include <regex>
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -1608,8 +1607,6 @@ 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"";
|
||||
@@ -1626,15 +1623,10 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
|
||||
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";
|
||||
message = L"";
|
||||
}
|
||||
displayOnGui = (packet->m_messageType == ChatPacket::e_ChatCustom);
|
||||
break;
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
#endif
|
||||
|
||||
#include "../Common/Leaderboards/LeaderboardManager.h"
|
||||
#include <regex>
|
||||
|
||||
//CMinecraftApp app;
|
||||
unsigned int CMinecraftApp::m_uiLastSignInData = 0;
|
||||
@@ -6793,8 +6794,6 @@ wstring CMinecraftApp::EscapeHTMLString(const wstring& desc)
|
||||
{L'&', L"&"},
|
||||
{L'<', L"<"},
|
||||
{L'>', L">"},
|
||||
{L'\"', L"""},
|
||||
{L'\'', L"'"},
|
||||
};
|
||||
|
||||
wstring finalString = L"";
|
||||
@@ -6809,60 +6808,70 @@ wstring CMinecraftApp::EscapeHTMLString(const wstring& desc)
|
||||
return finalString;
|
||||
}
|
||||
|
||||
wstring CMinecraftApp::FormatChatMessage(const wstring& desc, bool applyColor)
|
||||
wstring CMinecraftApp::FormatChatMessage(const wstring& desc, bool applyStyling)
|
||||
{
|
||||
static std::wstring_view colorFormatString = L"<font color=\"#%08x\" shadowcolor=\"#%08x\">";
|
||||
static std::wregex IDS_Pattern(LR"(\{\*IDS_(\d+)\*\})"); //maybe theres a better way to do translateable IDS
|
||||
static std::wstring_view colorFormatString = L"<font color=\"#%08x\">";
|
||||
|
||||
wstring results = desc;
|
||||
wchar_t replacements[64];
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_0), 0xFFFFFFFF);
|
||||
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_0), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§0", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_1), 0xFFFFFFFF);
|
||||
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_1), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§1", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_2), 0xFFFFFFFF);
|
||||
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_2), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§2", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_3), 0xFFFFFFFF);
|
||||
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_3), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§3", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_4), 0xFFFFFFFF);
|
||||
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_4), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§4", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_5), 0xFFFFFFFF);
|
||||
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_5), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§5", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_6), 0xFFFFFFFF);
|
||||
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_6), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§6", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_7), 0xFFFFFFFF);
|
||||
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_7), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§7", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_8), 0xFFFFFFFF);
|
||||
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_8), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§8", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_9), 0xFFFFFFFF);
|
||||
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_9), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§9", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_a), 0xFFFFFFFF);
|
||||
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_a), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§a", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_b), 0xFFFFFFFF);
|
||||
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_b), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§b", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_c), 0xFFFFFFFF);
|
||||
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_c), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§c", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_d), 0xFFFFFFFF);
|
||||
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_d), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§d", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_e), 0xFFFFFFFF);
|
||||
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_e), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§e", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_f), 0xFFFFFFFF);
|
||||
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_f), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§f", replacements);
|
||||
results = replaceAll(results, L"§r", replacements); //we only support color so reset is the same as white color
|
||||
|
||||
if (applyStyling) {
|
||||
std::wsmatch match;
|
||||
while (std::regex_search(results, match, IDS_Pattern)) {
|
||||
results = replaceAll(results, match[0], app.GetString(std::stoi(match[1].str())));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -569,7 +569,7 @@ public:
|
||||
int GetHTMLFontSize(EHTMLFontSize size);
|
||||
wstring FormatHTMLString(int iPad, const wstring& desc, int shadowColour = 0xFFFFFFFF);
|
||||
wstring EscapeHTMLString(const wstring &desc);
|
||||
wstring FormatChatMessage(const wstring& desc, bool applyColor = true);
|
||||
wstring FormatChatMessage(const wstring& desc, bool applyStyling = true);
|
||||
wstring GetActionReplacement(int iPad, unsigned char ucAction);
|
||||
wstring GetVKReplacement(unsigned int uiVKey);
|
||||
wstring GetIconReplacement(unsigned int uiIcon);
|
||||
|
||||
@@ -311,19 +311,27 @@ void UIScene::loadMovie()
|
||||
|
||||
if(!app.hasArchiveFile(moviePath))
|
||||
{
|
||||
app.DebugPrintf("WARNING: Could not find iggy movie %ls, falling back on 720\n", moviePath.c_str());
|
||||
app.DebugPrintf("WARNING: Could not find iggy movie %ls, trying other resolutions\n", moviePath.c_str());
|
||||
|
||||
// Try 720 first, then 1080 as final fallback
|
||||
moviePath = getMoviePath();
|
||||
moviePath.append(L"720.swf");
|
||||
m_loadedResolution = eSceneResolution_720;
|
||||
|
||||
if(!app.hasArchiveFile(moviePath))
|
||||
{
|
||||
app.DebugPrintf("ERROR: Could not find any iggy movie for %ls!\n", moviePath.c_str());
|
||||
moviePath = getMoviePath();
|
||||
moviePath.append(L"1080.swf");
|
||||
m_loadedResolution = eSceneResolution_1080;
|
||||
|
||||
if(!app.hasArchiveFile(moviePath))
|
||||
{
|
||||
app.DebugPrintf("ERROR: Could not find any iggy movie for %ls!\n", moviePath.c_str());
|
||||
#ifndef _CONTENT_PACKAGE
|
||||
__debugbreak();
|
||||
__debugbreak();
|
||||
#endif
|
||||
app.FatalLoadError();
|
||||
app.FatalLoadError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -266,8 +266,10 @@ void UIScene_HUD::handleReload()
|
||||
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);
|
||||
|
||||
int iGuiScale;
|
||||
|
||||
|
||||
@@ -287,6 +287,11 @@ UIScene_LoadMenu::UIScene_LoadMenu(int iPad, void *initData, UILayer *parentLaye
|
||||
WCHAR TempString[256];
|
||||
swprintf((WCHAR *)TempString, 256, L"%ls: %ls", app.GetString(IDS_SLIDER_DIFFICULTY), app.GetString(IDS_HARDCORE));
|
||||
m_sliderDifficulty.init(TempString, eControl_Difficulty, 0, 4, 4);
|
||||
|
||||
// Hardcore locks game mode to Survival
|
||||
m_iGameModeId = GameType::SURVIVAL->getId();
|
||||
m_bGameModeCreative = false;
|
||||
m_buttonGamemode.setLabel(app.GetString(IDS_GAMEMODE_SURVIVAL));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -427,15 +432,7 @@ void UIScene_LoadMenu::updateTooltips()
|
||||
void UIScene_LoadMenu::updateComponents()
|
||||
{
|
||||
m_parentLayer->showComponent(m_iPad,eUIComponent_Panorama,true);
|
||||
|
||||
if(RenderManager.IsWidescreen())
|
||||
{
|
||||
m_parentLayer->showComponent(m_iPad,eUIComponent_Logo,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_parentLayer->showComponent(m_iPad,eUIComponent_Logo,false);
|
||||
}
|
||||
m_parentLayer->showComponent(m_iPad,eUIComponent_Logo,false);
|
||||
}
|
||||
|
||||
wstring UIScene_LoadMenu::getMoviePath()
|
||||
@@ -582,7 +579,9 @@ void UIScene_LoadMenu::tick()
|
||||
m_MoreOptionsParams.bAllowFriendsOfFriends = TRUE;
|
||||
}
|
||||
|
||||
m_bHardcore = app.GetGameHostOption(uiHostOptions, eGameHostOption_Hardcore) > 0;
|
||||
// Use thumbnail host options if available, otherwise preserve the level.dat value
|
||||
if (app.GetGameHostOption(uiHostOptions, eGameHostOption_Hardcore) > 0)
|
||||
m_bHardcore = true;
|
||||
if (m_bHardcore)
|
||||
{
|
||||
WCHAR TempString[256];
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
static wstring ReadLevelNameFromSaveFile(const wstring& filePath, bool *outHardcore = nullptr)
|
||||
{
|
||||
// Check for a worldname.txt sidecar written by the rename feature first
|
||||
wstring sidecarName = L"";
|
||||
size_t slashPos = filePath.rfind(L'\\');
|
||||
if (slashPos != wstring::npos)
|
||||
{
|
||||
@@ -50,7 +51,7 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath, bool *outHardc
|
||||
{
|
||||
wchar_t wbuf[128] = {};
|
||||
MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, 127);
|
||||
return wstring(wbuf);
|
||||
sidecarName = wbuf;
|
||||
}
|
||||
}
|
||||
else fclose(fr);
|
||||
@@ -58,10 +59,10 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath, bool *outHardc
|
||||
}
|
||||
|
||||
HANDLE hFile = CreateFileW(filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, nullptr);
|
||||
if (hFile == INVALID_HANDLE_VALUE) return L"";
|
||||
if (hFile == INVALID_HANDLE_VALUE) return sidecarName;
|
||||
|
||||
DWORD fileSize = GetFileSize(hFile, nullptr);
|
||||
if (fileSize < 12 || fileSize == INVALID_FILE_SIZE) { CloseHandle(hFile); return L""; }
|
||||
if (fileSize < 12 || fileSize == INVALID_FILE_SIZE) { CloseHandle(hFile); return sidecarName; }
|
||||
|
||||
unsigned char *rawData = new unsigned char[fileSize];
|
||||
DWORD bytesRead = 0;
|
||||
@@ -69,7 +70,7 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath, bool *outHardc
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
delete[] rawData;
|
||||
return L"";
|
||||
return sidecarName;
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
|
||||
@@ -84,7 +85,7 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath, bool *outHardc
|
||||
if (decompSize == 0 || decompSize > 128 * 1024 * 1024)
|
||||
{
|
||||
delete[] rawData;
|
||||
return L"";
|
||||
return sidecarName;
|
||||
}
|
||||
saveData = new unsigned char[decompSize];
|
||||
Compression::getCompression()->Decompress(saveData, &decompSize, rawData + 8, fileSize - 8);
|
||||
@@ -140,6 +141,10 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath, bool *outHardc
|
||||
|
||||
if (freeSaveData) delete[] saveData;
|
||||
delete[] rawData;
|
||||
|
||||
// Prefer the sidecar name (user-renamed) over the level.dat name
|
||||
if (!sidecarName.empty()) return sidecarName;
|
||||
|
||||
// "world" is the engine default - it means no real name was ever set,
|
||||
// so return empty to let the caller fall back to the save filename (timestamp).
|
||||
if (result == L"world") result = L"";
|
||||
@@ -774,7 +779,16 @@ void UIScene_LoadOrJoinMenu::tick()
|
||||
wchar_t wFilename[MAX_SAVEFILENAME_LENGTH];
|
||||
ZeroMemory(wFilename, sizeof(wFilename));
|
||||
mbstowcs(wFilename, m_pSaveDetails->SaveInfoA[origIdx].UTF8SaveFilename, MAX_SAVEFILENAME_LENGTH - 1);
|
||||
wstring filePath = wstring(L"Windows64\\GameHDD\\") + wstring(wFilename) + wstring(L"\\saveData.ms");
|
||||
wchar_t wTitle[MAX_DISPLAYNAME_LENGTH];
|
||||
ZeroMemory(wTitle, sizeof(wTitle));
|
||||
mbstowcs(wTitle, m_pSaveDetails->SaveInfoA[origIdx].UTF8SaveTitle, MAX_DISPLAYNAME_LENGTH - 1);
|
||||
wstring filePath = wstring(L"Windows64\\GameHDD\\") + wstring(wFilename) + wstring(L"\\") + wstring(wTitle) + wstring(L".ms");
|
||||
// Fallback to legacy saveData.ms if new-style filename doesn't exist
|
||||
{
|
||||
DWORD attrs = GetFileAttributesW(filePath.c_str());
|
||||
if (attrs == INVALID_FILE_ATTRIBUTES)
|
||||
filePath = wstring(L"Windows64\\GameHDD\\") + wstring(wFilename) + wstring(L"\\saveData.ms");
|
||||
}
|
||||
|
||||
HANDLE hFile = CreateFileW(filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, nullptr);
|
||||
DWORD fileSize = 0;
|
||||
|
||||
@@ -1167,15 +1167,6 @@ void UIScene_SkinSelectMenu::handlePackIndexChanged()
|
||||
updatePackDisplay();
|
||||
}
|
||||
|
||||
std::wstring fakeWideToRealWide(const wchar_t* original)
|
||||
{
|
||||
const char* name = reinterpret_cast<const char*>(original);
|
||||
int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, nullptr, 0);
|
||||
std::wstring wName(len, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, name, -1, &wName[0], len);
|
||||
return wName.c_str();
|
||||
}
|
||||
|
||||
void UIScene_SkinSelectMenu::updatePackDisplay()
|
||||
{
|
||||
m_currentPackCount = app.m_dlcManager.getPackCount(DLCManager::e_DLCType_Skin) + SKIN_SELECT_MAX_DEFAULTS;
|
||||
@@ -1183,18 +1174,16 @@ void UIScene_SkinSelectMenu::updatePackDisplay()
|
||||
if(m_packIndex >= SKIN_SELECT_MAX_DEFAULTS)
|
||||
{
|
||||
DLCPack *thisPack = app.m_dlcManager.getPack(m_packIndex - SKIN_SELECT_MAX_DEFAULTS, DLCManager::e_DLCType_Skin);
|
||||
// Fix the incorrect string type on title to display correctly
|
||||
setCentreLabel(fakeWideToRealWide(thisPack->getName().c_str()));
|
||||
//setCentreLabel(thisPack->getName().c_str());
|
||||
setCentreLabel(thisPack->getName().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(m_packIndex)
|
||||
{
|
||||
case SKIN_SELECT_PACK_DEFAULT:
|
||||
case SKIN_SELECT_PACK_DEFAULT:
|
||||
setCentreLabel(app.GetString(IDS_NO_SKIN_PACK));
|
||||
break;
|
||||
case SKIN_SELECT_PACK_FAVORITES:
|
||||
case SKIN_SELECT_PACK_FAVORITES:
|
||||
setCentreLabel(app.GetString(IDS_FAVORITES_SKIN_PACK));
|
||||
break;
|
||||
}
|
||||
@@ -1204,18 +1193,16 @@ void UIScene_SkinSelectMenu::updatePackDisplay()
|
||||
if(nextPackIndex >= SKIN_SELECT_MAX_DEFAULTS)
|
||||
{
|
||||
DLCPack *thisPack = app.m_dlcManager.getPack(nextPackIndex - SKIN_SELECT_MAX_DEFAULTS, DLCManager::e_DLCType_Skin);
|
||||
// Fix the incorrect string type on title to display correctly
|
||||
setRightLabel(fakeWideToRealWide(thisPack->getName().c_str()));
|
||||
//setRightLabel(thisPack->getName().c_str());
|
||||
setRightLabel(thisPack->getName().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(nextPackIndex)
|
||||
{
|
||||
case SKIN_SELECT_PACK_DEFAULT:
|
||||
case SKIN_SELECT_PACK_DEFAULT:
|
||||
setRightLabel(app.GetString(IDS_NO_SKIN_PACK));
|
||||
break;
|
||||
case SKIN_SELECT_PACK_FAVORITES:
|
||||
case SKIN_SELECT_PACK_FAVORITES:
|
||||
setRightLabel(app.GetString(IDS_FAVORITES_SKIN_PACK));
|
||||
break;
|
||||
}
|
||||
@@ -1225,18 +1212,16 @@ void UIScene_SkinSelectMenu::updatePackDisplay()
|
||||
if(previousPackIndex >= SKIN_SELECT_MAX_DEFAULTS)
|
||||
{
|
||||
DLCPack *thisPack = app.m_dlcManager.getPack(previousPackIndex - SKIN_SELECT_MAX_DEFAULTS, DLCManager::e_DLCType_Skin);
|
||||
// Fix the incorrect string type on title to display correctly
|
||||
setLeftLabel(fakeWideToRealWide(thisPack->getName().c_str()));
|
||||
//setLeftLabel(thisPack->getName().c_str());
|
||||
setLeftLabel(thisPack->getName().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(previousPackIndex)
|
||||
{
|
||||
case SKIN_SELECT_PACK_DEFAULT:
|
||||
case SKIN_SELECT_PACK_DEFAULT:
|
||||
setLeftLabel(app.GetString(IDS_NO_SKIN_PACK));
|
||||
break;
|
||||
case SKIN_SELECT_PACK_FAVORITES:
|
||||
case SKIN_SELECT_PACK_FAVORITES:
|
||||
setLeftLabel(app.GetString(IDS_FAVORITES_SKIN_PACK));
|
||||
break;
|
||||
}
|
||||
|
||||
+38
-11
@@ -1439,6 +1439,37 @@ void Gui::clearMessages(int iPad)
|
||||
}
|
||||
}
|
||||
|
||||
int getVisibleMessageLength(const wstring& _string) {
|
||||
int visibleMessageLength = 0;
|
||||
bool inHtmlTag = false;
|
||||
|
||||
for (wchar_t _char : _string) {
|
||||
if (_char == L'<') inHtmlTag = true;
|
||||
if (_char == L'>') inHtmlTag = false;
|
||||
|
||||
if (!inHtmlTag) visibleMessageLength++;
|
||||
}
|
||||
|
||||
return visibleMessageLength;
|
||||
}
|
||||
|
||||
int getVisibleIndexToRaw(const wstring& _string, size_t target) {
|
||||
int visibleMessageLength = 0;
|
||||
bool inHtmlTag = false;
|
||||
|
||||
for (size_t i = 0; i < _string.size(); i++) {
|
||||
if (_string[i] == L'<') inHtmlTag = true;
|
||||
if (_string[i] == L'>') inHtmlTag = false;
|
||||
|
||||
if (!inHtmlTag) {
|
||||
if (visibleMessageLength == target) return i;
|
||||
|
||||
visibleMessageLength++;
|
||||
}
|
||||
}
|
||||
return _string.size();
|
||||
}
|
||||
|
||||
|
||||
void Gui::addMessage(const wstring& _string,int iPad,bool bIsDeathMessage)
|
||||
{
|
||||
@@ -1522,29 +1553,25 @@ void Gui::addMessage(const wstring& _string,int iPad,bool bIsDeathMessage)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
while (string.length() > maximumChars)
|
||||
while (getVisibleMessageLength(string) > maximumChars)
|
||||
{
|
||||
unsigned int i = 1;
|
||||
while (i < string.length() && (i + 1) <= maximumChars)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
size_t iLast=string.find_last_of(L" ",i);
|
||||
size_t cutOffset = getVisibleIndexToRaw(string, maximumChars);
|
||||
|
||||
size_t iLast=string.find_last_of(L" ", cutOffset);
|
||||
switch(XGetLanguage())
|
||||
{
|
||||
case XC_LANGUAGE_JAPANESE:
|
||||
case XC_LANGUAGE_TCHINESE:
|
||||
case XC_LANGUAGE_KOREAN:
|
||||
iLast = maximumChars;
|
||||
iLast = cutOffset;
|
||||
break;
|
||||
default:
|
||||
iLast=string.find_last_of(L" ",i);
|
||||
iLast=string.find_last_of(L" ", cutOffset);
|
||||
break;
|
||||
}
|
||||
|
||||
// if a space was found, include the space on this line
|
||||
if(iLast!=i)
|
||||
if(iLast!=cutOffset)
|
||||
{
|
||||
iLast++;
|
||||
}
|
||||
|
||||
@@ -972,7 +972,7 @@ void PlayerConnection::handleChat(shared_ptr<ChatPacket> packet)
|
||||
}
|
||||
#else
|
||||
wstring formatted = L"<" + player->name + L"> " + message;
|
||||
server->getPlayers()->broadcastAll(shared_ptr<ChatPacket>(new ChatPacket(app.FormatChatMessage(formatted, false))));
|
||||
server->getPlayers()->broadcastAll(shared_ptr<ChatPacket>(new ChatPacket(formatted)));
|
||||
#endif
|
||||
chatSpamTickCount += SharedConstants::TICKS_PER_SECOND;
|
||||
if (chatSpamTickCount > SharedConstants::TICKS_PER_SECOND * 10)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -9,6 +9,11 @@
|
||||
#include "../../Minecraft.World/LevelSettings.h"
|
||||
#include "../../Minecraft.World/BiomeSource.h"
|
||||
#include "../../Minecraft.World/LevelType.h"
|
||||
#include "stb_image_write.h"
|
||||
|
||||
extern ID3D11Device* g_pd3dDevice;
|
||||
extern ID3D11DeviceContext* g_pImmediateContext;
|
||||
extern IDXGISwapChain* g_pSwapChain;
|
||||
|
||||
CConsoleMinecraftApp app;
|
||||
|
||||
@@ -33,9 +38,120 @@ void CConsoleMinecraftApp::FatalLoadError()
|
||||
{
|
||||
}
|
||||
|
||||
static const int THUMBNAIL_SIZE = 64;
|
||||
|
||||
void CConsoleMinecraftApp::CaptureSaveThumbnail()
|
||||
{
|
||||
RenderManager.CaptureThumbnail(&m_ThumbnailBuffer);
|
||||
if (!g_pSwapChain || !g_pd3dDevice || !g_pImmediateContext)
|
||||
return;
|
||||
|
||||
// Release any previous capture
|
||||
if (m_ThumbnailBuffer.Allocated())
|
||||
m_ThumbnailBuffer.Release();
|
||||
|
||||
// Get the backbuffer
|
||||
ID3D11Texture2D* pBackBuffer = nullptr;
|
||||
HRESULT hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBackBuffer);
|
||||
if (FAILED(hr))
|
||||
return;
|
||||
|
||||
D3D11_TEXTURE2D_DESC backDesc = {};
|
||||
pBackBuffer->GetDesc(&backDesc);
|
||||
|
||||
// Create a staging texture at backbuffer size to read pixels
|
||||
D3D11_TEXTURE2D_DESC stagingDesc = backDesc;
|
||||
stagingDesc.Usage = D3D11_USAGE_STAGING;
|
||||
stagingDesc.BindFlags = 0;
|
||||
stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
stagingDesc.MiscFlags = 0;
|
||||
|
||||
ID3D11Texture2D* pStaging = nullptr;
|
||||
hr = g_pd3dDevice->CreateTexture2D(&stagingDesc, nullptr, &pStaging);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
pBackBuffer->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
g_pImmediateContext->CopyResource(pStaging, pBackBuffer);
|
||||
pBackBuffer->Release();
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mapped = {};
|
||||
hr = g_pImmediateContext->Map(pStaging, 0, D3D11_MAP_READ, 0, &mapped);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
pStaging->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
// Downsample to THUMBNAIL_SIZE x THUMBNAIL_SIZE with simple box filter
|
||||
unsigned char* thumb = new unsigned char[THUMBNAIL_SIZE * THUMBNAIL_SIZE * 4];
|
||||
|
||||
// Crop to square (center crop), then scale down
|
||||
UINT srcSize = (backDesc.Width < backDesc.Height) ? backDesc.Width : backDesc.Height;
|
||||
UINT offsetX = (backDesc.Width - srcSize) / 2;
|
||||
UINT offsetY = (backDesc.Height - srcSize) / 2;
|
||||
|
||||
for (int ty = 0; ty < THUMBNAIL_SIZE; ty++)
|
||||
{
|
||||
for (int tx = 0; tx < THUMBNAIL_SIZE; tx++)
|
||||
{
|
||||
// Map thumbnail pixel to source region
|
||||
UINT sx = offsetX + (tx * srcSize) / THUMBNAIL_SIZE;
|
||||
UINT sy = offsetY + (ty * srcSize) / THUMBNAIL_SIZE;
|
||||
|
||||
const unsigned char* src = (const unsigned char*)mapped.pData + sy * mapped.RowPitch + sx * 4;
|
||||
unsigned char* dst = thumb + (ty * THUMBNAIL_SIZE + tx) * 4;
|
||||
|
||||
dst[0] = src[0]; // R (or B depending on format, but BGRA->RGBA swap below)
|
||||
dst[1] = src[1]; // G
|
||||
dst[2] = src[2]; // B
|
||||
dst[3] = 0xFF; // A
|
||||
}
|
||||
}
|
||||
|
||||
g_pImmediateContext->Unmap(pStaging, 0);
|
||||
pStaging->Release();
|
||||
|
||||
// If backbuffer is BGRA, swap to RGBA for PNG
|
||||
if (backDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM || backDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB)
|
||||
{
|
||||
for (int i = 0; i < THUMBNAIL_SIZE * THUMBNAIL_SIZE; i++)
|
||||
{
|
||||
unsigned char tmp = thumb[i * 4];
|
||||
thumb[i * 4] = thumb[i * 4 + 2];
|
||||
thumb[i * 4 + 2] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// Encode to PNG in memory using stbi_write_png_to_func
|
||||
struct PngBuffer { unsigned char* data; int size; int capacity; } pngBuf = {};
|
||||
pngBuf.capacity = THUMBNAIL_SIZE * THUMBNAIL_SIZE * 4 + 256;
|
||||
pngBuf.data = (unsigned char*)malloc(pngBuf.capacity);
|
||||
pngBuf.size = 0;
|
||||
|
||||
stbi_write_png_to_func([](void* ctx, void* data, int size) {
|
||||
PngBuffer* buf = (PngBuffer*)ctx;
|
||||
if (buf->size + size > buf->capacity)
|
||||
{
|
||||
buf->capacity = (buf->size + size) * 2;
|
||||
buf->data = (unsigned char*)realloc(buf->data, buf->capacity);
|
||||
}
|
||||
memcpy(buf->data + buf->size, data, size);
|
||||
buf->size += size;
|
||||
}, &pngBuf, THUMBNAIL_SIZE, THUMBNAIL_SIZE, 4, thumb, THUMBNAIL_SIZE * 4);
|
||||
delete[] thumb;
|
||||
|
||||
if (pngBuf.size > 0)
|
||||
{
|
||||
m_ThumbnailBuffer.m_type = ImageFileBuffer::e_typePNG;
|
||||
m_ThumbnailBuffer.m_pBuffer = pngBuf.data;
|
||||
m_ThumbnailBuffer.m_bufferSize = pngBuf.size;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(pngBuf.data);
|
||||
}
|
||||
}
|
||||
void CConsoleMinecraftApp::GetSaveThumbnail(PBYTE *pbData,DWORD *pdwSize)
|
||||
{
|
||||
|
||||
@@ -1972,7 +1972,11 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
||||
// Present the frame. RenderManager.Present() hardcodes SyncInterval=1,
|
||||
// so when VSync is off we bypass it for uncapped frames. In DXGI
|
||||
// exclusive fullscreen this produces real tearing via direct scanout.
|
||||
if (!g_bVSync && g_pSwapChain)
|
||||
// Force VSync on the main menu regardless of user setting: an uncapped
|
||||
// simple menu scene drives the GPU to thousands of FPS and causes coil
|
||||
// whine on many cards.
|
||||
const bool forceVSyncForMenu = !app.GetGameStarted();
|
||||
if (!g_bVSync && !forceVSyncForMenu && g_pSwapChain)
|
||||
{
|
||||
HRESULT hrPresent = g_pSwapChain->Present(0, 0);
|
||||
// If the direct Present fails (e.g. during fullscreen transition),
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -123,7 +123,7 @@ void glClearColor(float r, float g, float b, float a)
|
||||
|
||||
RenderManager.SetClearColour(D3DCOLOR_RGBA(ir,ig,ib,ia));
|
||||
#else
|
||||
float rgba[4] = {r,g,b,a};
|
||||
float rgba[4] = {r,g,b,1.0f}; // Force alpha=1 to prevent DWM window transparency
|
||||
RenderManager.SetClearColour(rgba);
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user