diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index 35fdda3cb..2e2973525 100644 --- a/.github/nativefuncs.json +++ b/.github/nativefuncs.json @@ -454,6 +454,13 @@ "returnTypeString":"array", "argTypes":"string modName" }, + { + "name": "NSFetchVerifiedModsManifesto", + "helpText": "Retrieves the verified mods list from the central authority (GitHub).", + "returnTypeString": "void", + "argTypes": "" + + }, { "name": "NSIsModDownloadable", "helpText": "checks whether a mod is verified and can be auto-downloaded", diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index 9ad2a89a1..fad230451 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -374,6 +374,8 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "WRONG_MOD_VERSION" "Server has mod \"%s1\" v%s2 while you have v%s3" "MOD_NOT_VERIFIED" "(mod is not verified, and couldn't be downloaded automatically)" "MOD_DL_DISABLED" "(automatic mod downloading is disabled)" + "MANIFESTO_FETCHING_TITLE" "Setting up mod download" + "MANIFESTO_FETCHING_TEXT" "Retrieving the list of verified mods..." "DOWNLOADING_MOD_TITLE" "Downloading mod" "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Downloading mod (%s1%)" "DOWNLOADING_MOD_TEXT" "Downloading %s1 v%s2..." 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 127d9dcbf..14092364e 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut @@ -1,9 +1,11 @@ global function DownloadMod global function DisplayModDownloadErrorDialog +global function FetchVerifiedModsManifesto global enum eModInstallStatus { IDLE, + MANIFESTO_FETCHING, DOWNLOADING, CHECKSUMING, EXTRACTING, @@ -19,6 +21,36 @@ global enum eModInstallStatus const int MB = 1024*1000; + +void function FetchVerifiedModsManifesto() +{ + print("Start fetching verified mods manifesto from the Internet") + + // Fetching UI + DialogData dialogData + dialogData.header = Localize( "#MANIFESTO_FETCHING_TITLE" ) + dialogData.message = Localize( "#MANIFESTO_FETCHING_TEXT" ) + dialogData.showSpinner = true; + + // Prevent user from closing dialog + dialogData.forceChoice = true; + OpenDialog( dialogData ) + + // Do the actual fetching + NSFetchVerifiedModsManifesto() + + ModInstallState state = NSGetModInstallState() + while ( state.status == eModInstallStatus.MANIFESTO_FETCHING ) + { + state = NSGetModInstallState() + WaitFrame() + } + + // Close dialog when manifesto has been received + CloseActiveMenu() +} + + bool function DownloadMod( string modname, string modversion ) { @@ -61,8 +93,11 @@ void function UpdateModDownloadDialog( string modname, string modversion, ModIns switch ( state.status ) { case eModInstallStatus.IDLE: - Hud_SetText( header, Localize( "#DOWNLOADING_MOD_TITLE_W_PROGRESS", "Requesting..." ) ) - Hud_SetText( body, Localize( "#DOWNLOADING_MOD_TEXT_W_PROGRESS", modname, modversion, 0, 0 ) ) + Hud_SetText( header, Localize( "#MANIFESTO_FETCHING_TITLE") ) + Hud_SetText( body, Localize( "#MANIFESTO_FETCHING_TEXT" ) ) + case eModInstallStatus.MANIFESTO_FETCHING: + Hud_SetText( header, Localize( "#MANIFESTO_FETCHING_TITLE" ) ) + Hud_SetText( body, Localize( "#MANIFESTO_FETCHING_TEXT" ) ) break case eModInstallStatus.DOWNLOADING: Hud_SetText( header, Localize( "#DOWNLOADING_MOD_TITLE_W_PROGRESS", string( state.ratio ) ) ) 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 515e84b17..0b15827f2 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -1012,58 +1012,103 @@ void function OnServerSelected_Threaded( var button ) bool autoDownloadAllowed = GetConVarBool( "allow_mod_auto_download" ) int downloadedMods = 0; + // Check out if there's any server-required mod that is not locally installed + array modNames = NSGetModNames() + bool uninstalledModFound = false + // check mods for ( int i = 0; i < NSGetServerRequiredModsCount( serverIndex ); i++ ) { - if ( !NSGetModNames().contains( NSGetServerRequiredModName( serverIndex, i ) ) ) + string modname = NSGetServerRequiredModName( serverIndex, i ) + string modversion = NSGetServerRequiredModVersion( serverIndex, i ) + if ( modname.len() > 10 && modname.slice(0, 10) == "Northstar." ) + continue + if ( !modNames.contains( modname ) ) { - // Check if mod can be auto-downloaded - string modname = NSGetServerRequiredModName( serverIndex, i ) - string modversion = NSGetServerRequiredModVersion( serverIndex, i ) - bool modIsVerified = NSIsModDownloadable( modname, modversion ) + print( format ( "\"%s\" was not found locally, triggering manifesto fetching.", modname ) ) + uninstalledModFound = true + break + } else if ( NSGetModVersionByModName( modname ) != modversion ) { + print( format ( "\"%s\" was found locally but has version \"%s\" while server requires \"%s\", triggering manifesto fetching.", requiredModInfo.name, NSGetModVersionByModName( requiredModInfo.name ), requiredModInfo.version ) ) + uninstalledModFound = true + break + } + } + if ( uninstalledModFound && autoDownloadAllowed ) + { + print("Auto-download is allowed, checking if missing mods can be installed automatically.") + FetchVerifiedModsManifesto() + } + + + for ( int i = 0; i < NSGetServerRequiredModsCount( serverIndex ); i++ ) + { + string modname = NSGetServerRequiredModName( serverIndex, i ) + string modversion = NSGetServerRequiredModVersion( serverIndex, i ) + // Tolerate core mods having different versions + if ( modname.len() > 10 && modname.slice(0, 10) == "Northstar." ) + continue - // Display an error message if not - if ( !modIsVerified || !autoDownloadAllowed ) + if ( !NSGetModNames().contains( modname ) || NSGetModVersionByModName( modname ) != modversion ) + { + // Auto-download mod + if ( autoDownloadAllowed ) { - DialogData dialogData - dialogData.header = "#ERROR" - dialogData.message = Localize( "#MISSING_MOD", modname, modversion ) - dialogData.image = $"ui/menu/common/dialog_error" + bool modIsVerified = NSIsModDownloadable( modname, modversion ) - // Specify error (only if autoDownloadAllowed is set) - if ( autoDownloadAllowed ) + // Display error message if mod is not verified + if ( !modIsVerified ) { + DialogData dialogData + dialogData.header = "#ERROR" + dialogData.message = Localize( "#MISSING_MOD", modname, modversion ) dialogData.message += "\n" + Localize( "#MOD_NOT_VERIFIED" ) + dialogData.image = $"ui/menu/common/dialog_error" + + AddDialogButton( dialogData, "#DISMISS" ) + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) + AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) + + OpenDialog( dialogData ) + return + } + else + { + if ( DownloadMod( mod, modversion ) ) + { + downloadedMods++ + } + else + { + DisplayModDownloadErrorDialog( modname ) + return + } } + } - AddDialogButton( dialogData, "#DISMISS" ) + // Mod not found, display error message + else + { + DialogData dialogData + dialogData.header = "#ERROR" + dialogData.message = Localize( "#MISSING_MOD", modname, modversion ) + dialogData.image = $"ui/menu/common/dialog_error" + AddDialogButton( dialogData, "#DISMISS" ) AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) OpenDialog( dialogData ) - return } - else // Launch download - { - if ( DownloadMod( modname, modversion ) ) - { - downloadedMods++ - } - else - { - DisplayModDownloadErrorDialog( modname ) - return - } - } + } else { // this uses semver https://semver.org - array serverModVersion = split( NSGetServerRequiredModVersion( serverIndex, i ), "." ) - array clientModVersion = split( NSGetModVersionByModName( NSGetServerRequiredModName( serverIndex, i ) ), "." ) + array serverModVersion = split( modname, "." ) + array clientModVersion = split( NSGetModVersionByModName( modname ), "." ) bool semverFail = false // if server has invalid semver don't bother checking