[XAM] Implemented XamShowMarketplaceUI
This commit is contained in:
parent
738c8dbd11
commit
6df0904e86
|
@ -26,6 +26,8 @@ DEFINE_bool(storage_selection_dialog, false,
|
||||||
"Show storage device selection dialog when the game requests it.",
|
"Show storage device selection dialog when the game requests it.",
|
||||||
"UI");
|
"UI");
|
||||||
|
|
||||||
|
DECLARE_int32(license_mask);
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
namespace xam {
|
namespace xam {
|
||||||
|
@ -208,6 +210,49 @@ X_RESULT xeXamDispatchHeadlessEx(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
X_RESULT xeXamDispatchDialogAsync(T* dialog,
|
||||||
|
std::function<void(T*)> close_callback) {
|
||||||
|
// Broadcast XN_SYS_UI = true
|
||||||
|
kernel_state()->BroadcastNotification(0x9, true);
|
||||||
|
++xam_dialogs_shown_;
|
||||||
|
|
||||||
|
// Important to pass captured vars by value here since we return from this
|
||||||
|
// without waiting for the dialog to close so the original local vars will be
|
||||||
|
// destroyed.
|
||||||
|
// FIXME: Probably not the best idea to call Sleep in UI thread.
|
||||||
|
dialog->set_close_callback([dialog, close_callback]() {
|
||||||
|
close_callback(dialog);
|
||||||
|
|
||||||
|
--xam_dialogs_shown_;
|
||||||
|
|
||||||
|
xe::threading::Sleep(std::chrono::milliseconds(100));
|
||||||
|
// Broadcast XN_SYS_UI = false
|
||||||
|
kernel_state()->BroadcastNotification(0x9, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
return X_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
X_RESULT xeXamDispatchHeadlessAsync(std::function<void()> run_callback) {
|
||||||
|
// Broadcast XN_SYS_UI = true
|
||||||
|
kernel_state()->BroadcastNotification(0x9, true);
|
||||||
|
++xam_dialogs_shown_;
|
||||||
|
|
||||||
|
auto display_window = kernel_state()->emulator()->display_window();
|
||||||
|
display_window->app_context().CallInUIThread([run_callback]() {
|
||||||
|
run_callback();
|
||||||
|
|
||||||
|
--xam_dialogs_shown_;
|
||||||
|
|
||||||
|
xe::threading::Sleep(std::chrono::milliseconds(100));
|
||||||
|
// Broadcast XN_SYS_UI = false
|
||||||
|
kernel_state()->BroadcastNotification(0x9, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
return X_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
dword_result_t XamIsUIActive_entry() { return xeXamIsUIActive(); }
|
dword_result_t XamIsUIActive_entry() { return xeXamIsUIActive(); }
|
||||||
DECLARE_XAM_EXPORT2(XamIsUIActive, kUI, kImplemented, kHighFrequency);
|
DECLARE_XAM_EXPORT2(XamIsUIActive, kUI, kImplemented, kHighFrequency);
|
||||||
|
|
||||||
|
@ -620,6 +665,83 @@ dword_result_t XamGetDashContext_entry(const ppc_context_t& ctx) {
|
||||||
|
|
||||||
DECLARE_XAM_EXPORT1(XamGetDashContext, kNone, kImplemented);
|
DECLARE_XAM_EXPORT1(XamGetDashContext, kNone, kImplemented);
|
||||||
|
|
||||||
|
dword_result_t XamShowMarketplaceUI_entry(dword_t user_index, dword_t ui_type,
|
||||||
|
qword_t offer_id, dword_t unk_dword) {
|
||||||
|
// ui_type:
|
||||||
|
// 0 - view all content for the current title
|
||||||
|
// 1 - view content specified by offer id
|
||||||
|
// unk_dword:
|
||||||
|
// always -1? check more games
|
||||||
|
if (user_index >= 4) {
|
||||||
|
return X_ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!kernel_state()->IsUserSignedIn(user_index)) {
|
||||||
|
return X_ERROR_NO_SUCH_USER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cvars::headless) {
|
||||||
|
return xeXamDispatchHeadlessAsync([]() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto close = [ui_type](MessageBoxDialog* dialog) -> void {
|
||||||
|
if (ui_type == 1) {
|
||||||
|
uint32_t button = dialog->chosen_button();
|
||||||
|
if (button == 0) {
|
||||||
|
cvars::license_mask = 1;
|
||||||
|
|
||||||
|
// XN_LIVE_CONTENT_INSTALLED
|
||||||
|
kernel_state()->BroadcastNotification(0x2000007, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string title = "Xbox Marketplace";
|
||||||
|
std::string desc = "";
|
||||||
|
cxxopts::OptionNames buttons;
|
||||||
|
|
||||||
|
switch (ui_type) {
|
||||||
|
case 0:
|
||||||
|
desc =
|
||||||
|
"Game requested to open marketplace page with all content for the "
|
||||||
|
"current title ID.";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
desc = fmt::format(
|
||||||
|
"Game requested to open marketplace page for offer ID 0x{:016X}.",
|
||||||
|
offer_id);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
desc = fmt::format("Unknown marketplace op {:d}", ui_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc +=
|
||||||
|
"\nNote that since Xenia cannot access Xbox Marketplace, any DLC must be "
|
||||||
|
"installed manually using File -> Install Content.";
|
||||||
|
|
||||||
|
switch (ui_type) {
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
buttons.push_back("OK");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
desc +=
|
||||||
|
"\n\nTo start trial games in full mode, set license_mask to 1 in "
|
||||||
|
"Xenia config file.\n\nDo you wish to change license_mask to 1 for "
|
||||||
|
"*this session*?";
|
||||||
|
buttons.push_back("Yes");
|
||||||
|
buttons.push_back("No");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Emulator* emulator = kernel_state()->emulator();
|
||||||
|
ui::ImGuiDrawer* imgui_drawer = emulator->imgui_drawer();
|
||||||
|
return xeXamDispatchDialogAsync<MessageBoxDialog>(
|
||||||
|
new MessageBoxDialog(imgui_drawer, title, desc, buttons, 0), close);
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT1(XamShowMarketplaceUI, kUI, kSketchy);
|
||||||
|
|
||||||
} // namespace xam
|
} // namespace xam
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
Loading…
Reference in New Issue