From 249241d7cda68114836487a7a27a3532dfc1fba6 Mon Sep 17 00:00:00 2001 From: Mats Date: Wed, 9 Mar 2022 15:05:07 +0100 Subject: [PATCH] (steam) Initial integration with Steam API w/ mist (#13710) --- Makefile.common | 7 + config.def.h | 3 + configuration.c | 3 + configuration.h | 3 + intl/msg_hash_lbl.h | 22 ++ intl/msg_hash_us.h | 44 ++++ menu/cbs/menu_cbs_deferred_push.c | 14 ++ menu/cbs/menu_cbs_get_value.c | 52 +++++ menu/cbs/menu_cbs_ok.c | 68 +++++++ menu/cbs/menu_cbs_sublabel.c | 12 ++ menu/cbs/menu_cbs_title.c | 30 +++ menu/drivers/materialui.c | 10 + menu/drivers/ozone.c | 10 + menu/drivers/xmb.c | 13 ++ menu/menu_cbs.h | 6 + menu/menu_displaylist.c | 139 ++++++++++++- menu/menu_displaylist.h | 4 + menu/menu_driver.h | 5 + menu/menu_setting.c | 27 +++ msg_hash.h | 18 ++ qb/config.libs.sh | 18 ++ qb/config.params.sh | 1 + retroarch.c | 16 ++ steam/steam.c | 325 ++++++++++++++++++++++++++++++ steam/steam.h | 43 ++++ tasks/task_steam.c | 108 ++++++++++ 26 files changed, 1000 insertions(+), 1 deletion(-) create mode 100644 steam/steam.c create mode 100644 steam/steam.h create mode 100644 tasks/task_steam.c diff --git a/Makefile.common b/Makefile.common index 81923aad24..2c374a7113 100644 --- a/Makefile.common +++ b/Makefile.common @@ -2457,6 +2457,13 @@ ifeq ($(ANDROID), 1) OBJ += play_feature_delivery/play_feature_delivery.o endif +### Steam integration using mist +ifeq ($(HAVE_MIST), 1) + INCLUDE_DIRS += -I$(MIST_PATH)/include + LDFLAGS += -L$(MIST_PATH) -lmist + OBJ += steam/steam.o tasks/task_steam.o +endif + ################################## ### Classic Platform specifics ### ###############WIP################ diff --git a/config.def.h b/config.def.h index 438798eb56..10dca321c4 100644 --- a/config.def.h +++ b/config.def.h @@ -666,6 +666,9 @@ static const bool menu_show_core_updater = false; #else static const bool menu_show_core_updater = true; #endif +#ifdef HAVE_MIST +static const bool menu_show_core_manager_steam = true; +#endif static const bool menu_show_legacy_thumbnail_updater = false; static const bool menu_show_sublabels = true; static const bool menu_dynamic_wallpaper_enable = true; diff --git a/configuration.c b/configuration.c index b9422b2028..7e346ff6e9 100644 --- a/configuration.c +++ b/configuration.c @@ -1862,6 +1862,9 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("menu_show_online_updater", &settings->bools.menu_show_online_updater, true, menu_show_online_updater, false); SETTING_BOOL("menu_show_core_updater", &settings->bools.menu_show_core_updater, true, menu_show_core_updater, false); SETTING_BOOL("menu_show_legacy_thumbnail_updater", &settings->bools.menu_show_legacy_thumbnail_updater, true, menu_show_legacy_thumbnail_updater, false); +#ifdef HAVE_MIST + SETTING_BOOL("menu_show_core_manager_steam", &settings->bools.menu_show_core_manager_steam, true, menu_show_core_manager_steam, false); +#endif SETTING_BOOL("filter_by_current_core", &settings->bools.filter_by_current_core, true, DEFAULT_FILTER_BY_CURRENT_CORE, false); SETTING_BOOL("rgui_show_start_screen", &settings->bools.menu_show_start_screen, false, false /* TODO */, false); SETTING_BOOL("menu_navigation_wraparound_enable", &settings->bools.menu_navigation_wraparound_enable, true, true, false); diff --git a/configuration.h b/configuration.h index 519a4229bf..5fbb7532d4 100644 --- a/configuration.h +++ b/configuration.h @@ -659,6 +659,9 @@ typedef struct settings bool menu_horizontal_animation; bool menu_scroll_fast; bool menu_show_online_updater; +#ifdef HAVE_MIST + bool menu_show_core_manager_steam; +#endif bool menu_show_core_updater; bool menu_show_load_core; bool menu_show_load_content; diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index eea870f293..3a987c1524 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -620,6 +620,16 @@ MSG_HASH( MENU_ENUM_LABEL_CORE_MANAGER_LIST, "core_manager_list" ) +#ifdef HAVE_MIST +MSG_HASH( + MENU_ENUM_LABEL_CORE_STEAM_INSTALL, + "core_steam_install" + ) +MSG_HASH( + MENU_ENUM_LABEL_CORE_STEAM_UNINSTALL, + "core_steam_uninstall" + ) +#endif MSG_HASH( MENU_ENUM_LABEL_CPU_ARCHITECTURE, "system_information_cpu_architecture" @@ -884,6 +894,12 @@ MSG_HASH( MENU_ENUM_LABEL_DEFERRED_CORE_INFORMATION_LIST, "deferred_core_information_list" ) +#ifdef HAVE_MIST +MSG_HASH( + MENU_ENUM_LABEL_DEFERRED_CORE_INFORMATION_STEAM_LIST, + "deferred_core_information_steam_list" + ) +#endif MSG_HASH( MENU_ENUM_LABEL_DEFERRED_CORE_UPDATER_LIST, "core_updater" @@ -892,6 +908,12 @@ MSG_HASH( MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_LIST, "deferred_core_manager_list" ) +#ifdef HAVE_MIST +MSG_HASH( + MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_STEAM_LIST, + "deferred_core_manager_steam_list" + ) +#endif MSG_HASH( MENU_ENUM_LABEL_DEFERRED_CURSOR_MANAGER_LIST, "deferred_cursor_manager_list" diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 2ae08a80eb..bbe8f4d5c1 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3203,7 +3203,51 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_MANAGER_LIST, "Perform offline maintenance tasks on installed cores (backup, restore, delete, etc.) and view core information." ) +#ifdef HAVE_MIST +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_MANAGER_STEAM_LIST, + "Manage Cores" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_MANAGER_STEAM_LIST, + "Install or uninstall cores distributed through Steam." + ) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_STEAM_INSTALL, + "Install core" +) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_STEAM_UNINSTALL, + "Uninstall core" +) + +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_MANAGER_STEAM, + "Show 'Manage cores'" +) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_MANAGER_STEAM, + "Show the 'Manage cores' option in the Main Menu." +) + +MSG_HASH( + MSG_CORE_STEAM_INSTALLING, + "Installing core: " +) + +MSG_HASH( + MSG_CORE_STEAM_UNINSTALLED, + "The core will uninstall when quitting RetroArch." +) + +MSG_HASH( + MSG_CORE_STEAM_CURRENTLY_DOWNLOADING, + "The core is currently downloading" +) +#endif /* Settings > Configuration */ MSG_HASH( diff --git a/menu/cbs/menu_cbs_deferred_push.c b/menu/cbs/menu_cbs_deferred_push.c index a439abddd9..7274fddadf 100644 --- a/menu/cbs/menu_cbs_deferred_push.c +++ b/menu/cbs/menu_cbs_deferred_push.c @@ -271,6 +271,11 @@ GENERIC_DEFERRED_PUSH(deferred_push_core_delete_backup_list, DISPLAYLIST_ GENERIC_DEFERRED_PUSH(deferred_push_core_manager_list, DISPLAYLIST_CORE_MANAGER_LIST) +#ifdef HAVE_MIST +GENERIC_DEFERRED_PUSH(deferred_push_core_manager_steam_list, DISPLAYLIST_CORE_MANAGER_STEAM_LIST) +GENERIC_DEFERRED_PUSH(deferred_push_core_information_steam_list, DISPLAYLIST_CORE_INFORMATION_STEAM_LIST) +#endif + GENERIC_DEFERRED_PUSH(deferred_push_file_browser_select_sideload_core, DISPLAYLIST_FILE_BROWSER_SELECT_SIDELOAD_CORE) static int deferred_push_cursor_manager_list_deferred( @@ -891,6 +896,10 @@ static int menu_cbs_init_bind_deferred_push_compare_label( {MENU_ENUM_LABEL_DEFERRED_CORE_RESTORE_BACKUP_LIST, deferred_push_core_restore_backup_list}, {MENU_ENUM_LABEL_DEFERRED_CORE_DELETE_BACKUP_LIST, deferred_push_core_delete_backup_list}, {MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_LIST, deferred_push_core_manager_list}, +#ifdef HAVE_MIST + {MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_STEAM_LIST, deferred_push_core_manager_steam_list}, + {MENU_ENUM_LABEL_DEFERRED_CORE_INFORMATION_STEAM_LIST, deferred_push_core_information_steam_list}, +#endif {MENU_ENUM_LABEL_SIDELOAD_CORE_LIST, deferred_push_file_browser_select_sideload_core}, {MENU_ENUM_LABEL_DEFERRED_ARCHIVE_ACTION_DETECT_CORE, deferred_archive_action_detect_core}, {MENU_ENUM_LABEL_DEFERRED_ARCHIVE_ACTION, deferred_archive_action}, @@ -1318,6 +1327,11 @@ static int menu_cbs_init_bind_deferred_push_compare_label( case MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_LIST: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_manager_list); break; +#ifdef HAVE_MIST + case MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_STEAM_LIST: + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_manager_steam_list); + break; +#endif case MENU_ENUM_LABEL_SIDELOAD_CORE_LIST: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_file_browser_select_sideload_core); break; diff --git a/menu/cbs/menu_cbs_get_value.c b/menu/cbs/menu_cbs_get_value.c index 655c2f5b97..7e411330b1 100644 --- a/menu/cbs/menu_cbs_get_value.c +++ b/menu/cbs/menu_cbs_get_value.c @@ -59,6 +59,10 @@ #include "../../cheevos/cheevos_menu.h" #endif +#ifdef HAVE_MIST +#include "../../steam/steam.h" +#endif + #ifndef BIND_ACTION_GET_VALUE #define BIND_ACTION_GET_VALUE(cbs, name) (cbs)->action_get_value = (name) #endif @@ -519,6 +523,48 @@ static void menu_action_setting_disp_set_label_core_manager_entry( } } +#ifdef HAVE_MIST +static void menu_action_setting_disp_set_label_core_manager_steam_entry( + file_list_t* list, + unsigned *w, unsigned type, unsigned i, + const char *label, + char *s, size_t len, + const char *path, + char *s2, size_t len2) +{ + steam_core_dlc_list_t *core_dlc_list = NULL; + steam_core_dlc_t *core_dlc = NULL; + bool dlc_installed = false; + + *s = '\0'; + *w = 0; + + if (MIST_IS_ERROR(steam_get_core_dlcs(&core_dlc_list, true))) return; + + strlcpy(s2, path, len2); + + core_dlc = steam_get_core_dlc_by_name(core_dlc_list, path); + if (core_dlc == NULL) return; + + MistResult result = mist_steam_apps_is_dlc_installed(core_dlc->app_id, &dlc_installed); + + if (MIST_IS_ERROR(result)) + { + RARCH_ERR("[Steam]: Failed to get dlc install status (%d-%d)\n", MIST_UNPACK_RESULT(result)); + return; + } + + if (dlc_installed) + { + s[0] = '['; + s[1] = '#'; + s[2] = ']'; + s[3] = '\0'; + *w = (unsigned)STRLEN_CONST("[#]"); + } +} +#endif + static void menu_action_setting_disp_set_label_contentless_core( file_list_t* list, unsigned *w, unsigned type, unsigned i, @@ -1931,6 +1977,12 @@ static int menu_cbs_init_bind_get_string_representation_compare_label( BIND_ACTION_GET_VALUE(cbs, menu_action_setting_disp_set_label_core_manager_entry); break; +#ifdef HAVE_MIST + case MENU_ENUM_LABEL_CORE_MANAGER_STEAM_ENTRY: + BIND_ACTION_GET_VALUE(cbs, + menu_action_setting_disp_set_label_core_manager_steam_entry); + break; +#endif case MENU_ENUM_LABEL_CONTENTLESS_CORE: BIND_ACTION_GET_VALUE(cbs, menu_action_setting_disp_set_label_contentless_core); diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 46bb8d3c7d..fe34d02c7e 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -104,6 +104,10 @@ #include "../../switch_performance_profiles.h" #endif +#ifdef HAVE_MIST +#include "../../steam/steam.h" +#endif + enum { ACTION_OK_LOAD_PRESET = 0, @@ -320,6 +324,10 @@ static enum msg_hash_enums action_ok_dl_to_enum(unsigned lbl) return MENU_ENUM_LABEL_DEFERRED_CORE_SETTINGS_LIST; case ACTION_OK_DL_CORE_INFORMATION_LIST: return MENU_ENUM_LABEL_DEFERRED_CORE_INFORMATION_LIST; +#ifdef HAVE_MIST + case ACTION_OK_DL_CORE_INFORMATION_STEAM_LIST: + return MENU_ENUM_LABEL_DEFERRED_CORE_INFORMATION_STEAM_LIST; +#endif case ACTION_OK_DL_CORE_RESTORE_BACKUP_LIST: return MENU_ENUM_LABEL_DEFERRED_CORE_RESTORE_BACKUP_LIST; case ACTION_OK_DL_CORE_DELETE_BACKUP_LIST: @@ -480,6 +488,10 @@ static enum msg_hash_enums action_ok_dl_to_enum(unsigned lbl) return MENU_ENUM_LABEL_DEFERRED_MANUAL_CONTENT_SCAN_LIST; case ACTION_OK_DL_CORE_MANAGER_LIST: return MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_LIST; +#ifdef HAVE_MIST + case ACTION_OK_DL_CORE_MANAGER_STEAM_LIST: + return MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_STEAM_LIST; +#endif case ACTION_OK_DL_CORE_OPTION_OVERRIDE_LIST: return MENU_ENUM_LABEL_DEFERRED_CORE_OPTION_OVERRIDE_LIST; default: @@ -1487,6 +1499,9 @@ int generic_action_ok_displaylist_push(const char *path, case ACTION_OK_DL_DRIVER_SETTINGS_LIST: case ACTION_OK_DL_CORE_SETTINGS_LIST: case ACTION_OK_DL_CORE_INFORMATION_LIST: +#ifdef HAVE_MIST + case ACTION_OK_DL_CORE_INFORMATION_STEAM_LIST: +#endif case ACTION_OK_DL_VIDEO_SETTINGS_LIST: case ACTION_OK_DL_VIDEO_HDR_SETTINGS_LIST: case ACTION_OK_DL_VIDEO_SYNCHRONIZATION_SETTINGS_LIST: @@ -1565,6 +1580,9 @@ int generic_action_ok_displaylist_push(const char *path, case ACTION_OK_DL_CDROM_INFO_LIST: case ACTION_OK_DL_MANUAL_CONTENT_SCAN_LIST: case ACTION_OK_DL_CORE_MANAGER_LIST: +#ifdef HAVE_MIST + case ACTION_OK_DL_CORE_MANAGER_STEAM_LIST: +#endif case ACTION_OK_DL_CORE_OPTION_OVERRIDE_LIST: ACTION_OK_DL_LBL(action_ok_dl_to_enum(action_type), DISPLAYLIST_GENERIC); break; @@ -5747,6 +5765,9 @@ DEFAULT_ACTION_OK_FUNC(action_ok_push_video_output_settings_list, ACTION_OK_DL_V DEFAULT_ACTION_OK_FUNC(action_ok_push_configuration_settings_list, ACTION_OK_DL_CONFIGURATION_SETTINGS_LIST) DEFAULT_ACTION_OK_FUNC(action_ok_push_core_settings_list, ACTION_OK_DL_CORE_SETTINGS_LIST) DEFAULT_ACTION_OK_FUNC(action_ok_push_core_information_list, ACTION_OK_DL_CORE_INFORMATION_LIST) +#ifdef HAVE_MIST +DEFAULT_ACTION_OK_FUNC(action_ok_push_core_information_steam_list, ACTION_OK_DL_CORE_INFORMATION_STEAM_LIST) +#endif DEFAULT_ACTION_OK_FUNC(action_ok_push_core_restore_backup_list, ACTION_OK_DL_CORE_RESTORE_BACKUP_LIST) DEFAULT_ACTION_OK_FUNC(action_ok_push_core_delete_backup_list, ACTION_OK_DL_CORE_DELETE_BACKUP_LIST) DEFAULT_ACTION_OK_FUNC(action_ok_push_audio_settings_list, ACTION_OK_DL_AUDIO_SETTINGS_LIST) @@ -5784,6 +5805,9 @@ DEFAULT_ACTION_OK_FUNC(action_ok_pl_thumbnails_updater_list, ACTION_OK_DL_PL_THU DEFAULT_ACTION_OK_FUNC(action_ok_push_manual_content_scan_list, ACTION_OK_DL_MANUAL_CONTENT_SCAN_LIST) DEFAULT_ACTION_OK_FUNC(action_ok_manual_content_scan_dat_file, ACTION_OK_DL_MANUAL_CONTENT_SCAN_DAT_FILE) DEFAULT_ACTION_OK_FUNC(action_ok_push_core_manager_list, ACTION_OK_DL_CORE_MANAGER_LIST) +#ifdef HAVE_MIST +DEFAULT_ACTION_OK_FUNC(action_ok_push_core_manager_steam_list, ACTION_OK_DL_CORE_MANAGER_STEAM_LIST) +#endif DEFAULT_ACTION_OK_FUNC(action_ok_push_core_option_override_list, ACTION_OK_DL_CORE_OPTION_OVERRIDE_LIST) DEFAULT_ACTION_OK_FUNC(action_ok_push_core_options_list, ACTION_OK_DL_CORE_OPTIONS_LIST) @@ -7718,6 +7742,42 @@ static int action_ok_playlist_refresh(const char *path, return 0; } +#ifdef HAVE_MIST +static int action_ok_core_steam_install( + const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + steam_core_dlc_list_t *core_dlc_list = NULL; + steam_core_dlc_t *core_dlc = NULL; + + if (MIST_IS_ERROR(steam_get_core_dlcs(&core_dlc_list, true))) return 0; + + core_dlc = steam_get_core_dlc_by_name(core_dlc_list, label); + if (core_dlc == NULL) return 0; + + steam_install_core_dlc(core_dlc); + + return 0; +} + +static int action_ok_core_steam_uninstall( + const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + steam_core_dlc_list_t *core_dlc_list = NULL; + steam_core_dlc_t *core_dlc = NULL; + + if (MIST_IS_ERROR(steam_get_core_dlcs(&core_dlc_list, true))) return 0; + + core_dlc = steam_get_core_dlc_by_name(core_dlc_list, label); + if (core_dlc == NULL) return 0; + + steam_uninstall_core_dlc(core_dlc); + + return 0; +} +#endif + static int is_rdb_entry(enum msg_hash_enums enum_idx) { switch (enum_idx) @@ -7994,6 +8054,9 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, {MENU_ENUM_LABEL_CORE_SETTINGS, action_ok_push_core_settings_list}, {MENU_ENUM_LABEL_CORE_INFORMATION, action_ok_push_core_information_list}, {MENU_ENUM_LABEL_CORE_MANAGER_ENTRY, action_ok_push_core_information_list}, +#ifdef HAVE_MIST + {MENU_ENUM_LABEL_CORE_MANAGER_STEAM_ENTRY, action_ok_push_core_information_steam_list}, +#endif {MENU_ENUM_LABEL_CORE_RESTORE_BACKUP_LIST, action_ok_push_core_restore_backup_list}, {MENU_ENUM_LABEL_CORE_DELETE_BACKUP_LIST, action_ok_push_core_delete_backup_list}, {MENU_ENUM_LABEL_CONFIGURATION_SETTINGS, action_ok_push_configuration_settings_list}, @@ -8114,6 +8177,11 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, {MENU_ENUM_LABEL_SCREEN_RESOLUTION, action_ok_video_resolution}, {MENU_ENUM_LABEL_PLAYLIST_MANAGER_DEFAULT_CORE, action_ok_playlist_default_core}, {MENU_ENUM_LABEL_CORE_MANAGER_LIST, action_ok_push_core_manager_list}, +#ifdef HAVE_MIST + {MENU_ENUM_LABEL_CORE_MANAGER_STEAM_LIST, action_ok_push_core_manager_steam_list}, + {MENU_ENUM_LABEL_CORE_STEAM_INSTALL, action_ok_core_steam_install}, + {MENU_ENUM_LABEL_CORE_STEAM_UNINSTALL, action_ok_core_steam_uninstall}, +#endif {MENU_ENUM_LABEL_EXPLORE_TAB, action_ok_push_default}, {MENU_ENUM_LABEL_CONTENTLESS_CORES_TAB, action_ok_push_default}, }; diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 049b5fd11e..cc3a8b3329 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -525,6 +525,10 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_switch_installed_cores_pfd, MENU_ #endif DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_sideload_core_list, MENU_ENUM_SUBLABEL_SIDELOAD_CORE_LIST) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_core_manager_list, MENU_ENUM_SUBLABEL_CORE_MANAGER_LIST) +#ifdef HAVE_MIST +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_core_manager_steam_list, MENU_ENUM_SUBLABEL_CORE_MANAGER_STEAM_LIST) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_menu_show_core_manager_steam, MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_MANAGER_STEAM) +#endif DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_load_disc, MENU_ENUM_SUBLABEL_LOAD_DISC) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_dump_disc, MENU_ENUM_SUBLABEL_DUMP_DISC) #ifdef HAVE_LAKKA @@ -3739,6 +3743,14 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_CORE_MANAGER_LIST: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_manager_list); break; +#ifdef HAVE_MIST + case MENU_ENUM_LABEL_CORE_MANAGER_STEAM_LIST: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_manager_steam_list); + break; + case MENU_ENUM_LABEL_MENU_SHOW_CORE_MANAGER_STEAM: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_show_core_manager_steam); + break; +#endif case MENU_ENUM_LABEL_VIDEO_POST_FILTER_RECORD: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_post_filter_record); break; diff --git a/menu/cbs/menu_cbs_title.c b/menu/cbs/menu_cbs_title.c index 9222ab8c13..d6c06be005 100644 --- a/menu/cbs/menu_cbs_title.c +++ b/menu/cbs/menu_cbs_title.c @@ -491,6 +491,16 @@ error: return 0; } +#ifdef HAVE_MIST +static int action_get_core_information_steam_list( + const char *path, const char *label, unsigned menu_type, + char *s, size_t len) +{ + snprintf(s, len, "%s - %s", msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFORMATION), path); + return 1; +} +#endif + static int action_get_title_dropdown_input_description_common( const char *input_name, unsigned port, char *s, size_t len) { @@ -758,6 +768,9 @@ DEFAULT_TITLE_SEARCH_FILTER_MACRO(action_get_title_deferred_contentless_cores_li DEFAULT_TITLE_SEARCH_FILTER_MACRO(action_get_core_updater_list, MENU_ENUM_LABEL_VALUE_CORE_UPDATER_LIST) DEFAULT_TITLE_SEARCH_FILTER_MACRO(action_get_core_manager_list, MENU_ENUM_LABEL_VALUE_CORE_MANAGER_LIST) +#ifdef HAVE_MIST +DEFAULT_TITLE_SEARCH_FILTER_MACRO(action_get_core_manager_steam_list, MENU_ENUM_LABEL_VALUE_CORE_MANAGER_STEAM_LIST) +#endif DEFAULT_TITLE_SEARCH_FILTER_MACRO(action_get_core_cheat_options_list, MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS) DEFAULT_FILL_TITLE_SEARCH_FILTER_MACRO(action_get_title_video_shader_preset, MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_TWO) @@ -934,6 +947,9 @@ static int menu_cbs_init_bind_title_compare_label(menu_file_list_cbs_t *cbs, {MENU_ENUM_LABEL_DEFERRED_REMAPPINGS_PORT_LIST, action_get_title_remap_port}, {MENU_ENUM_LABEL_DEFERRED_CORE_SETTINGS_LIST, action_get_core_settings_list}, {MENU_ENUM_LABEL_DEFERRED_CORE_INFORMATION_LIST, action_get_core_information_list}, +#ifdef HAVE_MIST + {MENU_ENUM_LABEL_DEFERRED_CORE_INFORMATION_STEAM_LIST, action_get_core_information_steam_list}, +#endif {MENU_ENUM_LABEL_DEFERRED_CORE_RESTORE_BACKUP_LIST, action_get_title_deferred_core_restore_backup_list}, {MENU_ENUM_LABEL_DEFERRED_CORE_DELETE_BACKUP_LIST, action_get_title_deferred_core_delete_backup_list}, {MENU_ENUM_LABEL_DEFERRED_DUMP_DISC_LIST, action_get_dump_disc_list}, @@ -1142,6 +1158,10 @@ static int menu_cbs_init_bind_title_compare_label(menu_file_list_cbs_t *cbs, action_get_core_updater_list}, {MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_LIST, action_get_core_manager_list}, +#ifdef HAVE_MIST + {MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_STEAM_LIST, + action_get_core_manager_steam_list}, +#endif {MENU_ENUM_LABEL_CONFIGURATIONS_LIST, action_get_configurations_list}, {MENU_ENUM_LABEL_ADD_CONTENT_LIST, @@ -1463,6 +1483,11 @@ static int menu_cbs_init_bind_title_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_core_manager_list); break; +#ifdef HAVE_MIST + case MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_STEAM_LIST: + BIND_ACTION_GET_TITLE(cbs, action_get_core_manager_steam_list); + break; +#endif case MENU_ENUM_LABEL_ADD_CONTENT_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_add_content_list); break; @@ -1546,6 +1571,11 @@ static int menu_cbs_init_bind_title_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_DEFERRED_CORE_INFORMATION_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_core_information_list); break; +#ifdef HAVE_MIST + case MENU_ENUM_LABEL_DEFERRED_CORE_INFORMATION_STEAM_LIST: + BIND_ACTION_GET_TITLE(cbs, action_get_core_information_steam_list); + break; +#endif case MENU_ENUM_LABEL_DEFERRED_CORE_RESTORE_BACKUP_LIST: BIND_ACTION_GET_TITLE(cbs, action_get_title_deferred_core_restore_backup_list); break; diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 3dfba1789e..6ad0fa0818 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -9337,6 +9337,16 @@ static int materialui_list_push(void *data, void *userdata, false); } #endif +#endif +#ifdef HAVE_MIST + if (settings->bools.menu_show_core_manager_steam) + { + MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM( + info->list, + MENU_ENUM_LABEL_CORE_MANAGER_STEAM_LIST, + PARSE_ACTION, + false); + } #endif if (settings->uints.menu_content_show_add_entry == MENU_ADD_CONTENT_ENTRY_DISPLAY_MAIN_TAB) diff --git a/menu/drivers/ozone.c b/menu/drivers/ozone.c index ef385f6fdc..2fa22c007f 100644 --- a/menu/drivers/ozone.c +++ b/menu/drivers/ozone.c @@ -7990,6 +7990,16 @@ static int ozone_list_push(void *data, void *userdata, false); } #endif +#endif +#ifdef HAVE_MIST + if (settings->bools.menu_show_core_manager_steam && !settings->bools.kiosk_mode_enable) + { + MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM( + info->list, + MENU_ENUM_LABEL_CORE_MANAGER_STEAM_LIST, + PARSE_ACTION, + false); + } #endif if (!settings->bools.menu_content_show_settings && !string_is_empty(settings->paths.menu_content_show_settings_password)) { diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index bba8e3bfb1..8b9b2f09c7 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -7036,6 +7036,9 @@ static int xmb_list_push(void *data, void *userdata, #endif #if defined(HAVE_NETWORKING) && defined(HAVE_ONLINE_UPDATER) bool menu_show_online_updater = settings->bools.menu_show_online_updater; +#endif +#if defined(HAVE_MIST) + bool menu_show_core_manager_steam = settings->bools.menu_show_core_manager_steam; #endif bool menu_content_show_settings = settings->bools.menu_content_show_settings; const char *menu_content_show_settings_password = @@ -7200,6 +7203,16 @@ static int xmb_list_push(void *data, void *userdata, false); } #endif +#endif +#ifdef HAVE_MIST + if (menu_show_core_manager_steam && !kiosk_mode_enable) + { + MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM( + info->list, + MENU_ENUM_LABEL_CORE_MANAGER_STEAM_LIST, + PARSE_ACTION, + false); + } #endif if ( !menu_content_show_settings && !string_is_empty(menu_content_show_settings_password)) diff --git a/menu/menu_cbs.h b/menu/menu_cbs.h index 735cd06a6f..484744fa7b 100644 --- a/menu/menu_cbs.h +++ b/menu/menu_cbs.h @@ -117,6 +117,9 @@ enum ACTION_OK_DL_CHEAT_SEARCH_SETTINGS_LIST, ACTION_OK_DL_CORE_SETTINGS_LIST, ACTION_OK_DL_CORE_INFORMATION_LIST, +#ifdef HAVE_MIST + ACTION_OK_DL_CORE_INFORMATION_STEAM_LIST, +#endif ACTION_OK_DL_INPUT_HOTKEY_BINDS_LIST, ACTION_OK_DL_RECORDING_SETTINGS_LIST, ACTION_OK_DL_PLAYLIST_SETTINGS_LIST, @@ -151,6 +154,9 @@ enum ACTION_OK_DL_CURSOR_MANAGER_LIST, ACTION_OK_DL_CORE_UPDATER_LIST, ACTION_OK_DL_CORE_MANAGER_LIST, +#ifdef HAVE_MIST + ACTION_OK_DL_CORE_MANAGER_STEAM_LIST, +#endif ACTION_OK_DL_THUMBNAILS_UPDATER_LIST, ACTION_OK_DL_PL_THUMBNAILS_UPDATER_LIST, ACTION_OK_DL_BROWSE_URL_LIST, diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 0b2e121d12..b44a7141bf 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -123,6 +123,10 @@ #include "../misc/cpufreq/cpufreq.h" #include "../input/input_remapping.h" +#ifdef HAVE_MIST +#include "../steam/steam.h" +#endif + /* Spacers used for ' - ' labels * in playlists */ #define PL_LABEL_SPACER_DEFAULT " | " @@ -985,6 +989,91 @@ static unsigned menu_displaylist_parse_core_manager_list( return count; } +#ifdef HAVE_MIST +static unsigned menu_displaylist_parse_core_manager_steam_list( + menu_displaylist_info_t *info, + settings_t *settings) +{ + MistResult result; + steam_core_dlc_list_t *dlc_list; + steam_core_dlc_t *dlc_info; + size_t i; + unsigned count = 0; + + result = steam_get_core_dlcs(&dlc_list, false); + if (MIST_IS_ERROR(result)) goto error; + + for (i = 0; i < dlc_list->count; i++) + { + dlc_info = steam_core_dlc_list_get(dlc_list, i); + + if (menu_entries_append_enum(info->list, + dlc_info->name, + "", + MENU_ENUM_LABEL_CORE_MANAGER_STEAM_ENTRY, + MENU_SETTING_ACTION_CORE_MANAGER_STEAM_OPTIONS, + 0, 0)) + count++; + } + + return count; + +error: + /* TODO: Send error notification */ + RARCH_ERR("[Steam] Error enumerating core dlcs for core manager (%d-%d)\n", MIST_UNPACK_RESULT(result)); + return count; +} + +static unsigned menu_displaylist_parse_core_information_steam( + menu_displaylist_info_t *info, + settings_t *settings) +{ + unsigned count = 0; + MistResult result; + steam_core_dlc_list_t *dlc_list; + steam_core_dlc_t *core_dlc = NULL; + bool installed = false; + + result = steam_get_core_dlcs(&dlc_list, false); + if (MIST_IS_ERROR(result)) goto error; + + /* Get the core dlc information */ + core_dlc = steam_get_core_dlc_by_name(dlc_list, info->path); + if (core_dlc == NULL) return count; + + /* Check if installed */ + result = mist_steam_apps_is_dlc_installed(core_dlc->app_id, &installed); + if (MIST_IS_ERROR(result)) goto error; + + if (installed) + { + if (menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_STEAM_UNINSTALL), + core_dlc->name, + MENU_ENUM_LABEL_CORE_STEAM_UNINSTALL, + MENU_SETTING_ACTION_CORE_STEAM_UNINSTALL, + 0, 0)) + count++; + } + else + { + if (menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_STEAM_INSTALL), + core_dlc->name, + MENU_ENUM_LABEL_CORE_STEAM_INSTALL, + MENU_SETTING_ACTION_CORE_STEAM_INSTALL, + 0, 0)) + count++; + } + + return count; +error: + /* TODO: Send error notification */ + RARCH_ERR("[Steam] Error getting core information (%d-%d)\n", MIST_UNPACK_RESULT(result)); + return count; +} +#endif + static unsigned menu_displaylist_parse_core_option_dropdown_list( menu_displaylist_info_t *info) { @@ -8328,9 +8417,14 @@ unsigned menu_displaylist_build_list( #ifdef HAVE_LAKKA {MENU_ENUM_LABEL_MENU_SHOW_EJECT_DISC, PARSE_ONLY_BOOL, true }, #endif +#ifdef HAVE_ONLINE_UPDATER {MENU_ENUM_LABEL_MENU_SHOW_ONLINE_UPDATER, PARSE_ONLY_BOOL, true }, {MENU_ENUM_LABEL_MENU_SHOW_CORE_UPDATER, PARSE_ONLY_BOOL, true }, {MENU_ENUM_LABEL_MENU_SHOW_LEGACY_THUMBNAIL_UPDATER, PARSE_ONLY_BOOL, true }, +#endif +#ifdef HAVE_MIST + {MENU_ENUM_LABEL_MENU_SHOW_CORE_MANAGER_STEAM, PARSE_ONLY_BOOL, true }, +#endif {MENU_ENUM_LABEL_MENU_SHOW_INFORMATION, PARSE_ONLY_BOOL, true }, {MENU_ENUM_LABEL_MENU_SHOW_CONFIGURATIONS, PARSE_ONLY_BOOL, true }, {MENU_ENUM_LABEL_MENU_SHOW_HELP, PARSE_ONLY_BOOL, true }, @@ -11778,6 +11872,42 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, info->need_push = true; } break; +#ifdef HAVE_MIST + case DISPLAYLIST_CORE_MANAGER_STEAM_LIST: + menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); + count = menu_displaylist_parse_core_manager_steam_list(info, settings); + info->need_navigation_clear = true; + info->need_refresh = false; + info->need_push = true; + + /* No core dlcs were found */ + if (count == 0) + if (menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY), + msg_hash_to_str(MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY), + MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY, + FILE_TYPE_NONE, 0, 0)) + count++; + + break; + case DISPLAYLIST_CORE_INFORMATION_STEAM_LIST: + menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); + + info->need_navigation_clear = true; + info->need_refresh = false; + info->need_push = true; + count = menu_displaylist_parse_core_information_steam(info, settings); + + if (count == 0) + if (menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY), + msg_hash_to_str(MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY), + MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY, + FILE_TYPE_NONE, 0, 0)) + count++; + + break; +#endif case DISPLAYLIST_CONTENTLESS_CORES: { size_t contentless_core_ptr = @@ -12362,7 +12492,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, #endif #endif -#ifdef HAVE_COMPRESSION +#if defined(HAVE_COMPRESSION) && !defined(HAVE_MIST) if (menu_entries_append_enum(info->list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_SYSTEM_FILES), msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOAD_CORE_SYSTEM_FILES), @@ -12716,6 +12846,13 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, MENU_ENUM_LABEL_ONLINE_UPDATER, PARSE_ACTION, false) == 0) count++; +#endif +#ifdef HAVE_MIST + if (settings->bools.menu_show_core_manager_steam) + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, + MENU_ENUM_LABEL_CORE_MANAGER_STEAM_LIST, + PARSE_ACTION, false) == 0) + count++; #endif if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, MENU_ENUM_LABEL_SETTINGS, PARSE_ACTION, false) == 0) diff --git a/menu/menu_displaylist.h b/menu/menu_displaylist.h index e9f2e49961..4e036271b4 100644 --- a/menu/menu_displaylist.h +++ b/menu/menu_displaylist.h @@ -103,6 +103,10 @@ enum menu_displaylist_ctl_state DISPLAYLIST_CORES_COLLECTION_SUPPORTED, DISPLAYLIST_CORES_UPDATER, DISPLAYLIST_CORE_MANAGER_LIST, +#ifdef HAVE_MIST + DISPLAYLIST_CORE_MANAGER_STEAM_LIST, + DISPLAYLIST_CORE_INFORMATION_STEAM_LIST, +#endif DISPLAYLIST_THUMBNAILS_UPDATER, DISPLAYLIST_PL_THUMBNAILS_UPDATER, DISPLAYLIST_LAKKA, diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 758aba22bf..58e7a72660 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -131,6 +131,11 @@ enum menu_settings_type MENU_SETTING_ACTION_CORE_INPUT_REMAPPING_OPTIONS, MENU_SETTING_ACTION_CORE_CHEAT_OPTIONS, MENU_SETTING_ACTION_CORE_MANAGER_OPTIONS, +#ifdef HAVE_MIST + MENU_SETTING_ACTION_CORE_MANAGER_STEAM_OPTIONS, + MENU_SETTING_ACTION_CORE_STEAM_INSTALL, + MENU_SETTING_ACTION_CORE_STEAM_UNINSTALL, +#endif MENU_SETTING_ACTION_CORE_DISK_OPTIONS, MENU_SETTING_ACTION_CORE_SHADER_OPTIONS, MENU_SETTING_ACTION_SAVESTATE, diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 043441a9e1..8e81f0d1af 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -9202,6 +9202,16 @@ static bool setting_append_list( parent_group); #endif +#ifdef HAVE_MIST + CONFIG_ACTION( + list, list_info, + MENU_ENUM_LABEL_CORE_MANAGER_STEAM_LIST, + MENU_ENUM_LABEL_VALUE_CORE_MANAGER_STEAM_LIST, + &group_info, + &subgroup_info, + parent_group); +#endif + CONFIG_ACTION( list, list_info, MENU_ENUM_LABEL_SETTINGS, @@ -17868,6 +17878,23 @@ static bool setting_append_list( SD_FLAG_NONE); #endif +#ifdef HAVE_MIST + CONFIG_BOOL( + list, list_info, + &settings->bools.menu_show_core_manager_steam, + MENU_ENUM_LABEL_MENU_SHOW_CORE_MANAGER_STEAM, + MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_MANAGER_STEAM, + menu_show_core_manager_steam, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE); +#endif + CONFIG_BOOL( list, list_info, &settings->bools.settings_show_drivers, diff --git a/msg_hash.h b/msg_hash.h index 60323efd1e..18bdafb36f 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -746,6 +746,9 @@ enum msg_hash_enums MENU_ENUM_LABEL_SYSTEM_INFO_CONTROLLER_ENTRY, MENU_ENUM_LABEL_CORE_INFO_ENTRY, MENU_ENUM_LABEL_CORE_MANAGER_ENTRY, +#ifdef HAVE_MIST + MENU_ENUM_LABEL_CORE_MANAGER_STEAM_ENTRY, +#endif MENU_ENUM_LABEL_PLAYLIST_ENTRY, MENU_LABEL(START_VIDEO_PROCESSOR), @@ -1573,6 +1576,9 @@ enum msg_hash_enums MENU_ENUM_LABEL_DEFERRED_CORE_LIST, MENU_ENUM_LABEL_DEFERRED_CORE_UPDATER_LIST, MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_LIST, +#ifdef HAVE_MIST + MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_STEAM_LIST, +#endif MENU_ENUM_LABEL_DEFERRED_THUMBNAILS_UPDATER_LIST, MENU_ENUM_LABEL_DEFERRED_PL_THUMBNAILS_UPDATER_LIST, MENU_ENUM_LABEL_DEFERRED_RECORDING_SETTINGS_LIST, @@ -1640,6 +1646,9 @@ enum msg_hash_enums MENU_ENUM_LABEL_DEFERRED_AUDIO_MIXER_SETTINGS_LIST, MENU_ENUM_LABEL_DEFERRED_CORE_SETTINGS_LIST, MENU_ENUM_LABEL_DEFERRED_CORE_INFORMATION_LIST, +#ifdef HAVE_MIST + MENU_ENUM_LABEL_DEFERRED_CORE_INFORMATION_STEAM_LIST, +#endif MENU_ENUM_LABEL_DEFERRED_CORE_RESTORE_BACKUP_LIST, MENU_ENUM_LABEL_DEFERRED_CORE_DELETE_BACKUP_LIST, MENU_ENUM_LABEL_DEFERRED_CORE_OPTION_OVERRIDE_LIST, @@ -2251,6 +2260,15 @@ enum msg_hash_enums MENU_LABEL(START_CORE), MENU_LABEL(CORE_UPDATER_LIST), MENU_LABEL(CORE_MANAGER_LIST), +#ifdef HAVE_MIST + MENU_LABEL(CORE_MANAGER_STEAM_LIST), + MENU_LABEL(CORE_STEAM_INSTALL), + MENU_LABEL(CORE_STEAM_UNINSTALL), + MENU_LABEL(MENU_SHOW_CORE_MANAGER_STEAM), + MSG_CORE_STEAM_INSTALLING, + MSG_CORE_STEAM_UNINSTALLED, + MSG_CORE_STEAM_CURRENTLY_DOWNLOADING, +#endif MENU_LABEL(CORE_UPDATER_AUTO_EXTRACT_ARCHIVE), MENU_LABEL(CORE_UPDATER_SHOW_EXPERIMENTAL_CORES), MENU_LABEL(CORE_UPDATER_AUTO_BACKUP), diff --git a/qb/config.libs.sh b/qb/config.libs.sh index c418034ca0..19cd2a66e2 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -595,7 +595,25 @@ if [ "$HAVE_STEAM" = 'yes' ]; then add_opt UPDATE_CORES no die : 'Notice: Steam build enabled, disabling:' die : '* Core info cache.' + die : '* Core updater.' die : '* Online updater.' + + # Keep base directory relative to installation on Linux just like it is on Windows + if [ "$OS" = "Linux" ]; then + add_define MAKEFILE UNIX_CWD_ENV 1 + fi +fi + +if [ "$HAVE_MIST" = 'yes' ]; then + if [ "$HAVE_STEAM" != 'yes' ]; then + die 1 'Error: mist builds requires steam to be enabled' + fi + + if [ ! -d "$MIST_PATH" ]; then + die 1 'Error: MIST_PATH must be pointing to the location of mist artifacts' + fi + + add_define MAKEFILE MIST_PATH "$MIST_PATH" fi check_enabled CXX SLANG slang 'The C++ compiler is' false diff --git a/qb/config.params.sh b/qb/config.params.sh index 8616ceb844..6eb7901d50 100644 --- a/qb/config.params.sh +++ b/qb/config.params.sh @@ -189,6 +189,7 @@ HAVE_METAL=no # Metal support (macOS-only) C89_METAL=no HAVE_NETWORK_VIDEO=no HAVE_STEAM=no # Enable Steam build +HAVE_MIST=no # Enable Steam build w/ mist HAVE_ODROIDGO2=no # ODROID-GO Advance rotation support (requires librga) HAVE_LIBSHAKE=no # libShake haptic feedback support HAVE_CHECK=no # check support for unit tests diff --git a/retroarch.c b/retroarch.c index 7765466ae1..29ad5d3114 100644 --- a/retroarch.c +++ b/retroarch.c @@ -106,6 +106,10 @@ #include "network/discord.h" #endif +#ifdef HAVE_MIST +#include "steam/steam.h" +#endif + #include "config.def.h" #include "runloop.h" @@ -3740,6 +3744,10 @@ void main_exit(void *args) play_feature_delivery_deinit(); #endif +#if defined(HAVE_MIST) + steam_deinit(); +#endif + #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) CoUninitialize(); #endif @@ -3788,6 +3796,10 @@ int rarch_main(int argc, char *argv[], void *data) play_feature_delivery_init(); #endif +#if defined(HAVE_MIST) + steam_init(); +#endif + libretro_free_system_info(&runloop_st->system.info); command_event(CMD_EVENT_HISTORY_DEINIT, NULL); rarch_favorites_deinit(); @@ -3850,6 +3862,10 @@ int rarch_main(int argc, char *argv[], void *data) task_queue_check(); +#ifdef HAVE_MIST + steam_poll(); +#endif + #ifdef HAVE_QT app_exit = ui_companion_qt.application->exiting; #endif diff --git a/steam/steam.c b/steam/steam.c new file mode 100644 index 0000000000..64112b0edf --- /dev/null +++ b/steam/steam.c @@ -0,0 +1,325 @@ +#include +#include +#include +#include + +#include "../menu/menu_entries.h" +#include "../retroarch.h" +#include "../runloop.h" +#include "verbosity.h" + +#include "steam.h" + +static bool mist_initialized = false; +static steam_core_dlc_list_t *mist_dlc_list = NULL; + +void str_to_lower(char *str) +{ + for (size_t i = 0; str[i] != '\0'; i++) + { + str[i] = tolower(str[i]); + } +} + +void steam_init(void) +{ + MistResult result; + + result = mist_subprocess_init(); + + if (MIST_IS_SUCCESS(result)) + mist_initialized = true; + else + RARCH_ERR("[Steam]: Failed to initialize mist subprocess (%d-%d)\n", MIST_UNPACK_RESULT(result)); +} + +void steam_poll(void) +{ + MistResult result; + MistCallbackMsg callback; + steam_core_dlc_list_t *core_dlc_list; + bool has_callback = false; + static bool has_poll_errored = false; + + result = mist_poll(); + if (MIST_IS_ERROR(result)) + { + if(has_poll_errored) return; + + RARCH_ERR("[Steam]: Error polling (%d-%d)\n", MIST_UNPACK_RESULT(result)); + + has_poll_errored = true; + } + + result = mist_next_callback(&has_callback, &callback); + if(MIST_IS_ERROR(result)) return; + + while (has_callback && MIST_IS_SUCCESS(result)) + { + switch (callback.callback) + { + /* Reload core info and Steam Core DLC mappings */ + case MistCallback_DlcInstalled: + steam_get_core_dlcs(&core_dlc_list, true); + command_event(CMD_EVENT_CORE_INFO_INIT, NULL); + break; + } + + result = mist_next_callback(&has_callback, &callback); + } +} + +steam_core_dlc_list_t *steam_core_dlc_list_new(size_t count) +{ + steam_core_dlc_list_t *core_dlc_list = (steam_core_dlc_list_t*) + malloc(sizeof(*core_dlc_list)); + + core_dlc_list->list = (steam_core_dlc_t*) + malloc(count * sizeof(*core_dlc_list->list)); + + core_dlc_list->count = 0; /* This is incremented inside the setup function */ + + return core_dlc_list; +} + +void steam_core_dlc_list_free(steam_core_dlc_list_t *list) +{ + if (list == NULL) return; + + for (size_t i = 0; list->count > i; i++) + { + if (list->list[i].name != NULL) + free(list->list[i].name); + if (list->list[i].name_lower != NULL) + free(list->list[i].name_lower); + } + + free(list->list); + free(list); +} + +steam_core_dlc_t *steam_core_dlc_list_get(steam_core_dlc_list_t *list, size_t i) +{ + if (!list || (i >= list->count)) + return NULL; + + return &list->list[i]; +} + +/* Sort the dlc cores alphabetically based on their name */ +static int dlc_core_qsort_cmp(const void *a_, const void *b_) +{ + const steam_core_dlc_t *a = (const steam_core_dlc_t*)a_; + const steam_core_dlc_t *b = (const steam_core_dlc_t*)b_; + + return strcasecmp(a->name, b->name); +} + +/* Find core info for dlcs + * TODO: This currently only uses core info for cores that are installed */ +core_info_t* steam_find_core_info_for_dlc(const char* name) +{ + size_t name_len = strlen(name); + + core_info_list_t *core_info_list = NULL; + core_info_get_list(&core_info_list); + + if (core_info_list == NULL) return NULL; + + for (int i = 0; core_info_list->count > i; i++) + { + core_info_t *core_info = core_info_get(core_info_list, i); + + char core_info_name[256] = {0}; + + /* Find the opening parenthesis for the core name */ + char *start = strchr(core_info->display_name, '('); + if (start == NULL) continue; + + /* Skip the first parenthesis and copy it to the stack */ + strncpy(core_info_name, start + 1, sizeof(core_info_name) - 1); + + /* Null terminate at the closing parenthesis. */ + char *end = strchr((const char*)&core_info_name, ')'); + if (end == NULL) continue; + else *end = '\0'; + + /* Make it lowercase */ + str_to_lower((char*)&core_info_name); + + /* Check if it matches */ + if (strcasecmp(core_info_name, name) == 0) + return core_info; + } + + return NULL; +} + +/* Generate a list with core dlcs + * Needs to be called after initializion because it uses core info */ +MistResult steam_generate_core_dlcs_list(steam_core_dlc_list_t **list) +{ + MistResult result; + int count; + steam_core_dlc_list_t *dlc_list = NULL; + MistDlcData dlc_data; + + result = mist_steam_apps_get_dlc_count(&count); + if (MIST_IS_ERROR(result)) goto error; + + dlc_list = steam_core_dlc_list_new(count); + for (int i = 0; count > i; i++) + { + steam_core_dlc_t core_dlc; + + result = mist_steam_apps_get_dlc_data_by_index(i, &dlc_data); + if (MIST_IS_ERROR(result)) goto error; + + core_dlc.app_id = dlc_data.app_id; + + /* Strip away the "RetroArch - " prefix if present */ + if (strncmp(dlc_data.name, "RetroArch - ", sizeof("RetroArch - ") - 1) == 0) + core_dlc.name = strdup(dlc_data.name + sizeof("RetroArch - ") - 1); + else + core_dlc.name = strdup(dlc_data.name); + + /* Make a lower case version */ + core_dlc.name_lower = strdup(core_dlc.name); + str_to_lower(core_dlc.name_lower); + + core_dlc.core_info = steam_find_core_info_for_dlc(core_dlc.name_lower); + + dlc_list->list[i] = core_dlc; + dlc_list->count++; + } + + /* Sort the list */ + qsort(dlc_list->list, dlc_list->count, + sizeof(steam_core_dlc_t), dlc_core_qsort_cmp); + + *list = dlc_list; + return MistResult_Success; + +error: + if (dlc_list != NULL) steam_core_dlc_list_free(dlc_list); + + return result; +} + +MistResult steam_get_core_dlcs(steam_core_dlc_list_t **list, bool cached) { + MistResult result; + steam_core_dlc_list_t *new_list = NULL; + + if (cached && mist_dlc_list != NULL) + { + *list = mist_dlc_list; + return MistResult_Success; + } + + result = steam_generate_core_dlcs_list(&new_list); + if (MIST_IS_ERROR(result)) return result; + + if (mist_dlc_list != NULL) steam_core_dlc_list_free(mist_dlc_list); + + mist_dlc_list = new_list; + *list = new_list; + + return MistResult_Success; +} + +steam_core_dlc_t* steam_get_core_dlc_by_name(steam_core_dlc_list_t *list, const char *name) { + steam_core_dlc_t *core_info; + + for (int i = 0; list->count > i; i++) + { + core_info = steam_core_dlc_list_get(list, i); + if (strcasecmp(core_info->name, name) == 0) return core_info; + } + + return NULL; +} + +void steam_install_core_dlc(steam_core_dlc_t *core_dlc) +{ + MistResult result; + char msg[PATH_MAX_LENGTH] = { 0 }; + + bool downloading = false; + bool installed = false; + uint64_t bytes_downloaded = 0; + uint64_t bytes_total = 0; + + /* Check if the core is already being downloaded */ + result = mist_steam_apps_get_dlc_download_progress(core_dlc->app_id, &downloading, &bytes_downloaded, &bytes_total); + if (MIST_IS_ERROR(result)) goto error; + + /* Check if the core is already installed */ + result = mist_steam_apps_is_dlc_installed(core_dlc->app_id, &installed); + if (MIST_IS_ERROR(result)) goto error; + + if (downloading || installed) + { + runloop_msg_queue_push(msg_hash_to_str(MSG_CORE_STEAM_CURRENTLY_DOWNLOADING), 1, 180, true, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR); + + return; + } + + result = mist_steam_apps_install_dlc(core_dlc->app_id); + if (MIST_IS_ERROR(result)) goto error; + + task_push_steam_core_dlc_install(core_dlc->app_id, core_dlc->name); + + return; +error: + snprintf(msg, sizeof(msg), "%s: (%d-%d)", + msg_hash_to_str(MSG_ERROR), + MIST_UNPACK_RESULT(result)); + + runloop_msg_queue_push(msg, 1, 180, true, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR); + + RARCH_ERR("[Steam]: Error installing DLC %d (%d-%d)\n", core_dlc->app_id, MIST_UNPACK_RESULT(result)); + return; +} + +void steam_uninstall_core_dlc(steam_core_dlc_t *core_dlc) +{ + char msg[PATH_MAX_LENGTH] = { 0 }; + + MistResult result = mist_steam_apps_uninstall_dlc(core_dlc->app_id); + + if (MIST_IS_ERROR(result)) goto error; + + runloop_msg_queue_push(msg_hash_to_str(MSG_CORE_STEAM_UNINSTALLED), 1, 180, true, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + + bool refresh = false; + + return; +error: + snprintf(msg, sizeof(msg), "%s: (%d-%d)", + msg_hash_to_str(MSG_ERROR), + MIST_UNPACK_RESULT(result)); + + runloop_msg_queue_push(msg, 1, 180, true, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR); + + RARCH_ERR("[Steam]: Error uninstalling DLC %d (%d-%d)\n", core_dlc->app_id, MIST_UNPACK_RESULT(result)); + return; +} + +void steam_deinit(void) +{ + MistResult result; + + result = mist_subprocess_deinit(); + + /* Free the cached dlc list */ + if (mist_dlc_list != NULL) steam_core_dlc_list_free(mist_dlc_list); + + if (MIST_IS_SUCCESS(result)) + mist_initialized = false; + else + RARCH_ERR("[Steam]: Failed to deinitialize mist subprocess (%d-%d)\n", MIST_UNPACK_RESULT(result)); +} diff --git a/steam/steam.h b/steam/steam.h new file mode 100644 index 0000000000..316dd0ad1c --- /dev/null +++ b/steam/steam.h @@ -0,0 +1,43 @@ +#ifndef __RARCH_STEAM_H +#define __RARCH_STEAM_H + +#include + +#include "core_info.h" + +#define MIST_UNPACK_RESULT(result) MIST_RESULT_CODE(result), MIST_ERROR(result) + +struct steam_core_dlc { + AppId app_id; + char* name; + char* name_lower; + core_info_t* core_info; /* NOTE: This will be NULL if no core info was found for the name */ +}; + +typedef struct steam_core_dlc steam_core_dlc_t; + +typedef struct +{ + steam_core_dlc_t *list; + size_t count; +} steam_core_dlc_list_t; + +void steam_init(void); + +void steam_deinit(void); + +void steam_poll(void); + +MistResult steam_generate_core_dlcs_list(steam_core_dlc_list_t **list); +MistResult steam_get_core_dlcs(steam_core_dlc_list_t **list, bool cached); +steam_core_dlc_t *steam_core_dlc_list_get(steam_core_dlc_list_t *list, size_t i); +steam_core_dlc_t* steam_get_core_dlc_by_name(steam_core_dlc_list_t *list, const char *name); +void steam_core_dlc_list_free(steam_core_dlc_list_t *list); /* NOTE: This should not be called manually with lists from steam_get_core_dlcs */ + +void steam_install_core_dlc(steam_core_dlc_t *core_dlc); +void steam_uninstall_core_dlc(steam_core_dlc_t *core_dlc); + +/* Located in tasks/task_steam.c */ +void task_push_steam_core_dlc_install(AppId app_id, const char *name); + +#endif /* __RARCH_STEAM_H */ diff --git a/tasks/task_steam.c b/tasks/task_steam.c new file mode 100644 index 0000000000..8e1480ea33 --- /dev/null +++ b/tasks/task_steam.c @@ -0,0 +1,108 @@ +#include + +#include "tasks_internal.h" +#include "../menu/menu_entries.h" +#include "../runloop.h" +#include "../steam/steam.h" + +typedef struct steam_core_dlc_install_state { + AppId app_id; + char *name; + bool has_downloaded; +} steam_core_dlc_install_state_t; + +static void task_steam_core_dlc_install_handler(retro_task_t *task) +{ + char msg[PATH_MAX_LENGTH] = { 0 }; + steam_core_dlc_install_state_t *state = NULL; + MistResult result = MistResult_Success; + bool downloading = false; + uint64_t bytes_downloaded = 0; + uint64_t bytes_total = 0; + int8_t progress; + + if (!task) + goto task_finished; + + state = (steam_core_dlc_install_state_t*)task->state; + + if (!state) + goto task_finished; + + if (task_get_cancelled(task)) + goto task_finished; + + result = mist_steam_apps_get_dlc_download_progress(state->app_id, &downloading, &bytes_downloaded, &bytes_total); + if(MIST_IS_ERROR(result)) goto task_finished; + if(!downloading) + { + if(state->has_downloaded) goto task_finished; + } + else + state->has_downloaded = true; + + // Min bytes total to avoid division by zero at start + if(bytes_total < 1) bytes_total = 1; + + progress = (int8_t)((bytes_downloaded * 100) / bytes_total); + if(progress < 0) progress = 0; + if(progress > 100) progress = 100; + + task_set_progress(task, progress); + + return; +task_finished: + if (task) task_set_finished(task, true); + + /* If finished successfully */ + if(MIST_IS_SUCCESS(result)) + { + /* Invalidate the core dlc cache */ + steam_core_dlc_list_t *list; + steam_get_core_dlcs(&list, false); + + strlcpy(msg, msg_hash_to_str(MSG_CORE_INSTALLED), + sizeof(msg)); + strlcat(msg, state->name, + sizeof(msg)); + + runloop_msg_queue_push(msg, 1, 180, true, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR); + } + + /* Cleanup */ + if (state) + { + free(state->name); + free(state); + } +} + +void task_push_steam_core_dlc_install( + AppId app_id, + const char *name) +{ + char task_title[PATH_MAX_LENGTH]; + + retro_task_t *task = task_init(); + steam_core_dlc_install_state_t* state = (steam_core_dlc_install_state_t*)calloc(1, + sizeof(steam_core_dlc_install_state_t)); + + state->app_id = app_id; + state->name = strdup(name); + state->has_downloaded = false; + + strlcpy(task_title, msg_hash_to_str(MSG_CORE_STEAM_INSTALLING), + sizeof(task_title)); + strlcat(task_title, name, + sizeof(task_title)); + + task->handler = task_steam_core_dlc_install_handler; + task->state = state; + task->mute = false; + task->title = strdup(task_title); + task->progress = 0; + task->callback = NULL; + + task_queue_push(task); +}