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 a4469bf94..fbd5a1b3d 100644 --- a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut +++ b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut @@ -47,6 +47,7 @@ global struct RequiredModInfo { string name string version + string downloadLink } global struct ServerInfo diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut index 4110f730d..a22b9faf8 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut @@ -1,6 +1,7 @@ global function DownloadMod global function DisplayModDownloadErrorDialog global function FetchVerifiedModsManifesto +global function IsModDownloadable global enum eModInstallStatus { @@ -19,6 +20,11 @@ global enum eModInstallStatus NOT_FOUND } +struct +{ + bool abortDownload = false +} file + const int MB = 1024 * 1000 void function FetchVerifiedModsManifesto() @@ -49,8 +55,61 @@ void function FetchVerifiedModsManifesto() CloseActiveMenu() } +void function ApproveDownload() +{ + file.abortDownload = false +} + +void function AbortDownload() +{ + file.abortDownload = true +} + bool function DownloadMod( RequiredModInfo mod ) { + // Prompt user to authorize downloading non-approved mods + if ( !NSIsModDownloadable( mod.name, mod.version ) && IsModDownloadable( mod ) ) + { + DialogData dialogData + dialogData.header = "Download mod?" + dialogData.image = $"rui/menu/common/unlock_random" + + string link = mod.downloadLink.len() > 0 ? mod.downloadLink : "https://example.org/" + string message = "This mod was not approved by the community, and thus might contain malicious content.\n\n" + message += format( "^FFFFFF00Mod:^0 %s v%s\n", mod.name, mod.version ) + message += "^FFFFFF00Download link:^0 ^5588FF00" + message += link + message += "^0\n\nDo you want to download this mod?" + dialogData.message = message + // dialogData.inputDisableTime = 5 + AddDialogButton( + dialogData, + "Manually check the mod", + void function() : ( dialogData, link ) + { + LaunchExternalWebBrowser( link, WEBBROWSER_FLAG_FORCEEXTERNAL ) + // Keep the dialog open + OpenDialog( dialogData ) + } + ) + AddDialogButton( dialogData, "#OK", ApproveDownload ) + AddDialogButton( dialogData, "#CANCEL", AbortDownload ) + dialogData.forceChoice = true + OpenDialog( dialogData ) + + // Wait for user selection + while ( IsDialogActive( dialogData ) ) + { + WaitFrame() + } + + if ( file.abortDownload ) + { + print( format( "User refused downloading unapproved mod \"%s\".", mod.name ) ) + return false + } + } + // Downloading mod UI DialogData dialogData dialogData.header = Localize( "#DOWNLOADING_MOD_TITLE" ) @@ -183,3 +242,14 @@ void function DisplayModDownloadErrorDialog( string modName ) OpenDialog( dialogData ) } + +/** + * Returns whether {mod} can be downloaded, using information from its manifesto. + * + * This is different from native {NSIsModDownloadable}, which returns whether a + * mod has been approved by the community (= appears in the verified mods list). +*/ +bool function IsModDownloadable( RequiredModInfo mod ) +{ + return mod.downloadLink.len() > 0 +} 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 b5176e98b..171be4299 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -1104,10 +1104,20 @@ string function FillInServerModsLabel( array mods ) { template = " %s v%s\n" } - // Display a green checkmark if it can be downloaded, a red cross if not + // Display a green checkmark if it can be downloaded... + else if ( NSIsModDownloadable( mod.name, mod.version ) ) + { + template = " %s v%s ^00ff0000(↓)^FFFFFFFF\n" + } + // A yellow checkmark if it features a download link... + else if ( IsModDownloadable( mod ) ) + { + template = " %s v%s ^ffff0000(↓)^FFFFFFFF\n" + } + // Or a red cross if not else { - template = NSIsModDownloadable( mod.name, mod.version ) ? " %s v%s ^00ff0000(↓)^FFFFFFFF\n" : " %s v%s ^ff000000(x)^FFFFFFFF\n" + template = " %s v%s ^ff000000(x)^FFFFFFFF\n" } ret += format( template, mod.name, mod.version ) @@ -1236,9 +1246,10 @@ void function OnServerSelected_Threaded( string password = "" ) if ( autoDownloadAllowed ) { bool modIsVerified = NSIsModDownloadable( mod.name, mod.version ) + bool modHasDownloadLink = IsModDownloadable( mod ) // Display error message if mod is not verified - if ( !modIsVerified ) + if ( !modIsVerified && !modHasDownloadLink ) { DialogData dialogData dialogData.header = "#ERROR"