mirror of
https://github.com/GabsPuNs/Project-Zenith-Main.git
synced 2026-07-09 23:18:30 +00:00
Replace hardcoded English strings in RML UI files with {IDS_XXX}
placeholders that are translated at runtime via RmlUi's TranslateString
override, which looks up keys in the LCE StringTable.
- Override SystemInterface_Win64::TranslateString to scan for {KEY}
patterns and resolve them via StringTable::getString(wstring)
- Add GetLCEStringTable() accessor to CConsoleMinecraftApp
- Update PauseMenu.rml, SettingsMenu.rml, HelpOptions.rml with IDS_XXX keys
- Update dynamic dialog SetInnerRML calls in UIScene_PauseMenu.cpp
- Fix CMakePresets.json: remove hardcoded VS2022 ml64.exe path
487 lines
13 KiB
C++
487 lines
13 KiB
C++
// Non-RmlUi includes that depend on Windows macros
|
|
#include "UI.h"
|
|
#include "../../MinecraftServer.h"
|
|
#include "../../MultiPlayerLocalPlayer.h"
|
|
|
|
// RmlUi includes (Windows macros temporarily suppressed)
|
|
#pragma push_macro("byte")
|
|
#pragma push_macro("GetNextSibling")
|
|
#pragma push_macro("GetFirstChild")
|
|
#undef byte
|
|
#undef GetNextSibling
|
|
#undef GetFirstChild
|
|
|
|
#include "UIScene_PauseMenu.h"
|
|
#include "RmlManager.h"
|
|
#include "../../Windows64/KeyboardMouseInput.h"
|
|
#include <RmlUi/Core/Input.h>
|
|
#include <RmlUi/Core/Context.h>
|
|
|
|
#pragma pop_macro("GetFirstChild")
|
|
#pragma pop_macro("GetNextSibling")
|
|
#pragma pop_macro("byte")
|
|
|
|
UIScene_PauseMenu::UIScene_PauseMenu(int iPad, void *initData, UILayer *parentLayer)
|
|
: UIScene(iPad, parentLayer)
|
|
, m_document(nullptr)
|
|
, m_bIgnoreInput(false)
|
|
, m_bExitDialog(false)
|
|
, m_bSaveDialog(false)
|
|
{
|
|
Rml::Context* ctx = RmlManager::Get().GetContext();
|
|
if (!ctx)
|
|
{
|
|
app.DebugPrintf("[RmlPauseMenu] No RmlUi context available\n");
|
|
return;
|
|
}
|
|
|
|
m_document = ctx->LoadDocument("PauseMenu.rml");
|
|
if (m_document)
|
|
{
|
|
app.DebugPrintf("[RmlPauseMenu] Document loaded OK, showing...\n");
|
|
m_document->Show();
|
|
app.DebugPrintf("[RmlPauseMenu] Document shown, visible=%d, context docs=%d\n",
|
|
m_document->IsVisible(), ctx->GetNumDocuments());
|
|
m_document->GetElementById("resume")->AddEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("help_options")->AddEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("achievements")->AddEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("save_game")->AddEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("exit_game")->AddEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("exit_save")->AddEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("exit_nosave")->AddEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("exit_cancel")->AddEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("save_cancel")->AddEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("save_confirm")->AddEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("resume")->Focus();
|
|
}
|
|
else
|
|
{
|
|
app.DebugPrintf("[RmlPauseMenu] Failed to load PauseMenu.rml\n");
|
|
}
|
|
|
|
ui.HidePressStart();
|
|
|
|
// parentLayer->addComponent(iPad,eUIComponent_Logo);
|
|
|
|
if (g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1)
|
|
{
|
|
app.SetXuiServerAction(ProfileManager.GetPrimaryPad(), eXuiServerAction_PauseServer, (void*)TRUE);
|
|
}
|
|
|
|
TelemetryManager->RecordMenuShown(m_iPad, eUIScene_PauseMenu, 0);
|
|
TelemetryManager->RecordPauseOrInactive(m_iPad);
|
|
}
|
|
|
|
UIScene_PauseMenu::~UIScene_PauseMenu()
|
|
{
|
|
if (m_document)
|
|
{
|
|
m_document->GetElementById("resume")->RemoveEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("help_options")->RemoveEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("achievements")->RemoveEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("save_game")->RemoveEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("exit_game")->RemoveEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("exit_save")->RemoveEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("exit_nosave")->RemoveEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("exit_cancel")->RemoveEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("save_cancel")->RemoveEventListener(Rml::EventId::Click, this);
|
|
m_document->GetElementById("save_confirm")->RemoveEventListener(Rml::EventId::Click, this);
|
|
m_document->Close();
|
|
m_document = nullptr;
|
|
}
|
|
|
|
m_parentLayer->showComponent(m_iPad, eUIComponent_Panorama, false);
|
|
m_parentLayer->showComponent(m_iPad, eUIComponent_MenuBackground, false);
|
|
m_parentLayer->showComponent(m_iPad, eUIComponent_Logo, false);
|
|
}
|
|
|
|
void UIScene_PauseMenu::gainFocus()
|
|
{
|
|
if (!bHasFocus && stealsFocus())
|
|
{
|
|
bHasFocus = true;
|
|
updateTooltips();
|
|
updateComponents();
|
|
if (!m_bFocussedOnce)
|
|
{
|
|
// No Iggy set-focus call needed for RmlUi scene
|
|
}
|
|
handleGainFocus(m_bFocussedOnce);
|
|
if (bHasFocus)
|
|
m_bFocussedOnce = true;
|
|
if (m_document)
|
|
m_document->Show();
|
|
}
|
|
}
|
|
|
|
void UIScene_PauseMenu::handleLoseFocus()
|
|
{
|
|
if (m_document)
|
|
m_document->Hide();
|
|
}
|
|
|
|
void UIScene_PauseMenu::reloadMovie(bool force)
|
|
{
|
|
}
|
|
|
|
void UIScene_PauseMenu::tick()
|
|
{
|
|
// Signal the base class that we've ticked once, so it sets m_bCanHandleInput
|
|
// (the Iggy while-loop that normally sets this never runs without a loaded SWF)
|
|
m_hasTickedOnce = true;
|
|
|
|
UIScene::tick();
|
|
|
|
Rml::Context* ctx = RmlManager::Get().GetContext();
|
|
if (!ctx || !bHasFocus)
|
|
return;
|
|
|
|
// Forward mouse position (for hover effects and correct click targeting)
|
|
ctx->ProcessMouseMove(g_KBMInput.GetMouseX(), g_KBMInput.GetMouseY(), 0);
|
|
|
|
// Forward mouse button presses/releases
|
|
if (g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_LEFT))
|
|
ctx->ProcessMouseButtonDown(0, 0);
|
|
if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_LEFT))
|
|
ctx->ProcessMouseButtonUp(0, 0);
|
|
if (g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_RIGHT))
|
|
ctx->ProcessMouseButtonDown(1, 0);
|
|
if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_RIGHT))
|
|
ctx->ProcessMouseButtonUp(1, 0);
|
|
|
|
// Forward scroll wheel
|
|
int wheelDelta = g_KBMInput.GetMouseWheel();
|
|
if (wheelDelta != 0)
|
|
ctx->ProcessMouseWheel(wheelDelta / -120, 0);
|
|
|
|
ctx->Update();
|
|
}
|
|
|
|
void UIScene_PauseMenu::render(S32 width, S32 height, C4JRender::eViewportType viewport)
|
|
{
|
|
}
|
|
|
|
void UIScene_PauseMenu::handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled)
|
|
{
|
|
if (m_bIgnoreInput)
|
|
return;
|
|
|
|
if (pressed)
|
|
{
|
|
if (iPad == ProfileManager.GetPrimaryPad() && g_NetworkManager.IsLocalGame())
|
|
{
|
|
app.SetXuiServerAction(ProfileManager.GetPrimaryPad(), eXuiServerAction_PauseServer, (void*)FALSE);
|
|
}
|
|
}
|
|
|
|
Rml::Context* ctx = RmlManager::Get().GetContext();
|
|
if (!ctx)
|
|
return;
|
|
|
|
// Translate game actions to RmlUi key events.
|
|
// Mouse clicks are forwarded in tick() via ProcessMouseButtonDown/Up,
|
|
// so here we only handle keyboard-originated actions.
|
|
if (!pressed)
|
|
return;
|
|
|
|
switch (key)
|
|
{
|
|
case ACTION_MENU_UP:
|
|
ctx->ProcessKeyDown(Rml::Input::KI_UP, 0);
|
|
handled = true;
|
|
break;
|
|
case ACTION_MENU_DOWN:
|
|
ctx->ProcessKeyDown(Rml::Input::KI_DOWN, 0);
|
|
handled = true;
|
|
break;
|
|
case ACTION_MENU_OK:
|
|
// Only forward as keyboard Enter if actually coming from keyboard,
|
|
// not from mouse click (mouse is handled in tick()).
|
|
if (g_KBMInput.IsKeyPressed(VK_RETURN))
|
|
{
|
|
ctx->ProcessKeyDown(Rml::Input::KI_RETURN, 0);
|
|
handled = true;
|
|
}
|
|
break;
|
|
case ACTION_MENU_CANCEL:
|
|
case ACTION_MENU_PAUSEMENU:
|
|
if (m_bExitDialog)
|
|
{
|
|
OnExitCancel();
|
|
handled = true;
|
|
}
|
|
else if (m_bSaveDialog)
|
|
{
|
|
OnSaveCancel();
|
|
handled = true;
|
|
}
|
|
else
|
|
{
|
|
navigateBack();
|
|
handled = true;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void UIScene_PauseMenu::ProcessEvent(Rml::Event& event)
|
|
{
|
|
if (m_bIgnoreInput)
|
|
return;
|
|
|
|
const Rml::String& id = event.GetCurrentElement()->GetId();
|
|
|
|
if (event == Rml::EventId::Click)
|
|
{
|
|
if (id == "resume") OnResume();
|
|
else if (id == "help_options") OnHelpAndOptions();
|
|
else if (id == "achievements") OnAchievements();
|
|
else if (id == "save_game") OnSaveGame();
|
|
else if (id == "exit_game") OnExitGame();
|
|
else if (id == "exit_save") OnExitSave();
|
|
else if (id == "exit_nosave") OnExitNoSave();
|
|
else if (id == "exit_cancel") OnExitCancel();
|
|
else if (id == "save_confirm") OnSaveConfirm();
|
|
else if (id == "save_cancel") OnSaveCancel();
|
|
}
|
|
}
|
|
|
|
void UIScene_PauseMenu::ShowScene(bool show)
|
|
{
|
|
if (m_document)
|
|
{
|
|
if (show)
|
|
m_document->Show();
|
|
else
|
|
m_document->Hide();
|
|
}
|
|
}
|
|
|
|
void UIScene_PauseMenu::navigateBack()
|
|
{
|
|
if (m_iPad == ProfileManager.GetPrimaryPad() && g_NetworkManager.IsLocalGame())
|
|
{
|
|
app.SetXuiServerAction(ProfileManager.GetPrimaryPad(), eXuiServerAction_PauseServer, (void*)FALSE);
|
|
}
|
|
|
|
ui.PlayUISFX(eSFX_Back);
|
|
UIScene::navigateBack();
|
|
}
|
|
|
|
void UIScene_PauseMenu::OnResume()
|
|
{
|
|
ui.PlayUISFX(eSFX_Back);
|
|
navigateBack();
|
|
}
|
|
|
|
void UIScene_PauseMenu::OnHelpAndOptions()
|
|
{
|
|
ui.NavigateToScene(m_iPad, eUIScene_HelpAndOptionsMenu);
|
|
}
|
|
|
|
void UIScene_PauseMenu::OnAchievements()
|
|
{
|
|
ui.NavigateToScene(m_iPad, eUIScene_AchievementsMenu);
|
|
}
|
|
|
|
void UIScene_PauseMenu::ShowSaveDialog(bool show)
|
|
{
|
|
if (!m_document)
|
|
return;
|
|
|
|
auto* saveDialog = m_document->GetElementById("save_dialog");
|
|
auto* buttons = m_document->GetElementById("buttons");
|
|
|
|
if (show)
|
|
{
|
|
if (buttons) buttons->SetProperty("display", "none");
|
|
if (saveDialog) saveDialog->SetProperty("display", "block");
|
|
|
|
auto* saveText = m_document->GetElementById("save_text");
|
|
|
|
if (!ProfileManager.IsFullVersion())
|
|
{
|
|
if (saveText) saveText->SetInnerRML("{IDS_UNLOCK_TOSAVE_TEXT}");
|
|
}
|
|
else
|
|
{
|
|
if (saveText) saveText->SetInnerRML("{IDS_CONFIRM_SAVE_GAME}");
|
|
}
|
|
|
|
m_document->GetElementById("save_cancel")->Focus();
|
|
m_bSaveDialog = true;
|
|
}
|
|
else
|
|
{
|
|
if (saveDialog) saveDialog->SetProperty("display", "none");
|
|
if (buttons) buttons->SetProperty("display", "block");
|
|
|
|
m_document->GetElementById("save_game")->Focus();
|
|
m_bSaveDialog = false;
|
|
}
|
|
}
|
|
|
|
void UIScene_PauseMenu::OnSaveGame()
|
|
{
|
|
if (m_iPad != ProfileManager.GetPrimaryPad())
|
|
return;
|
|
|
|
if (!ProfileManager.IsFullVersion())
|
|
{
|
|
ShowSaveDialog(true);
|
|
return;
|
|
}
|
|
|
|
bool bSaveExists;
|
|
StorageManager.DoesSaveExist(&bSaveExists);
|
|
|
|
if (bSaveExists)
|
|
{
|
|
ShowSaveDialog(true);
|
|
}
|
|
else
|
|
{
|
|
app.SetAction(m_iPad, eAppAction_SaveGame);
|
|
}
|
|
}
|
|
|
|
void UIScene_PauseMenu::OnSaveConfirm()
|
|
{
|
|
ShowSaveDialog(false);
|
|
|
|
if (!ProfileManager.IsFullVersion())
|
|
{
|
|
ProfileManager.DisplayFullVersionPurchase(false, m_iPad, eSen_UpsellID_Full_Version_Of_Game);
|
|
}
|
|
else
|
|
{
|
|
app.SetAction(m_iPad, eAppAction_SaveGame);
|
|
}
|
|
}
|
|
|
|
void UIScene_PauseMenu::OnSaveCancel()
|
|
{
|
|
ShowSaveDialog(false);
|
|
}
|
|
|
|
void UIScene_PauseMenu::ShowExitDialog(bool show)
|
|
{
|
|
if (!m_document)
|
|
return;
|
|
|
|
auto* exitDialog = m_document->GetElementById("exit_dialog");
|
|
auto* buttons = m_document->GetElementById("buttons");
|
|
|
|
if (show)
|
|
{
|
|
Minecraft* pMinecraft = Minecraft::GetInstance();
|
|
|
|
if (buttons) buttons->SetProperty("display", "none");
|
|
if (exitDialog) exitDialog->SetProperty("display", "block");
|
|
|
|
// Configure dialog for current state
|
|
auto* exitSave = m_document->GetElementById("exit_save");
|
|
auto* exitNosave = m_document->GetElementById("exit_nosave");
|
|
auto* exitCancel = m_document->GetElementById("exit_cancel");
|
|
auto* exitText = m_document->GetElementById("exit_text");
|
|
|
|
if (ProfileManager.IsFullVersion() && m_iPad == ProfileManager.GetPrimaryPad())
|
|
{
|
|
// Full version primary pad: show Save & Exit + Exit without Saving + Cancel
|
|
if (exitSave) exitSave->SetProperty("display", "inline-block");
|
|
if (exitNosave) exitNosave->SetProperty("display", "inline-block");
|
|
|
|
if (g_NetworkManager.GetPlayerCount() > 1)
|
|
{
|
|
if (exitText) exitText->SetInnerRML("{IDS_CONFIRM_EXIT_GAME_CONFIRM_DISCONNECT_SAVE}");
|
|
}
|
|
else
|
|
{
|
|
if (exitText) exitText->SetInnerRML("{IDS_CONFIRM_EXIT_GAME}");
|
|
}
|
|
if (exitCancel) exitCancel->Focus();
|
|
}
|
|
else if (!ProfileManager.IsFullVersion() && m_iPad == ProfileManager.GetPrimaryPad())
|
|
{
|
|
// Trial version: simple OK/Cancel, "progress will be lost"
|
|
if (exitSave) exitSave->SetProperty("display", "none");
|
|
if (exitNosave) exitNosave->SetProperty("display", "inline-block");
|
|
if (exitNosave) exitNosave->SetInnerRML("{IDS_YES}");
|
|
if (exitText) exitText->SetInnerRML("{IDS_CONFIRM_EXIT_GAME_PROGRESS_LOST}");
|
|
if (exitCancel) exitCancel->Focus();
|
|
}
|
|
|
|
m_bExitDialog = true;
|
|
}
|
|
else
|
|
{
|
|
if (exitDialog) exitDialog->SetProperty("display", "none");
|
|
if (buttons) buttons->SetProperty("display", "block");
|
|
|
|
// Restore default button state
|
|
auto* exitSave = m_document->GetElementById("exit_save");
|
|
auto* exitNosave = m_document->GetElementById("exit_nosave");
|
|
if (exitSave) exitSave->SetProperty("display", "inline-block");
|
|
if (exitNosave) exitNosave->SetInnerRML("{IDS_EXIT_GAME_NO_SAVE}");
|
|
if (exitNosave) exitNosave->SetProperty("display", "inline-block");
|
|
|
|
m_document->GetElementById("exit_game")->Focus();
|
|
m_bExitDialog = false;
|
|
}
|
|
}
|
|
|
|
void UIScene_PauseMenu::OnExitGame()
|
|
{
|
|
Minecraft* pMinecraft = Minecraft::GetInstance();
|
|
|
|
// Non-primary pad: exit directly without dialog
|
|
if (m_iPad != ProfileManager.GetPrimaryPad())
|
|
{
|
|
if (pMinecraft->localplayers[m_iPad] != nullptr)
|
|
TelemetryManager->RecordLevelExit(m_iPad, eSen_LevelExitStatus_Exited);
|
|
app.SetAction(m_iPad, eAppAction_ExitPlayer);
|
|
return;
|
|
}
|
|
|
|
// Primary pad: show inline confirmation dialog (no Iggy MessageBox)
|
|
ShowExitDialog(true);
|
|
}
|
|
|
|
void UIScene_PauseMenu::OnExitSave()
|
|
{
|
|
ShowExitDialog(false);
|
|
SetIgnoreInput(true);
|
|
|
|
Minecraft* pMinecraft = Minecraft::GetInstance();
|
|
if (pMinecraft->localplayers[m_iPad] != nullptr)
|
|
{
|
|
int playTime = static_cast<int>(pMinecraft->localplayers[m_iPad]->getSessionTimer());
|
|
TelemetryManager->RecordLevelExit(m_iPad, eSen_LevelExitStatus_Exited);
|
|
}
|
|
|
|
MinecraftServer::getInstance()->setSaveOnExit(true);
|
|
app.SetAction(m_iPad, eAppAction_ExitWorld);
|
|
}
|
|
|
|
void UIScene_PauseMenu::OnExitNoSave()
|
|
{
|
|
ShowExitDialog(false);
|
|
SetIgnoreInput(true);
|
|
|
|
Minecraft* pMinecraft = Minecraft::GetInstance();
|
|
if (pMinecraft->localplayers[m_iPad] != nullptr)
|
|
{
|
|
int playTime = static_cast<int>(pMinecraft->localplayers[m_iPad]->getSessionTimer());
|
|
TelemetryManager->RecordLevelExit(m_iPad, eSen_LevelExitStatus_Exited);
|
|
}
|
|
|
|
app.SetAction(m_iPad, eAppAction_ExitWorld);
|
|
}
|
|
|
|
void UIScene_PauseMenu::OnExitCancel()
|
|
{
|
|
ShowExitDialog(false);
|
|
}
|