Skip to content

Commit

Permalink
Mod download UI integration (#761)
Browse files Browse the repository at this point in the history
UI integration for the mod downloading feature. Feature activation locked behind a convar.
  • Loading branch information
Alystrasz authored Dec 14, 2023
1 parent 6d678ac commit e49e7e8
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 10 deletions.
19 changes: 19 additions & 0 deletions .github/nativefuncs.json
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,25 @@
"returnTypeString":"array<string>",
"argTypes":"string modName"
},
{
"name": "NSIsModDownloadable",
"helpText": "checks whether a mod is verified and can be auto-downloaded",
"returnTypeString": "bool",
"argTypes": "string name, string version"

},
{
"name": "NSDownloadMod",
"helpText": "downloads a given mod from distant API to local game profile",
"returnTypeString": "void",
"argTypes": "string name, string version"
},
{
"name": "NSGetModInstallState",
"helpText": "get status of the mod currently being installed",
"returnTypeString": "ModInstallState",
"argTypes": ""
},
{
"name":"NSReloadMods",
"helpText":"",
Expand Down
8 changes: 8 additions & 0 deletions Northstar.Client/mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
"LoadPriority": 0,
"InitScript": "cl_northstar_client_init.nut",
"ConVars": [
{
"Name": "allow_mod_auto_download",
"DefaultValue": "0"
},
{
"Name": "filter_hide_empty",
"DefaultValue": "0"
Expand Down Expand Up @@ -82,6 +86,10 @@
"After": "NSUpdateGameStateClientStart"
}
},
{
"Path": "ui/menu_ns_moddownload.nut",
"RunOn": "UI"
},
{
"Path": "ui/menu_ns_serverbrowser.nut",
"RunOn": "UI",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,5 +366,25 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a
"PROGRESSION_DISABLED_BODY" "^CCCC0000Progression has been disabled.^\n\nTitans, Weapons, Factions, Skins, etc. will all be unlocked and usable at any time.\n\nThis can be changed at any time in the multiplayer lobby."

"PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Progression can now be enabled!^\n\nNorthstar now supports vanilla progression, meaning you can choose to unlock Weapons, Skins, Titans, etc. through levelling up and completing challenges.\n\nYou can enable progression using the button at the bottom of the lobby screen.\n\nThis can be changed at any time."

// Mod downloading
"MISSING_MOD" "Missing mod \"%s1\" v%s2"
"MOD_NOT_VERIFIED" "(mod is not verified, and couldn't be downloaded automatically)"
"MOD_DL_DISABLED" "(automatic mod downloading is disabled)"
"DOWNLOADING_MOD_TITLE" "Downloading mod"
"DOWNLOADING_MOD_TITLE_W_PROGRESS" "Downloading mod (%s1%)"
"DOWNLOADING_MOD_TEXT" "Downloading %s1 v%s2..."
"DOWNLOADING_MOD_TEXT_W_PROGRESS" "Downloading %s1 v%s2...\n(%s3/%s4 MB)"
"CHECKSUMING_TITLE" "Checksuming mod"
"CHECKSUMING_TEXT" "Verifying contents of %s1 v%s2..."
"EXTRACTING_MOD_TITLE" "Extracting mod (%s1%)"
"EXTRACTING_MOD_TEXT" "Extracting %s1 v%s2...\n(%s3/%s4 MB)"
"FAILED_DOWNLOADING" "Failed downloading mod"
"FAILED_READING_ARCHIVE" "An error occurred while reading mod archive."
"FAILED_WRITING_TO_DISK" "An error occurred while extracting mod files to the filesystem."
"MOD_FETCHING_FAILED" "Mod archive could not be downloaded from Thunderstore."
"MOD_CORRUPTED" "Downloaded archive checksum does not match verified signature."
"NO_DISK_SPACE_AVAILABLE" "There is not enough space on your disk."
"MOD_FETCHING_FAILED_GENERAL" "Mod extraction failed. Check logs for more details."
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,11 @@ global struct MasterServerAuthResult
string errorCode
string errorMessage
}

global struct ModInstallState
{
int status
int progress
int total
float ratio
}
117 changes: 117 additions & 0 deletions Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut
Original file line number Diff line number Diff line change
@@ -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 )
}
59 changes: 49 additions & 10 deletions Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut
Original file line number Diff line number Diff line change
Expand Up @@ -951,33 +951,65 @@ string function FillInServerModsLabel( array<RequiredModInfo> 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
{
Expand Down Expand Up @@ -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()
Expand Down

0 comments on commit e49e7e8

Please sign in to comment.