fix: resolve merge conflicts and integrate XML locale updates (#1)

Resolve merge conflicts across multiple components
Merge and synchronize XML locale changes
Ensure consistency between string resources and localization files
Minor fixes to restore successful builds after merge
This commit is contained in:
Fireblade 2026-04-10 19:47:59 -04:00 committed by GitHub
parent 0ad7e383fa
commit 0ed96f1592
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 1200 additions and 2424 deletions

View file

@ -78,16 +78,14 @@
"**/Minecraft.Client/PSVitaMedia/Media": true,
"**/Minecraft.Client/PSVitaMedia/Tutorial": true,
"**/Minecraft.Client/PSVitaMedia/Minecraft.Client.self": true,
"**/Minecraft.Client/redist64": true
"**/Minecraft.Client/sce_sys": true
"**/Minecraft.Client/TROPDIR": true
"**/Minecraft.Client/redist64": true,
"**/Minecraft.Client/sce_sys": true,
"**/Minecraft.Client/TROPDIR": true,
"**/Minecraft.Client/Windows64/4JLibs/libs": true,
"**/Minecraft.Client/Windows64/GameConfig/Minecraft.spa": true,
"**/Minecraft.Client/Windows64/GameHDD": true,
"**/Minecraft.Client/Windows64/Iggy/lib": true,
"**/Minecraft.Client/Windows64Media": true,
"**/Minecraft.Client/Windows64Media/4J_strings.h": false,
"**/Minecraft.Client/Windows64Media/strings.h": false,
"**/Minecraft.Client/x64": true,
"**/Minecraft.Client/Xbox/4JLibs/libs": true,
"**/Minecraft.Client/Xbox/4JLibs/Media": true,
@ -110,7 +108,7 @@
"**/Minecraft.Client/thumbnailTest256.png": true,
"**/Minecraft.Client/thumbnailTest1028.png": true,
"**/Minecraft.World/x64_Debug": true,
"**/Minecraft.World/x64_Release": true
"**/Minecraft.World/x64_Release": true,
"**/x64": true
}
}
}

View file

@ -88,9 +88,58 @@ if(PLATFORM_NAME STREQUAL "Windows64") # Server is only supported on Windows for
add_subdirectory(Minecraft.Server)
endif()
if(TARGET GenerateStringsHeader_Minecraft.Client)
add_dependencies(Minecraft.World GenerateStringsHeader_Minecraft.Client)
endif()
# ---
# String ID lookup generation
# ---
set(STRING_ID_LOOKUP_OUTPUT
"${CMAKE_CURRENT_BINARY_DIR}/generated/StringIdLookup.generated.inc"
)
set(STRING_ID_XML_ROOT
"${CMAKE_SOURCE_DIR}/Minecraft.Client/Windows64Media/loc"
)
file(GLOB_RECURSE STRING_ID_XML_FILES CONFIGURE_DEPENDS
"${STRING_ID_XML_ROOT}/*.xml"
)
set(GENERATED_STRINGS_HEADER
"${CMAKE_BINARY_DIR}/generated/Windows64Media/strings.h"
)
add_custom_command(
OUTPUT "${STRING_ID_LOOKUP_OUTPUT}"
COMMAND ${CMAKE_COMMAND}
"-DHEADER_LIST=${GENERATED_STRINGS_HEADER}"
"-DOUTPUT_FILE=${STRING_ID_LOOKUP_OUTPUT}"
-P "${CMAKE_SOURCE_DIR}/cmake/GenerateStringIdLookup.cmake"
DEPENDS
${STRING_ID_XML_FILES}
"${GENERATED_STRINGS_HEADER}"
"${CMAKE_SOURCE_DIR}/cmake/GenerateStringIdLookup.cmake"
COMMENT "Generating StringIdLookup.generated.inc"
VERBATIM
)
add_custom_target(GenerateStringIdLookup ALL
DEPENDS "${STRING_ID_LOOKUP_OUTPUT}"
)
if(TARGET GenerateStringsHeader_Minecraft.Client)
add_dependencies(GenerateStringIdLookup GenerateStringsHeader_Minecraft.Client)
endif()
set_property(TARGET GenerateStringIdLookup PROPERTY FOLDER "Build")
# ---
# Build versioning
# ---
set(BUILDVER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/cmake/GenerateBuildVer.cmake")
set(BUILDVER_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/generated/Common/BuildVer.h")
@ -108,10 +157,25 @@ if(PLATFORM_NAME STREQUAL "Windows64")
add_dependencies(Minecraft.Server GenerateBuildVer)
endif()
add_dependencies(Minecraft.Client GenerateStringIdLookup)
if(TARGET Minecraft.Server)
add_dependencies(Minecraft.Server GenerateStringIdLookup)
endif()
target_include_directories(Minecraft.Client PRIVATE
"${CMAKE_CURRENT_BINARY_DIR}/generated"
)
target_include_directories(Minecraft.Server PRIVATE
"${CMAKE_CURRENT_BINARY_DIR}/generated"
)
# ---
# Project organisation
# ---
# Set the startup project for Visual Studio
set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT Minecraft.Client)
# Setup folders for Visual Studio, just hides the build targets under a sub folder

View file

@ -25,6 +25,32 @@ set(MINECRAFT_CLIENT_SOURCES
add_executable(Minecraft.Client ${MINECRAFT_CLIENT_SOURCES} )
set(MINECRAFT_CLIENT_COMPILETIME_STRINGS_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/${PLATFORM_NAME}Media/strings.h")
if(PLATFORM_NAME STREQUAL "Windows64")
set(MINECRAFT_CLIENT_COMPILETIME_STRINGS_HEADER "${CMAKE_BINARY_DIR}/generated/Windows64Media/strings.h")
file(GLOB_RECURSE MINECRAFT_CLIENT_WINDOWS_LOCALIZATION_XML CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/Windows64Media/loc/*.xml"
)
add_custom_command(
OUTPUT "${MINECRAFT_CLIENT_COMPILETIME_STRINGS_HEADER}"
COMMAND ${CMAKE_COMMAND}
"-DXML_ROOT=${CMAKE_CURRENT_SOURCE_DIR}/Windows64Media/loc"
"-DOUTPUT_FILE=${MINECRAFT_CLIENT_COMPILETIME_STRINGS_HEADER}"
-P "${CMAKE_SOURCE_DIR}/cmake/GenerateStringsHeaderFromXml.cmake"
DEPENDS
${MINECRAFT_CLIENT_WINDOWS_LOCALIZATION_XML}
"${CMAKE_SOURCE_DIR}/cmake/GenerateStringsHeaderFromXml.cmake"
COMMENT "Generating compile-time string IDs from XML"
VERBATIM
)
add_custom_target(GenerateStringsHeader_Minecraft.Client DEPENDS "${MINECRAFT_CLIENT_COMPILETIME_STRINGS_HEADER}")
set_property(TARGET GenerateStringsHeader_Minecraft.Client PROPERTY FOLDER "Build")
add_dependencies(Minecraft.Client GenerateStringsHeader_Minecraft.Client)
add_dependencies(Minecraft.Client GenerateStringIdLookup)
endif()
# Only define executable on windows
if(PLATFORM_NAME STREQUAL "Windows64")
set_target_properties(Minecraft.Client PROPERTIES WIN32_EXECUTABLE TRUE)
@ -88,6 +114,25 @@ set(ASSET_FOLDER_PAIRS
)
setup_asset_folder_copy(Minecraft.Client "${ASSET_FOLDER_PAIRS}")
# copy prebuilt loc folder and use it lmao
if(PLATFORM_NAME STREQUAL "Windows64")
add_custom_target(AssetLocalizationCopy_Minecraft.Client ALL
COMMAND ${CMAKE_COMMAND} -E rm -f "$<TARGET_FILE_DIR:Minecraft.Client>/Common/Localization/strings.h"
COMMAND ${CMAKE_COMMAND} -E rm -f "$<TARGET_FILE_DIR:Minecraft.Client>/Common/Localization/4J_strings.h"
COMMAND ${CMAKE_COMMAND}
"-DCOPY_SOURCE=${CMAKE_CURRENT_SOURCE_DIR}/Windows64Media/loc"
"-DCOPY_DEST=$<TARGET_FILE_DIR:Minecraft.Client>/Common/Localization"
-P "${CMAKE_SOURCE_DIR}/cmake/CopyFolderScript.cmake"
COMMAND ${CMAKE_COMMAND} -E rm -f "$<TARGET_FILE_DIR:Minecraft.Client>/Windows64Media/strings.h"
COMMAND ${CMAKE_COMMAND} -E rm -f "$<TARGET_FILE_DIR:Minecraft.Client>/Windows64Media/4J_strings.h"
COMMENT "Copying language files into build folder..."
VERBATIM
)
add_dependencies(Minecraft.Client AssetLocalizationCopy_Minecraft.Client)
set_property(TARGET AssetLocalizationCopy_Minecraft.Client PROPERTY FOLDER "Build")
endif()
# Copy redist files
add_copyredist_target(Minecraft.Client)

View file

@ -328,11 +328,73 @@ void CMinecraftApp::DebugPrintf(int user, const char *szFormat, ...)
#endif
}
namespace
{
const wchar_t *ResolveStringKeyFromId(int iID)
{
#ifdef _WINDOWS64
switch(iID)
{
#include "StringIdLookup.generated.inc"
default:
return nullptr;
}
#else
(void)iID;
return nullptr;
#endif
}
}
LPCWSTR CMinecraftApp::GetString(int iID)
{
//return L"Değişiklikler ve Yenilikler";
//return L"ÕÕÕÕÖÖÖÖ";
return app.m_stringTable->getString(iID);
if(app.m_stringTable == nullptr)
{
const wchar_t *key = ResolveStringKeyFromId(iID);
return key != nullptr ? key : L"";
}
LPCWSTR byIndex = app.m_stringTable->getString(iID);
if(byIndex != nullptr && byIndex[0] != L'\0')
{
return byIndex;
}
const wchar_t *key = ResolveStringKeyFromId(iID);
if(key != nullptr)
{
LPCWSTR byKey = app.m_stringTable->getString(key);
if(byKey != nullptr && byKey[0] != L'\0')
{
return byKey;
}
// Prefer visible fallback text instead of returning an empty string.
return key;
}
return L"";
}
LPCWSTR CMinecraftApp::GetString(const wchar_t *id)
{
if(id == nullptr)
{
return L"";
}
if(app.m_stringTable == nullptr)
{
return id;
}
LPCWSTR byKey = app.m_stringTable->getString(id);
if(byKey != nullptr && byKey[0] != L'\0')
{
return byKey;
}
return id;
}
void CMinecraftApp::SetAction(int iPad, eXuiAction action, LPVOID param)
@ -4563,6 +4625,58 @@ void CMinecraftApp::loadStringTable()
// we need to unload the current string table, this is a reload
delete m_stringTable;
}
#ifdef _WINDOWS64
m_stringTable = nullptr;
const wstring localisationCandidates[] =
{
L"Common\\Localization", // Fireblade - check multiple directories before resulting to .loc usage
L"Windows64Media\\loc",
L"..\\Minecraft.Client\\Windows64Media\\loc"
};
for (const auto &localisationFolder : localisationCandidates)
{
File localisationDirectory(localisationFolder);
if (localisationDirectory.exists() && localisationDirectory.isDirectory())
{
StringTable *candidateTable = new StringTable(localisationFolder); // Fireblade - xml before loc
const bool hasKeyString = candidateTable->hasStringKey(L"IDS_OK");
bool hasIndexString = false;
#ifdef IDS_OK
LPCWSTR indexedString = candidateTable->getString(IDS_OK);
hasIndexString = (indexedString != nullptr && indexedString[0] != L'\0');
#endif
if (hasKeyString || hasIndexString)
{
m_stringTable = candidateTable;
app.DebugPrintf("Loaded language data from '%ls'\n", localisationFolder.c_str());
break;
}
app.DebugPrintf("Ignoring localisation path '%ls' (missing expected IDs)\n", localisationFolder.c_str());
delete candidateTable;
}
}
if (m_stringTable == nullptr && m_mediaArchive != nullptr) // Fireblade - fallback to previous behavior
{
const wstring localisationFile = L"languages.loc";
if (m_mediaArchive->hasFile(localisationFile))
{
byteArray locFile = m_mediaArchive->getFile(localisationFile);
m_stringTable = new StringTable(locFile.data, locFile.length);
delete locFile.data;
}
}
if (m_stringTable == nullptr)
{
app.DebugPrintf("Failed to initialize language data\n");
assert(false);
}
#else // Fireblade - other platforms keep same logic
wstring localisationFile = L"languages.loc";
if (m_mediaArchive->hasFile(localisationFile))
{
@ -4577,6 +4691,7 @@ void CMinecraftApp::loadStringTable()
// AHHHHHHHHH.
}
#endif
#endif
}
int CMinecraftApp::PrimaryPlayerSignedOutReturned(void *pParam,int iPad,const C4JStorage::EMessageResult)

View file

@ -157,6 +157,7 @@ public:
void SetSpecialTutorialCompletionFlag(int iPad, int index);
static LPCWSTR GetString(int iID);
static LPCWSTR GetString(const wchar_t *id);
eGameMode GetGameMode() { return m_eGameMode;}
void SetGameMode(eGameMode eMode) { m_eGameMode=eMode;}

View file

@ -175,6 +175,8 @@ bool CPlatformNetworkManagerStub::Initialise(CGameNetworkManager *pGameNetworkMa
m_bIsOfflineGame = false;
#ifdef _WINDOWS64
m_bJoinPending = false;
m_joinLocalUsersMask = 0;
m_joinHostName[0] = 0;
#endif
m_pSearchParam = nullptr;
m_SessionsUpdatedCallback = nullptr;
@ -296,6 +298,7 @@ void CPlatformNetworkManagerStub::DoWork()
WinsockNetLayer::FinalizeJoin();
BYTE localSmallId = WinsockNetLayer::GetLocalSmallId();
IQNet::m_player[localSmallId].m_smallId = localSmallId;
IQNet::m_player[localSmallId].m_isRemote = false;
IQNet::m_player[localSmallId].m_isHostPlayer = false;
@ -553,6 +556,9 @@ int CPlatformNetworkManagerStub::JoinGame(FriendSessionInfo* searchResult, int l
WinsockNetLayer::StopDiscovery();
wcsncpy_s(m_joinHostName, 32, searchResult->data.hostName, _TRUNCATE);
m_joinLocalUsersMask = localUsersMask;
if (!WinsockNetLayer::BeginJoinGame(hostIP, hostPort))
{
app.DebugPrintf("Win64 LAN: Failed to start async join to %s:%d\n", hostIP, hostPort);

View file

@ -76,8 +76,11 @@ private:
bool m_bIsOfflineGame;
bool m_bIsPrivateGame;
int m_flagIndexSize;
#ifdef _WINDOWS64
bool m_bJoinPending;
int m_joinLocalUsersMask;
wchar_t m_joinHostName[32];
#endif
// This is only maintained by the host, and is not valid on client machines

View file

@ -429,10 +429,28 @@ void UIController::SetupFont()
else if (m_eTargetFont != eFont_NotLoaded)
{
m_mcTTFFont = createFont(m_eTargetFont);
if (m_mcTTFFont == nullptr || !m_mcTTFFont->isLoaded())
{
if (m_mcTTFFont != nullptr)
{
delete m_mcTTFFont;
m_mcTTFFont = nullptr;
}
app.DebugPrintf("[Iggy] Set font indirect to '%hs'.\n", m_mcTTFFont->getFontName().c_str());
IggyFontSetIndirectUTF8( "Mojangles7", -1, IGGY_FONTFLAG_all, m_mcTTFFont->getFontName().c_str(), -1, IGGY_FONTFLAG_none );
IggyFontSetIndirectUTF8( "Mojangles11", -1, IGGY_FONTFLAG_all, m_mcTTFFont->getFontName().c_str(), -1, IGGY_FONTFLAG_none );
app.DebugPrintf("Failed to load font %i. Falling back to bitmaps.\n", nextLanguage);
m_eTargetFont = eFont_Bitmap;
if (m_moj7 == nullptr) m_moj7 = new UIBitmapFont(SFontData::Mojangles_7);
if (m_moj11 == nullptr) m_moj11 = new UIBitmapFont(SFontData::Mojangles_11);
m_moj7->registerFont();
m_moj11->registerFont();
}
else
{
app.DebugPrintf("[Iggy] Set font indirect to '%hs'.\n", m_mcTTFFont->getFontName().c_str());
IggyFontSetIndirectUTF8( "Mojangles7", -1, IGGY_FONTFLAG_all, m_mcTTFFont->getFontName().c_str(), -1, IGGY_FONTFLAG_none );
IggyFontSetIndirectUTF8( "Mojangles11", -1, IGGY_FONTFLAG_all, m_mcTTFFont->getFontName().c_str(), -1, IGGY_FONTFLAG_none );
}
}
else
{

View file

@ -5,7 +5,9 @@
#include "UITTFFont.h"
UITTFFont::UITTFFont(const string &name, const string &path, S32 fallbackCharacter, bool registerAsDefaultFonts)
: m_strFontName(name)
: m_strFontName(name),
pbData(nullptr),
m_loaded(false) // check if loaded
{
app.DebugPrintf("UITTFFont opening %s\n",path.c_str());
@ -19,7 +21,7 @@ UITTFFont::UITTFFont(const string &name, const string &path, S32 fallbackCharact
{
DWORD error = GetLastError();
app.DebugPrintf("Failed to open TTF file with error code %d (%x)\n", error, error);
assert(false);
return; // Fireblade - replaced assert to avoid crashing if font fails to load
}
DWORD dwHigh=0;
@ -33,7 +35,11 @@ UITTFFont::UITTFFont(const string &name, const string &path, S32 fallbackCharact
BOOL bSuccess = ReadFile(file,pbData,dwFileSize,&bytesRead,nullptr);
if(bSuccess==FALSE)
{
delete[] pbData; // Fireblade - avoid memory leaks (hopefully)
pbData = nullptr;
CloseHandle(file);
app.FatalLoadError();
return; // Fireblade - return early in case of error
}
CloseHandle(file);
@ -47,15 +53,26 @@ UITTFFont::UITTFFont(const string &name, const string &path, S32 fallbackCharact
IggyFontInstallTruetypeUTF8 ( (void *)pbData, IGGY_TTC_INDEX_none, "Times New Roman", -1, IGGY_FONTFLAG_none );
IggyFontInstallTruetypeUTF8 ( (void *)pbData, IGGY_TTC_INDEX_none, "Arial", -1, IGGY_FONTFLAG_none );
}
m_loaded = true;
}
else
{
CloseHandle(file);
}
}
UITTFFont::~UITTFFont()
{
delete[] pbData;
}
string UITTFFont::getFontName()
{
return m_strFontName;
}
}
bool UITTFFont::isLoaded() const
{
return m_loaded;
}

View file

@ -6,6 +6,7 @@ private:
const string m_strFontName;
PBYTE pbData;
bool m_loaded;
//DWORD dwDataSize;
public:
@ -13,4 +14,5 @@ public:
~UITTFFont();
string getFontName();
bool isLoaded() const;
};

View file

@ -35,10 +35,31 @@ DLCTexturePack::DLCTexturePack(DWORD id, DLCPack *pack, TexturePack *fallback) :
m_pSoundBank=nullptr;
#endif
if(m_dlcInfoPack->doesPackContainFile(DLCManager::e_DLCType_LocalisationData, L"languages.loc"))
// Fireblade - attempt to use .loc first as i dont think we really mess with dlcs that much
if (m_stringTable == nullptr)
{
DLCLocalisationFile *localisationFile = static_cast<DLCLocalisationFile *>(m_dlcInfoPack->getFile(DLCManager::e_DLCType_LocalisationData, L"languages.loc"));
if(m_dlcInfoPack->doesPackContainFile(DLCManager::e_DLCType_LocalisationData, L"languages.loc"))
{
DLCLocalisationFile *localisationFile = static_cast<DLCLocalisationFile *>(
m_dlcInfoPack->getFile(DLCManager::e_DLCType_LocalisationData, L"languages.loc")
);
m_stringTable = localisationFile->getStringTable();
}
}
// fallback in case languages.loc is not found
if (m_stringTable == nullptr)
{
if (m_dlcInfoPack->getDLCItemsCount(DLCManager::e_DLCType_LocalisationData) > 0)
{
DLCLocalisationFile* localisationFile = static_cast<DLCLocalisationFile*>(
m_dlcInfoPack->getFile(DLCManager::e_DLCType_LocalisationData, 0)
);
if (localisationFile != nullptr)
{
m_stringTable = localisationFile->getStringTable();
}
}
}
// 4J Stu - These calls need to be in the most derived version of the class

View file

@ -45,7 +45,8 @@ C_4JProfile ProfileManager;
CSentientManager SentientManager;
CXuiStringTable StringTable;
#ifndef _XBOX_ONE
#if !defined(_XBOX_ONE) && !defined(_WINDOWS64)
ATG::XMLParser::XMLParser() {}
ATG::XMLParser::~XMLParser() {}
HRESULT ATG::XMLParser::ParseXMLBuffer(CONST CHAR* strBuffer, UINT uBufferSize) { return S_OK; }

View file

@ -16,12 +16,15 @@
#include "../Minecraft.World/net.minecraft.world.level.tile.entity.h"
#include "../Minecraft.World/net.minecraft.world.level.saveddata.h"
#include "../Minecraft.World/net.minecraft.world.entity.animal.h"
#include "../Minecraft.World/net.minecraft.network.h"
#include "../Minecraft.World/net.minecraft.world.food.h"
#include "../Minecraft.World/AABB.h"
#include "../Minecraft.World/Pos.h"
#include "../Minecraft.World/SharedConstants.h"
#include "../Minecraft.World/ChatPacket.h"
#include "../Minecraft.World/StringHelpers.h"
#include "../Minecraft.World/Socket.h"
#include "../Minecraft.World/Achievements.h"
#include "../Minecraft.World/net.minecraft.h"
#include "../Minecraft.World/LevelData.h"
#include "../Minecraft.World/Pos.h"
@ -31,6 +34,7 @@
#include "../Minecraft.World/GenericStats.h"
#include "../Minecraft.World/JavaMath.h"
#include "..\Minecraft.World\ListTag.h"
// 4J Added
#include "../Minecraft.World/net.minecraft.world.item.crafting.h"
#include "Options.h"
@ -2016,8 +2020,6 @@ void PlayerConnection::handleCustomPayload(shared_ptr<CustomPayloadPacket> custo
}
#endif
#if 0
if (CustomPayloadPacket.CUSTOM_BOOK_PACKET.equals(customPayloadPacket.identifier))
if (CustomPayloadPacket::CUSTOM_BOOK_PACKET.compare(customPayloadPacket->identifier) == 0)
{
ByteArrayInputStream bais(customPayloadPacket->data);
@ -2057,9 +2059,7 @@ void PlayerConnection::handleCustomPayload(shared_ptr<CustomPayloadPacket> custo
player->inventory->setItem(player->inventory->selected, sentItem);
}
}
else
#endif
if (CustomPayloadPacket::TRADER_SELECTION_PACKET.compare(customPayloadPacket->identifier) == 0)
else if (CustomPayloadPacket::TRADER_SELECTION_PACKET.compare(customPayloadPacket->identifier) == 0)
{
ByteArrayInputStream bais(customPayloadPacket->data);
DataInputStream input(&bais);

View file

@ -1,26 +1,203 @@
#include "stdafx.h"
#include "StringTable.h"
#include "../Minecraft.World/File.h"
#include "../Minecraft.World/StringHelpers.h"
#include <algorithm>
#include <fstream>
#include <sstream>
// Fireblade - heavily modified from original
// Fireblade - switched from locs to xmls
namespace
{
class XmlStringTableCallback : public ATG::ISAXCallback
{
public:
explicit XmlStringTableCallback(StringTable *table)
: m_table(table),
m_insideValue(false)
{
}
HRESULT StartDocument() override { return S_OK; }
HRESULT EndDocument() override { return S_OK; }
HRESULT ElementBegin(CONST WCHAR *strName, UINT NameLen, CONST ATG::XMLAttribute *pAttributes, UINT NumAttributes) override
{
const wstring elementName(strName, NameLen);
if (equalsIgnoreCase(elementName, L"data"))
{
m_id.clear();
m_value.clear();
for (UINT i = 0; i < NumAttributes; ++i)
{
const ATG::XMLAttribute &attribute = pAttributes[i];
const wstring attributeName(attribute.strName, attribute.NameLen);
if (equalsIgnoreCase(attributeName, L"name") && attribute.strValue != nullptr)
{
m_id.assign(attribute.strValue, attribute.ValueLen);
break;
}
}
}
else if (equalsIgnoreCase(elementName, L"value") && !m_id.empty())
{
m_insideValue = true;
m_value.clear();
}
return S_OK;
}
HRESULT ElementContent(CONST WCHAR *strData, UINT DataLen, BOOL /*More*/) override
{
if (m_insideValue && strData != nullptr && DataLen > 0)
{
m_value.append(strData, DataLen);
}
return S_OK;
}
HRESULT ElementEnd(CONST WCHAR *strName, UINT NameLen) override
{
const wstring elementName(strName, NameLen);
if (equalsIgnoreCase(elementName, L"value"))
{
m_insideValue = false;
}
else if (equalsIgnoreCase(elementName, L"data"))
{
if (!m_id.empty())
{
m_table->setStringValue(m_id, m_value);
}
m_id.clear();
m_value.clear();
m_insideValue = false;
}
return S_OK;
}
HRESULT CDATABegin() override { return S_OK; }
HRESULT CDATAData(CONST WCHAR *strCDATA, UINT CDATALen, BOOL /*bMore*/) override
{
if (m_insideValue && strCDATA != nullptr && CDATALen > 0)
{
m_value.append(strCDATA, CDATALen);
}
return S_OK;
}
HRESULT CDATAEnd() override { return S_OK; }
VOID Error(HRESULT hError, CONST CHAR *strMessage) override
{
app.DebugPrintf("String XML parse error (%08X): %s\n", hError, strMessage ? strMessage : "(unknown)");
}
private:
StringTable *m_table;
bool m_insideValue;
wstring m_id;
wstring m_value;
};
bool IsXmlFileName(const wstring &path)
{
if (path.length() < 4) return false;
return toLower(path.substr(path.length() - 4)) == L".xml";
}
void ReplaceAll(string &target, const string &from, const string &to)
{
if (from.empty()) return;
size_t pos = 0;
while ((pos = target.find(from, pos)) != string::npos)
{
target.replace(pos, from.length(), to);
pos += to.length();
}
}
string DecodeXmlEntities(string text)
{
ReplaceAll(text, "&lt;", "<");
ReplaceAll(text, "&gt;", ">");
ReplaceAll(text, "&quot;", "\"");
ReplaceAll(text, "&apos;", "'");
ReplaceAll(text, "&amp;", "&");
return text;
}
string ToNativePath(const wstring &path)
{
string out(path.begin(), path.end());
#if defined(__PS3__) || defined(__ORBIS__)
std::replace(out.begin(), out.end(), '\\', '/');
#else
std::replace(out.begin(), out.end(), '/', '\\');
#endif
return out;
}
} // namespace
StringTable::StringTable(void)
{
isStatic = false;
}
StringTable::StringTable(const wstring &xmlRootPath)
{
isStatic = true;
m_xmlRootPath = xmlRootPath;
ProcessXmlStringTableData(m_xmlRootPath);
}
// Load string table from a binary blob, filling out with the current localisation data only
StringTable::StringTable(PBYTE pbData, DWORD dwSize)
{
isStatic = false;
m_xmlRootPath.clear();
src = byteArray(pbData, dwSize);
ProcessStringTableData();
}
void StringTable::ReloadStringTable()
void StringTable::ReloadStringTable() // Fireblade - dynamically reloads table based off file format used
{
m_stringsMap.clear();
m_stringsVec.clear();
ProcessStringTableData();
if (!m_xmlRootPath.empty())
{
ProcessXmlStringTableData(m_xmlRootPath);
}
else
{
ProcessStringTableData();
}
}
void StringTable::setStringValue(const wstring &id, const wstring &value)
{
if (id.empty()) return;
m_stringsMap[id] = value;
}
bool StringTable::hasStringKey(const wstring &id) const
{
if (id.empty()) return false;
return m_stringsMap.find(id) != m_stringsMap.end();
}
void StringTable::ProcessStringTableData(void)
@ -127,7 +304,151 @@ void StringTable::ProcessStringTableData(void)
bais.reset();
}
void StringTable::ProcessXmlStringTableData(const wstring &xmlRootPath)
{
ProcessXmlDirectory(xmlRootPath);
vector<wstring> locales;
app.getLocale(locales);
bool loadedLocaleDirectory = false;
for (auto &locale : locales)
{
const wstring localePath = xmlRootPath + L"\\" + locale;
File localeFolder(localePath);
if (localeFolder.exists() && localeFolder.isDirectory())
{
app.DebugPrintf("Loading XML locale '%ls'.\n", locale.c_str());
ProcessXmlDirectory(localePath);
loadedLocaleDirectory = true;
break;
}
}
if (!loadedLocaleDirectory)
{
app.DebugPrintf("No localization XML found, falling back to .loc file.\n");
}
app.DebugPrintf("StringTable:: XML loaded %u keys from '%ls'.\n", static_cast<unsigned>(m_stringsMap.size()), xmlRootPath.c_str());
isStatic = true;
}
void StringTable::ProcessXmlDirectory(const wstring &directoryPath)
{
File directory(directoryPath);
if (!directory.exists() || !directory.isDirectory()) return;
std::vector<File *> *files = directory.listFiles();
if (files == nullptr) return;
vector<wstring> xmlFiles;
for (auto *file : *files)
{
if (file != nullptr)
{
if (file->isFile() && IsXmlFileName(file->getName()))
{
xmlFiles.push_back(file->getPath());
}
delete file;
}
}
delete files;
sort(xmlFiles.begin(), xmlFiles.end());
for (auto &xmlFile : xmlFiles)
{
ProcessXmlFile(xmlFile);
}
}
void StringTable::ProcessXmlFile(const wstring &filePath)
{
ATG::XMLParser parser;
XmlStringTableCallback callback(this);
parser.RegisterSAXCallbackInterface(&callback);
const string nativePath = ToNativePath(filePath);
const size_t beforeCount = m_stringsMap.size();
if (FAILED(parser.ParseXMLFile(nativePath.c_str())))
{
app.DebugPrintf("StringTable:: Failed to parse XML localization file '%s'.\n", nativePath.c_str());
ProcessXmlFileLoose(filePath);
return;
}
if (m_stringsMap.size() == beforeCount)
{
ProcessXmlFileLoose(filePath);
}
}
void StringTable::ProcessXmlFileLoose(const wstring &filePath)
{
const string nativePath = ToNativePath(filePath);
std::ifstream input(nativePath.c_str(), std::ios::binary);
if (!input.is_open())
{
return;
}
std::ostringstream contents;
contents << input.rdbuf();
string xml = contents.str();
int parsedCount = 0;
size_t cursor = 0;
while (true)
{
const size_t dataStart = xml.find("<data", cursor);
if (dataStart == string::npos) break;
const size_t tagEnd = xml.find('>', dataStart);
if (tagEnd == string::npos) break;
size_t namePos = xml.find("name=\"", dataStart);
if (namePos == string::npos || namePos > tagEnd)
{
cursor = tagEnd + 1;
continue;
}
namePos += 6;
const size_t nameEnd = xml.find('"', namePos);
if (nameEnd == string::npos)
{
cursor = tagEnd + 1;
continue;
}
const size_t valueOpen = xml.find("<value>", tagEnd);
const size_t dataClose = xml.find("</data>", tagEnd);
if (valueOpen == string::npos || dataClose == string::npos || valueOpen > dataClose)
{
cursor = tagEnd + 1;
continue;
}
const size_t valueStart = valueOpen + 7;
const size_t valueEnd = xml.find("</value>", valueStart);
if (valueEnd == string::npos || valueEnd > dataClose)
{
cursor = dataClose + 7;
continue;
}
string id = xml.substr(namePos, nameEnd - namePos);
string value = xml.substr(valueStart, valueEnd - valueStart);
value = DecodeXmlEntities(value);
setStringValue(convStringToWstring(id), convStringToWstring(value));
parsedCount++;
cursor = dataClose + 7;
}
}
StringTable::~StringTable(void)
{
// delete src.data; TODO 4J-JEV: ?
@ -141,14 +462,6 @@ void StringTable::getData(PBYTE *ppData, UINT *pSize)
LPCWSTR StringTable::getString(const wstring &id)
{
#ifndef _CONTENT_PACKAGE
if (isStatic)
{
__debugbreak();
return L"";
}
#endif
auto it = m_stringsMap.find(id);
if(it != m_stringsMap.end())
@ -157,23 +470,16 @@ LPCWSTR StringTable::getString(const wstring &id)
}
else
{
return L"";
m_missingKeyFallback = id;
return m_missingKeyFallback.c_str();
}
}
LPCWSTR StringTable::getString(int id)
{
#ifndef _CONTENT_PACKAGE
if (!isStatic)
if (id >= 0 && static_cast<size_t>(id) < m_stringsVec.size())
{
__debugbreak();
return L"";
}
#endif
if (id < m_stringsVec.size())
{
LPCWSTR pwchString=m_stringsVec.at(id).c_str();
LPCWSTR pwchString = m_stringsVec.at(id).c_str();
return pwchString;
}
else

View file

@ -17,8 +17,10 @@ private:
unordered_map<wstring, wstring> m_stringsMap;
vector<wstring> m_stringsVec;
wstring m_missingKeyFallback;
byteArray src;
wstring m_xmlRootPath;
public:
@ -59,6 +61,7 @@ public:
// };
StringTable(void);
StringTable(const wstring &xmlRootPath);
StringTable(PBYTE pbData, DWORD dwSize);
~StringTable(void);
void ReloadStringTable();
@ -67,6 +70,8 @@ public:
LPCWSTR getString(const wstring &id);
LPCWSTR getString(int id);
void setStringValue(const wstring &id, const wstring &value);
bool hasStringKey(const wstring &id) const;
//static LPCWSTR m_wchLocaleCode[LOCALE_COUNT];
@ -75,6 +80,10 @@ public:
private:
//wstring getLangId(DWORD dwLanguage=0);
void ProcessStringTableData(void);
void ProcessXmlStringTableData(const wstring &xmlRootPath);
void ProcessXmlDirectory(const wstring &directoryPath);
void ProcessXmlFile(const wstring &filePath);
void ProcessXmlFileLoose(const wstring &filePath);
};

View file

@ -2470,7 +2470,7 @@ Can also be used for low-level lighting.</value>
</data>
<data name="IDS_ITEM_WHEAT_SEEDS">
<value>Wheat Seeds</value>
<value>Seeds</value>
</data>
<data name="IDS_ITEM_WHEAT">
@ -3162,11 +3162,11 @@ Can also be used for low-level lighting.</value>
</data>
<data name="IDS_TILE_FLOWER">
<value>Flower</value>
<value>Dandelion</value>
</data>
<data name="IDS_TILE_ROSE">
<value>Rose</value>
<value>Poppy</value>
</data>
<data name="IDS_TILE_MUSHROOM">
@ -6538,6 +6538,10 @@ Would you like to install the mash-up pack or texture pack now?</value>
<value>Game Mode: Adventure</value>
</data>
<data name="IDS_GAMEMODE_HARDCORE">
<value>Game Mode: Hardcore</value>
</data>
<data name="IDS_SURVIVAL">
<value>Survival</value>
</data>
@ -6550,6 +6554,10 @@ Would you like to install the mash-up pack or texture pack now?</value>
<value>Adventure</value>
</data>
<data name="IDS_HARDCORE">
<value>Hardcore</value>
</data>
<data name="IDS_CREATED_IN_SURVIVAL">
<value>Created in Survival Mode</value>
</data>
@ -6866,6 +6874,10 @@ Would you like to install the mash-up pack or texture pack now?</value>
<value>Death Messages</value>
</data>
<data name="IDS_HARDCORE_DEATH_MESSAGE">
<value>dead.</value>
</data>
<data name="IDS_CHECKBOX_ANIMATED_CHARACTER">
<value>Animated Character</value>
</data>
@ -8842,7 +8854,7 @@ All Ender Chests in a world are linked. Items placed into an Ender Chest are acc
<data name="IDS_TILE_STONESLAB_DARK_OAK">
<value>Dark Oak Wood Slab</value>
</data>
</data>
<data name="IDS_TILE_STONESLAB_DARK_OAK">
<value>Dark Oak Wood Slab</value>
@ -8934,122 +8946,145 @@ All Ender Chests in a world are linked. Items placed into an Ender Chest are acc
<data name="IDS_ITEM_ARMOR_STAND">
<value>Armor Stand</value>
</data>
<data name="IDS_DESC_ARMOR_STAND">
<value>Can be equipped to display armor and other decorative items such as mob heads.</value>
</data>
<data name="IDS_RABBIT">
<value>Rabbit</value>
</data>
<data name="IDS_DESC_RABBIT">
<value>A harmless creature. May drop a rabbit hide or a rabbit's foot when killed.</value>
</data>
<data name="IDS_ITEM_RABBIT_HIDE">
<value>Rabbit Hide</value>
</data>
<data name="IDS_DESC_RABBIT_HIDE">
<value>Used in crafting leather.</value>
</data>
<data name="IDS_ITEM_RABBIT_FOOT">
<value>Rabbit's Foot</value>
</data>
<data name="IDS_DESC_RABBIT_FOOT">
<value>Used as an ingredient for brewing potions.</value>
</data>
<data name="IDS_ITEM_RABBIT_RAW">
<value>Raw Rabbit</value>
</data>
<data name="IDS_DESC_RABBIT_RAW">
<value>Restores 0.5{*ICON_SHANK_01*}, or can be cooked in a furnace.</value>
</data>
<data name="IDS_ITEM_RABBIT_COOKED">
<value>Cooked Rabbit</value>
</data>
<data name="IDS_DESC_RABBIT_COOKED">
<value>Restores 2.5{*ICON_SHANK_01*}. Used to cook up some rabbit stew.</value>
</data>
<data name="IDS_ITEM_MUTTON_RAW">
<value>Raw Mutton</value>
</data>
<data name="IDS_DESC_MUTTON_RAW">
<value>Restores 1{*ICON_SHANK_01*}, or can be cooked in a furnace.</value>
</data>
<data name="IDS_ITEM_MUTTON_COOKED">
<value>Cooked Mutton</value>
</data>
<data name="IDS_DESC_MUTTON_COOKED">
<value>Restores 3{*ICON_SHANK_01*}. Created by cooking raw mutton in a furnace.</value>
</data>
<data name="IDS_TILE_SAPLING_ACACIA">
<value>Acacia Sapling</value>
</data>
</data>
<data name="IDS_TILE_SAPLING_DARK_OAK">
<value>Dark Oak Sapling</value>
</data>
</data>
<data name="IDS_TILE_LEAVES_ACACIA">
<value>Acacia Leaves</value>
</data>
</data>
<data name="IDS_TILE_LEAVES_DARK_OAK">
<value>Dark Oak Leaves</value>
</data>
</data>
<data name="IDS_TILE_RED_SANDSTONE">
<value>Red Sandstone</value>
</data>
</data>
<data name="IDS_TILE_STAIRS_RED_SANDSTONE">
<value>Red Sandstone Stairs</value>
</data>
</data>
<data name="IDS_ITEM_PRISMARINE_CRYSTAL">
<value>Prismarine Crystal</value>
</data>
</data>
<data name="IDS_TILE_SEA_LANTERN">
<value>Sea Lantern</value>
</data>
</data>
<data name="IDS_WINDOWS_EXIT">
<value>Exit Minecraft</value>
</data>
<data name="IDS_TILE_PACKED_ICE">
<value>Packed Ice</value>
</data>
<data name="IDS_DESC_PACKED_ICE">
<value>A solid unmeltable block of ice that can have objects placed on it.</value>
</data>
<data name="IDS_TILE_RED_SANDSTONE_CHISELED">
<value>Chiseled Red Sandstone</value>
</data>
<data name="IDS_TILE_RED_SANDSTONE_SMOOTH">
<value>Smooth Red Sandstone</value>
</data>
<data name="IDS_DESC_RED_SANDSTONE">
<value>Red colored Sandstone. It is not influenced by gravity like normal Sand.</value>
</data>
<data name="IDS_DESC_SEA_LANTERN">
<value>Underwater light sources that can be found in Ocean Monuments. Can be crafted from Prismarine shards and Prismarine crystals.</value>
</data>
<data name="IDS_TILE_PRISMARINE">
<value>Prismarine</value>
</data>
<data name="IDS_DESC_PRISMARINE">
<data name="IDS_TILE_PRISMARINE_DARK">
<value>Dark Prismarine</value>
</data>
<data name="IDS_TILE_PRISMARINE_BRICKS">
<value>Prismarine Bricks</value>
</data>
<data name="IDS_ITEM_PRISMARINE_SHARD">
<value>Prismarine Shard</value>
</data>
<data name="IDS_ITEM_PRISMARINE_DESC">
<value>Rare decorative stone that can be found in Ocean Monuments. Can be crafted from Prismarine shards.</value>
</data>
<data name="IDS_DESC_DOUBLE_TALL_GRASS">
<value>PLACEHOLDER</value>
<data name="IDS_ITEM_PRISMARINE_DARK_DESC">
<value>A rarer form of Prismarine that can be found in Ocean Monuments. Can be crafted with Prismarine shards and an Ink Sac.</value>
</data>
<data name="IDS_ITEM_PRISMARINE_BRICK_DESC">
<value>Decorative Prismarine brick that can be found in Ocean Monuments. Can be crafted from Prismarine shards.</value>
</data>
<data name="IDS_ITEM_PRISMARINE_CRYSTAL_DESC">
<value>Obtained from Sea Lanterns or by defeating Guardians and Elder Guardians. Can be used in crafting Sea Lanterns.</value>
</data>
<data name="IDS_ITEM_PRISMARINE_SHARD_DESC">
<value>Dropped by Guardians and Elder Guardians. Can be used in crafting Prismarine and Sea Lanterns.</value>
</data>
<data name="IDS_ITEM_RABBIT_STEW">
<value>{*ICON_SHANK_01*}</value>
</data>
<data name="IDS_TILE_DOUBLE_TALL_GRASS">
<value>Double Tall Grass</value>
</data>
<data name="IDS_TILE_SUNFLOWER">
<value>Sunflower</value>
<value>Tall Grass</value>
</data>
<data name="IDS_TILE_LARGE_FERN">
@ -9068,40 +9103,283 @@ All Ender Chests in a world are linked. Items placed into an Ender Chest are acc
<value>Peony</value>
</data>
<data name="IDS_ITEM_PRISMARINE_SHARD">
<value>Prismarine Shard</value>
<data name="IDS_TILE_PACKED_ICE">
<value>Packed Ice</value>
</data>
<data name="IDS_ITEM_PRISMARINE_SHARD_DESC">
<value>Dropped by Guardians and Elder Guardians. Can be used in crafting Prismarine and Sea Lanterns.</value>
</data>
<data name="IDS_TILE_SUNFLOWER">
<value>Sunflower</value>
</data>
<data name="IDS_ITEM_PRISMARINE_CRYSTAL_DESC">
<value>Obtained from Sea Lanterns or by defeating Guardians and Elder Guardians. Can be used in crafting Sea Lanterns.</value>
</data>
<data name="IDS_DESC_PACKED_ICE">
<value>A solid unmeltable block of ice that can have objects placed on it.</value>
</data>
<data name="IDS_ITEM_PRISMARINE_DESC">
<data name="IDS_DESC_RED_SANDSTONE">
<value>Red colored Sandstone. It is not influenced by gravity like normal Sand.</value>
</data>
<data name="IDS_DESC_SEA_LANTERN">
<value>Underwater light sources that can be found in Ocean Monuments. Can be crafted from Prismarine shards and Prismarine crystals.</value>
</data>
<data name="IDS_DESC_PRISMARINE">
<value>Rare decorative stone that can be found in Ocean Monuments. Can be crafted from Prismarine shards.</value>
</data>
<data name="IDS_ITEM_PRISMARINE_BRICK_DESC">
<value>Decorative Prismarine brick that can be found in Ocean Monuments. Can be crafted from Prismarine shards.</value>
</data>
<data name="IDS_ITEM_PRISMARINE_DARK_DESC">
<value>A rarer form of Prismarine that can be found in Ocean Monuments. Can be crafted with Prismarine shards and an Ink Sac.</value>
</data>
<data name="IDS_TILE_PRISMARINE">
<value>Prismarine</value>
<data name="IDS_DESC_DOUBLE_TALL_GRASS">
<value>Double tall grass that can sometimes drop seeds.</value>
</data>
<data name="IDS_TILE_PRISMARINE_BRICKS">
<value>Prismarine Bricks</value>
<data name="IDS_TILE_RED_SANDSTONE_CHISELED">
<value>Chiseled Red Sandstone</value>
</data>
<data name="IDS_TILE_PRISMARINE_DARK">
<value>Dark Prismarine</value>
<data name="IDS_TILE_RED_SANDSTONE_SMOOTH">
<value>Smooth Red Sandstone</value>
</data>
</root>
<data name="IDS_TILE_PODZOL">
<value>Podzol</value>
</data>
<data name="IDS_TILE_COARSE_DIRT">
<value>Coarse Dirt</value>
</data>
<data name="IDS_DESC_PODZOL">
<value>Similar to Dirt Blocks, but very good for growing mushrooms on.</value>
</data>
<data name="IDS_DESC_COARSE_DIRT">
<value>A special type of dirt that does not grow grass.</value>
</data>
<data name="IDS_TILE_GRANITE">
<value>Granite</value>
</data>
<data name="IDS_TILE_POLISHED_GRANITE">
<value>Polished Granite</value>
</data>
<data name="IDS_TILE_ANDESITE">
<value>Andesite</value>
</data>
<data name="IDS_TILE_POLISHED_ANDESITE">
<value>Polished Andesite</value>
</data>
<data name="IDS_TILE_DIORITE">
<value>Diorite</value>
</data>
<data name="IDS_TILE_POLISHED_DIORITE">
<value>Polished Diorite</value>
</data>
<data name="IDS_DESC_GRANITE">
<value>Can be mined with a pickaxe to collect granite.</value>
</data>
<data name="IDS_DESC_POLISHED_GRANITE">
<value>Can be crafted from granite for a polished look.</value>
</data>
<data name="IDS_DESC_ANDESITE">
<value>Can be mined with a pickaxe to collect andesite.</value>
</data>
<data name="IDS_DESC_POLISHED_ANDESITE">
<value>Can be crafted from andesite for a polished look.</value>
</data>
<data name="IDS_DESC_DIORITE">
<value>Can be mined with a pickaxe to collect diorite.</value>
</data>
<data name="IDS_DESC_POLISHED_DIORITE">
<value>Can be crafted from diorite for a polished look.</value>
</data>
<data name="IDS_TILE_RED_SAND">
<value>Red Sand</value>
</data>
<data name="IDS_TILE_WET_SPONGE">
<value>Wet Sponge</value>
</data>
<data name="IDS_DESC_WET_SPONGE">
<value>Can be dried in a furnace, allowing the sponge to be reused.</value>
</data>
<data name="IDS_ITEM_SALMON_RAW">
<value>Raw Salmon</value>
</data>
<data name="IDS_ITEM_SALMON_COOKED">
<value>Cooked Salmon</value>
</data>
<data name="IDS_ITEM_CLOWNFISH">
<value>Clownfish</value>
</data>
<data name="IDS_ITEM_PUFFERFISH">
<value>Pufferfish</value>
</data>
<data name="IDS_DESC_SALMON_RAW">
<value>Restores 1{*ICON_SHANK_01*}, or can be cooked in a furnace. Can be fed to an ocelot to tame it.</value>
</data>
<data name="IDS_DESC_SALMON_COOKED">
<value>Restores 3{*ICON_SHANK_01*}. Created by cooking a raw salmon in a furnace.</value>
</data>
<data name="IDS_DESC_CLOWNFISH">
<value>Restores 0.5{*ICON_SHANK_01*}.</value>
</data>
<data name="IDS_DESC_PUFFERFISH">
<value>Restores 0.5{*ICON_SHANK_01*} however it is poisonous. Can also be used as an ingredient in brewing potions.</value>
</data>
<data name="IDS_TILE_BLUE_ORCHID">
<value>Blue Orchid</value>
</data>
<data name="IDS_TILE_ALLIUM">
<value>Allium</value>
</data>
<data name="IDS_TILE_HOUSTONIA">
<value>Azure Bluet</value>
</data>
<data name="IDS_TILE_TULIP_RED">
<value>Red Tulip</value>
</data>
<data name="IDS_TILE_TULIP_ORANGE">
<value>Orange Tulip</value>
</data>
<data name="IDS_TILE_TULIP_WHITE">
<value>White Tulip</value>
</data>
<data name="IDS_TILE_TULIP_PINK">
<value>Pink Tulip</value>
</data>
<data name="IDS_TILE_OXEYE_DAISY">
<value>Oxeye Daisy</value>
</data>
<data name="IDS_DESC_ROSE">
<value>A common red flower that can be used to craft red dye.</value>
</data>
<data name="IDS_DESC_BLUE_ORCHID">
<value>A rare blue flower that can be used to craft light blue dye.</value>
</data>
<data name="IDS_DESC_ALLIUM">
<value>A rare magenta flower that can be used to craft magenta dye.</value>
</data>
<data name="IDS_DESC_HOUSTONIA">
<value>A small white flower that can be used to craft light gray dye.</value>
</data>
<data name="IDS_DESC_TULIP_RED">
<value>A small red flower that can be used to craft red dye.</value>
</data>
<data name="IDS_DESC_TULIP_ORANGE">
<value>A small orange flower that can be used to craft orange dye.</value>
</data>
<data name="IDS_DESC_TULIP_WHITE">
<value>A small white flower that can be used to craft light gray dye.</value>
</data>
<data name="IDS_DESC_TULIP_PINK">
<value>A small pink flower that can be used to craft pink dye.</value>
</data>
<data name="IDS_DESC_OXEYE_DAISY">
<value>A common white and yellow flower that can be used to craft light gray dye.</value>
</data>
<data name="IDS_DESC_SUNFLOWER">
<value>A tall yellow flower that can be used to craft yellow dye.</value>
</data>
<data name="IDS_DESC_LILAC">
<value>A tall purple flower that can be used to craft magenta dye.</value>
</data>
<data name="IDS_DESC_LARGE_FERN">
<value>A tall fern that can sometimes drop seeds.</value>
</data>
<data name="IDS_DESC_ROSE_BUSH">
<value>A tall red flower that can be used to craft red dye.</value>
</data>
<data name="IDS_DESC_PEONY">
<value>A tall green and pink flower that can be used to craft pink dye.</value>
</data>
<data name="IDS_ENDERMITE">
<value>Endermite</value>
</data>
<data name="IDS_ITEM_WRITTENBOOK">
<value>Written Book</value>
</data>
<data name="IDS_DESC_WRITTENBOOK">
<value>A book signed by the author (cannot be written in).</value>
</data>
<data name="IDS_ITEM_WRITINGBOOK">
<value>Book and Quill</value>
</data>
<data name="IDS_DESC_WRITINGBOOK">
<value>A Book that can be written in.</value>
</data>
<data name="IDS_TOOLTIPS_NEXTPAGE">
<value>Next Page</value>
</data>
<data name="IDS_TOOLTIPS_BACKPAGE">
<value>Previous Page</value>
</data>
<data name="IDS_TOOLTIPS_ADDPAGE">
<value>Add Page</value>
</data>
<data name="IDS_TITLE_EXITBOOK">
<value>Exit Book</value>
</data>
<data name="IDS_DESC_EXITBOOK">
<value>Are you sure you want to exit this book and the changes you've made?</value>
</data>
<data name="IDS_ENCHANTMENT_LURE">
<value>Lure</value>
</data>
<data name="IDS_ENCHANTMENT_LUCK_OF_THE_SEA">
<value>Luck of the Sea</value>
</data>
</root>

View file

@ -172,7 +172,7 @@ Would you like to unlock the full game?</value>
</data>
<data name="IDS_FATAL_ERROR_TEXT">
<value>"Minecraft: Xbox One Edition" has failed to load, and cannot continue.</value>
<value>"Minecraft: Legacy Console Edition" has failed to load, and cannot continue.</value>
</data>
<data name="IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT">
@ -201,7 +201,7 @@ Would you like to unlock the full game?</value>
<data name="IDS_SAVE_ICON_MESSAGE">
<value>This game has a level autosave feature. When you see the icon above displayed, the game is saving your data.
Please do not turn off your Xbox One console while this icon is on-screen.</value>
Please do not turn off your computer while this icon is on-screen.</value>
</data>
<data name="IDS_GAMEOPTION_HOST_PRIVILEGES">
@ -225,13 +225,13 @@ Please do not turn off your Xbox One console while this icon is on-screen.</valu
</data>
<data name="IDS_SOCIAL_DEFAULT_DESCRIPTION">
<value>Look what I made in Minecraft: Xbox One Edition!</value>
<value>Look what I made in Minecraft: Legacy Console Edition!</value>
</data>
<data name="IDS_TITLE_UPDATE_NAME">
<value>Title Update 14</value>
</data>
<data name="IDS_PLATFORM_NAME">
<value>Xbox One</value>
<value>Computer</value>
</data>
<data name="IDS_BACK_BUTTON">
<value>Back</value>
@ -240,7 +240,7 @@ Please do not turn off your Xbox One console while this icon is on-screen.</valu
<value>This option disables achievements and leaderboard updates for this world while playing, and if loading it again after saving with this option on.</value>
</data>
<data name="IDS_KICK_PLAYER_DESCRIPTION">
<value>For players that are not on the same Xbox One console as the host player, selecting this option will kick the player from the game and any other players on their Xbox One console. This player will not be able to rejoin the game until it is restarted.</value>
<value>For players that are not on the same device as the host player, selecting this option will kick the player from the game and any other players sharing the device. This player will not be able to rejoin the game until it is restarted.</value>
</data>
<data name="IDS_USING_TRIAL_TEXUREPACK_WARNING">
<value>You are using the trial version of a texture pack. You will have access to the full contents of the texture pack, but you will not be able to save your progress.
@ -248,7 +248,6 @@ If you try to save while using the trial version, you will be given the option t
</value>
</data>
<data name="IDS_WORLD_SIZE_TITLE_SMALL">
<value>Small</value>
</data>
@ -287,4 +286,4 @@ If you try to save while using the trial version, you will be given the option t
<data name="IDS_ERROR_NETWORK_TITLE">
<value>Network Error</value>
</data>
</root>
</root>

File diff suppressed because it is too large Load diff

View file

@ -423,6 +423,7 @@ set(_MINECRAFT_CLIENT_WINDOWS_WINDOWS64_SOCIAL
source_group("Windows64/Social" FILES ${_MINECRAFT_CLIENT_WINDOWS_WINDOWS64_SOCIAL})
set(_MINECRAFT_CLIENT_WINDOWS_WINDOWS64_XML
"${CMAKE_CURRENT_SOURCE_DIR}/Xbox/XML/ATGXmlParser.cpp"
"${BASE_DIR}/XML/ATGXmlParser.h"
)
source_group("Windows64/XML" FILES ${_MINECRAFT_CLIENT_WINDOWS_WINDOWS64_XML})

View file

@ -10,6 +10,8 @@ set(_MINECRAFT_SERVER_COMMON_ROOT
"${_MS_SRC}/../Minecraft.Client/AllowAllCuller.cpp"
"${_MS_SRC}/../Minecraft.Client/ArchiveFile.cpp"
"${_MS_SRC}/../Minecraft.Client/ArrowRenderer.cpp"
"${_MS_SRC}/../Minecraft.Client/ArmorStandModel.cpp"
"${_MS_SRC}/../Minecraft.Client/ArmorStandRenderer.cpp"
"${_MS_SRC}/../Minecraft.Client/BatModel.cpp"
"${_MS_SRC}/../Minecraft.Client/BatRenderer.cpp"
"${_MS_SRC}/../Minecraft.Client/BeaconRenderer.cpp"
@ -134,6 +136,7 @@ set(_MINECRAFT_SERVER_COMMON_ROOT
"${_MS_SRC}/../Minecraft.Client/Common/UI/IUIScene_PauseMenu.cpp"
"${_MS_SRC}/../Minecraft.Client/Common/UI/IUIScene_StartGame.cpp"
"${_MS_SRC}/../Minecraft.Client/Common/UI/IUIScene_TradingMenu.cpp"
"${_MS_SRC}/../Minecraft.Client/Common/UI/IUIScene_WritingBookMenu.cpp"
"${_MS_SRC}/../Minecraft.Client/Common/UI/UIBitmapFont.cpp"
"${_MS_SRC}/../Minecraft.Client/Common/UI/UIUnicodeBitmapFont.cpp"
"${_MS_SRC}/../Minecraft.Client/Common/UI/UIComponent_Chat.cpp"
@ -149,6 +152,7 @@ set(_MINECRAFT_SERVER_COMMON_ROOT
"${_MS_SRC}/../Minecraft.Client/Common/UI/UIControl_Base.cpp"
"${_MS_SRC}/../Minecraft.Client/Common/UI/UIControl_BeaconEffectButton.cpp"
"${_MS_SRC}/../Minecraft.Client/Common/UI/UIControl_BitmapIcon.cpp"
"${_MS_SRC}/../Minecraft.Client/Common/UI/UIControl_Book.cpp"
"${_MS_SRC}/../Minecraft.Client/Common/UI/UIControl_Button.cpp"
"${_MS_SRC}/../Minecraft.Client/Common/UI/UIControl_ButtonList.cpp"
"${_MS_SRC}/../Minecraft.Client/Common/UI/UIControl_CheckBox.cpp"
@ -395,7 +399,7 @@ set(_MINECRAFT_SERVER_COMMON_ROOT
"${_MS_SRC}/../Minecraft.Client/PreStitchedTextureMap.cpp"
"${_MS_SRC}/../Minecraft.Client/ProgressRenderer.cpp"
"${_MS_SRC}/../Minecraft.Client/QuadrupedModel.cpp"
"${_MS_SRC}/../Minecraft.Client/RabbitModel.cpp"
"${_MS_SRC}/../Minecraft.Client/RabbitModel.cpp"
"${_MS_SRC}/../Minecraft.Client/RabbitRenderer.cpp"
"${_MS_SRC}/../Minecraft.Client/Rect2i.cpp"
"${_MS_SRC}/../Minecraft.Client/RedDustParticle.cpp"
@ -448,6 +452,7 @@ set(_MINECRAFT_SERVER_COMMON_ROOT
"${_MS_SRC}/../Minecraft.Client/StitchedTexture.cpp"
"${_MS_SRC}/../Minecraft.Client/Stitcher.cpp"
"${_MS_SRC}/../Minecraft.Client/StringTable.cpp"
"${_MS_SRC}/../Minecraft.Client/Xbox/XML/ATGXmlParser.cpp"
"${_MS_SRC}/../Minecraft.Client/SuspendedParticle.cpp"
"${_MS_SRC}/../Minecraft.Client/SuspendedTownParticle.cpp"
"${_MS_SRC}/../Minecraft.Client/TakeAnimationParticle.cpp"

View file

@ -225,4 +225,30 @@ unsigned int Sapling::getDescriptionId(int iData)
{
if (iData < 0 || iData >= SAPLING_NAMES_SIZE) iData = 0;
return Sapling::SAPLING_NAMES[iData];
}
}
int Sapling::getSpawnResourcesAuxValue(int data)
{
return data & TYPE_MASK;
}
bool Sapling::isSapling(Level *level, int x, int y, int z, int type)
{
return (level->getTile(x, y, z) == id) && ((level->getData(x, y, z) & TYPE_MASK) == type);
}
bool Sapling::fertilize(Level *level, int x, int y, int z)
{
this->advanceTree(level, x, y, z, level->random);
return true;
}
void Sapling::registerIcons(IconRegister *iconRegister)
{
icons = new Icon*[SAPLING_NAMES_SIZE];
for (int i = 0; i < SAPLING_NAMES_SIZE; i++)
{
icons[i] = iconRegister->registerIcon(TEXTURE_NAMES[i]);
}
}

View file

@ -216,7 +216,7 @@ void MemSect(int sect);
#elif defined _WINDOWS64
#include "../Minecraft.Client/Windows64/Windows64_App.h"
#include "../Minecraft.Client/Windows64Media/strings.h"
#include "Windows64Media/strings.h"
#include "../Minecraft.Client/Windows64/Sentient/SentientTelemetryCommon.h"
#include "../Minecraft.Client/Windows64/Sentient/MinecraftTelemetry.h"

View file

@ -0,0 +1,58 @@
if(NOT DEFINED OUTPUT_FILE OR OUTPUT_FILE STREQUAL "")
message(FATAL_ERROR "OUTPUT_FILE is required")
endif()
if(NOT DEFINED HEADER_LIST)
set(HEADER_LIST "")
endif()
# add_custom_command passes list args as an escaped string (\;). Normalize it.
string(REPLACE "\\;" ";" HEADER_LIST "${HEADER_LIST}")
set(_entries "")
set(_seen_names "")
set(_processed_headers "")
foreach(_header IN LISTS HEADER_LIST)
if(NOT EXISTS "${_header}")
continue()
endif()
list(APPEND _processed_headers "${_header}")
file(STRINGS "${_header}" _header_lines REGEX "^#[ \t]*define[ \t]+IDS_[A-Za-z0-9_]+[ \t]+[0-9]+([ \t].*)?$")
foreach(_line IN LISTS _header_lines)
string(REGEX REPLACE "^#[ \t]*define[ \t]+(IDS_[A-Za-z0-9_]+)[ \t]+([0-9]+).*$" "\\1;\\2" _parts "${_line}")
list(LENGTH _parts _part_count)
if(_part_count LESS 2)
continue()
endif()
list(GET _parts 0 _name)
list(FIND _seen_names "${_name}" _seen_index)
if(NOT _seen_index EQUAL -1)
continue()
endif()
list(APPEND _seen_names "${_name}")
string(APPEND _entries "#ifdef ${_name}\n")
string(APPEND _entries "case ${_name}: return L\"${_name}\";\n")
string(APPEND _entries "#endif\n")
endforeach()
endforeach()
list(LENGTH _seen_names _entry_count)
if(_entry_count EQUAL 0)
message(FATAL_ERROR "GenerateStringIdLookup.cmake found no IDS_ defines. HEADER_LIST='${HEADER_LIST}'")
endif()
get_filename_component(_output_dir "${OUTPUT_FILE}" DIRECTORY)
if(NOT _output_dir STREQUAL "")
file(MAKE_DIRECTORY "${_output_dir}")
endif()
file(WRITE "${OUTPUT_FILE}" "// Auto-generated by cmake/GenerateStringIdLookup.cmake.\n")
file(APPEND "${OUTPUT_FILE}" "// Do not edit manually.\n\n")
file(APPEND "${OUTPUT_FILE}" "${_entries}")

View file

@ -0,0 +1,103 @@
if(NOT DEFINED OUTPUT_FILE OR OUTPUT_FILE STREQUAL "")
message(FATAL_ERROR "OUTPUT_FILE is required")
endif()
if(NOT DEFINED XML_ROOT OR XML_ROOT STREQUAL "")
message(FATAL_ERROR "XML_ROOT is required")
endif()
if(NOT DEFINED BASE_HEADER)
set(BASE_HEADER "")
endif()
if(NOT EXISTS "${XML_ROOT}")
message(FATAL_ERROR "XML_ROOT does not exist: ${XML_ROOT}")
endif()
set(_defined_names "")
set(_entries "")
set(_max_id -1)
if(BASE_HEADER AND EXISTS "${BASE_HEADER}")
file(STRINGS "${BASE_HEADER}" _base_lines REGEX "^#[ \t]*define[ \t]+IDS_[A-Za-z0-9_]+[ \t]+[0-9]+([ \t].*)?$")
foreach(_line IN LISTS _base_lines)
string(REGEX REPLACE "^#[ \t]*define[ \t]+(IDS_[A-Za-z0-9_]+)[ \t]+([0-9]+).*$" "\\1;\\2" _parts "${_line}")
list(LENGTH _parts _part_count)
if(_part_count LESS 2)
continue()
endif()
list(GET _parts 0 _name)
list(GET _parts 1 _value)
list(FIND _defined_names "${_name}" _name_index)
if(NOT _name_index EQUAL -1)
continue()
endif()
list(APPEND _defined_names "${_name}")
set(_padded_value "000000000${_value}")
string(REGEX REPLACE "^.*([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9])$" "\\1" _padded_value "${_padded_value}")
list(APPEND _entries "${_padded_value}|${_value}|${_name}")
if(_value GREATER _max_id)
set(_max_id "${_value}")
endif()
endforeach()
endif()
file(GLOB_RECURSE _xml_files "${XML_ROOT}/*.xml")
set(_discovered_names "")
foreach(_xml_file IN LISTS _xml_files)
file(STRINGS "${_xml_file}" _xml_lines REGEX "name=\"IDS_[A-Za-z0-9_]+\"")
foreach(_xml_line IN LISTS _xml_lines)
string(REGEX MATCH "name=\"(IDS_[A-Za-z0-9_]+)\"" _match "${_xml_line}")
if(_match STREQUAL "")
continue()
endif()
set(_name "${CMAKE_MATCH_1}")
list(FIND _defined_names "${_name}" _name_index)
if(NOT _name_index EQUAL -1)
continue()
endif()
list(FIND _discovered_names "${_name}" _discovered_index)
if(NOT _discovered_index EQUAL -1)
continue()
endif()
list(APPEND _discovered_names "${_name}")
endforeach()
endforeach()
list(SORT _discovered_names)
set(_next_id "${_max_id}")
foreach(_name IN LISTS _discovered_names)
math(EXPR _next_id "${_next_id} + 1")
set(_padded_value "000000000${_next_id}")
string(REGEX REPLACE "^.*([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9])$" "\\1" _padded_value "${_padded_value}")
list(APPEND _entries "${_padded_value}|${_next_id}|${_name}")
list(APPEND _defined_names "${_name}")
endforeach()
list(SORT _entries)
list(LENGTH _entries _entry_count)
get_filename_component(_output_dir "${OUTPUT_FILE}" DIRECTORY)
if(NOT _output_dir STREQUAL "")
file(MAKE_DIRECTORY "${_output_dir}")
endif()
file(WRITE "${OUTPUT_FILE}" "#pragma once\n")
file(APPEND "${OUTPUT_FILE}" "// Auto-generated from localization XML. Do not edit manually.\n")
file(APPEND "${OUTPUT_FILE}" "// Source root: ${XML_ROOT}\n")
file(APPEND "${OUTPUT_FILE}" "// Total strings: ${_entry_count}\n\n")
foreach(_entry IN LISTS _entries)
string(REGEX REPLACE "^[0-9]+\\|([0-9]+)\\|(IDS_[A-Za-z0-9_]+)$" "\\1;\\2" _entry_parts "${_entry}")
list(GET _entry_parts 0 _value)
list(GET _entry_parts 1 _name)
file(APPEND "${OUTPUT_FILE}" "#define ${_name} ${_value}\n")
endforeach()