From e49e7e8321269a3de19f07981c8974e87e9fd938 Mon Sep 17 00:00:00 2001 From: Rémy Raes Date: Thu, 14 Dec 2023 22:19:08 +0100 Subject: Mod download UI integration (#761) UI integration for the mod downloading feature. Feature activation locked behind a convar. --- .../scripts/vscripts/cl_northstar_client_init.nut | 8 ++ .../scripts/vscripts/ui/menu_ns_moddownload.nut | 117 +++++++++++++++++++++ .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 59 +++++++++-- 3 files changed, 174 insertions(+), 10 deletions(-) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut (limited to 'Northstar.Client/mod/scripts/vscripts') diff --git a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut index 765d29c3..3560fd56 100644 --- a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut +++ b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut @@ -53,3 +53,11 @@ global struct MasterServerAuthResult string errorCode string errorMessage } + +global struct ModInstallState +{ + int status + int progress + int total + float ratio +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut new file mode 100644 index 00000000..4d299362 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut @@ -0,0 +1,117 @@ +global function DownloadMod +global function DisplayModDownloadErrorDialog + +global enum eModInstallStatus +{ + DOWNLOADING, + CHECKSUMING, + EXTRACTING, + DONE, + FAILED, + FAILED_READING_ARCHIVE, + FAILED_WRITING_TO_DISK, + MOD_FETCHING_FAILED, + MOD_CORRUPTED, + NO_DISK_SPACE_AVAILABLE, + NOT_FOUND +} + +const int MB = 1024*1000; + +bool function DownloadMod( RequiredModInfo mod ) +{ + // Downloading mod UI + DialogData dialogData + dialogData.header = Localize( "#DOWNLOADING_MOD_TITLE" ) + dialogData.message = Localize( "#DOWNLOADING_MOD_TEXT", mod.name, mod.version ) + dialogData.showSpinner = true; + + // Prevent user from closing dialog + dialogData.forceChoice = true; + OpenDialog( dialogData ) + + // Save reference to UI elements, to update their content + var menu = GetMenu( "Dialog" ) + var header = Hud_GetChild( menu, "DialogHeader" ) + var body = GetSingleElementByClassname( menu, "DialogMessageClass" ) + + // Start actual mod downloading + NSDownloadMod( mod.name, mod.version ) + + ModInstallState state = NSGetModInstallState() + while ( state.status < eModInstallStatus.DONE ) + { + state = NSGetModInstallState() + UpdateModDownloadDialog( mod, state, menu, header, body ) + WaitFrame() + } + + printt( "Mod status:", state.status ) + + // Close loading dialog + CloseActiveMenu() + + return state.status == eModInstallStatus.DONE +} + +void function UpdateModDownloadDialog( RequiredModInfo mod, ModInstallState state, var menu, var header, var body ) +{ + switch ( state.status ) + { + case eModInstallStatus.DOWNLOADING: + Hud_SetText( header, Localize( "#DOWNLOADING_MOD_TITLE_W_PROGRESS", string( state.ratio ) ) ) + Hud_SetText( body, Localize( "#DOWNLOADING_MOD_TEXT_W_PROGRESS", mod.name, mod.version, floor( state.progress / MB ), floor( state.total / MB ) ) ) + break + case eModInstallStatus.CHECKSUMING: + Hud_SetText( header, Localize( "#CHECKSUMING_TITLE" ) ) + Hud_SetText( body, Localize( "#CHECKSUMING_TEXT", mod.name, mod.version ) ) + break + case eModInstallStatus.EXTRACTING: + Hud_SetText( header, Localize( "#EXTRACTING_MOD_TITLE", string( state.ratio ) ) ) + Hud_SetText( body, Localize( "#EXTRACTING_MOD_TEXT", mod.name, mod.version, floor( state.progress / MB ), floor( state.total / MB ) ) ) + break + default: + break + } +} + +void function DisplayModDownloadErrorDialog( string modName ) +{ + ModInstallState state = NSGetModInstallState() + + DialogData dialogData + dialogData.header = Localize( "#FAILED_DOWNLOADING", modName ) + dialogData.image = $"ui/menu/common/dialog_error" + + switch ( state.status ) + { + case eModInstallStatus.FAILED_READING_ARCHIVE: + dialogData.message = Localize( "#FAILED_READING_ARCHIVE" ) + break + case eModInstallStatus.FAILED_WRITING_TO_DISK: + dialogData.message = Localize( "#FAILED_WRITING_TO_DISK" ) + break + case eModInstallStatus.MOD_FETCHING_FAILED: + dialogData.message = Localize( "#MOD_FETCHING_FAILED" ) + break + case eModInstallStatus.MOD_CORRUPTED: + dialogData.message = Localize( "#MOD_CORRUPTED" ) + break + case eModInstallStatus.NO_DISK_SPACE_AVAILABLE: + dialogData.message = Localize( "#NO_DISK_SPACE_AVAILABLE" ) + break + case eModInstallStatus.NOT_FOUND: + dialogData.message = Localize( "#NOT_FOUND" ) + break + case eModInstallStatus.FAILED: + default: + dialogData.message = Localize( "#MOD_FETCHING_FAILED_GENERAL" ) + break + } + + AddDialogButton( dialogData, "#DISMISS" ) + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) + AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) + + OpenDialog( dialogData ) +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index efc8d66c..29c7621c 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -951,33 +951,65 @@ string function FillInServerModsLabel( array mods ) void function OnServerSelected( var button ) +{ + thread OnServerSelected_Threaded( button ) +} + +void function OnServerSelected_Threaded( var button ) { if ( NSIsRequestingServerList() || NSGetServerCount() == 0 || file.serverListRequestFailed ) return ServerInfo server = file.focusedServer - file.lastSelectedServer = server + // Count mods that have been successfully downloaded + bool autoDownloadAllowed = GetConVarBool( "allow_mod_auto_download" ) + int downloadedMods = 0; + foreach ( RequiredModInfo mod in server.requiredMods ) { if ( !NSGetModNames().contains( mod.name ) ) { - DialogData dialogData - dialogData.header = "#ERROR" - dialogData.message = format( "Missing mod \"%s\" v%s", mod.name, mod.version ) - dialogData.image = $"ui/menu/common/dialog_error" + // Check if mod can be auto-downloaded + bool modIsVerified = NSIsModDownloadable( mod.name, mod.version ) + + // Display an error message if not + if ( !modIsVerified || !autoDownloadAllowed ) + { + DialogData dialogData + dialogData.header = "#ERROR" + dialogData.message = Localize( "#MISSING_MOD", mod.name, mod.version ) + dialogData.image = $"ui/menu/common/dialog_error" + + // Specify error (only if autoDownloadAllowed is set) + if ( autoDownloadAllowed ) + { + dialogData.message += "\n" + Localize( "#MOD_NOT_VERIFIED" ) + } - #if PC_PROG AddDialogButton( dialogData, "#DISMISS" ) AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) - #endif // PC_PROG - AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) + AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) - OpenDialog( dialogData ) + OpenDialog( dialogData ) + + return + } - return + else // Launch download + { + if ( DownloadMod( mod ) ) + { + downloadedMods++ + } + else + { + DisplayModDownloadErrorDialog( mod.name ) + return + } + } } else { @@ -1018,6 +1050,13 @@ void function OnServerSelected( var button ) } } + // Make Northstar aware new mods have been added + if ( downloadedMods > 0 ) + { + print( "Some new mods have been downloaded or enabled, reloading mods." ) + NSReloadMods(); + } + if ( server.requiresPassword ) { OnCloseServerBrowserMenu() -- cgit v1.2.3