Index: src/qcommon/q_shared.h =================================================================== --- src/qcommon/q_shared.h (revision 938) +++ src/qcommon/q_shared.h (working copy) @@ -1318,4 +1318,13 @@ #define SAY_TEAM 1 #define SAY_TELL 2 +// flags for com_downloadPrompt +#define DLP_TYPE_MASK 0x0f +#define DLP_IGNORE 0x01 // don't download anything +#define DLP_CURL 0x02 // download via HTTP redirect +#define DLP_UDP 0x04 // download from server +#define DLP_SHOW 0x10 // prompt needs to be shown +#define DLP_PROMPTED 0x20 // prompt has been processed by client +#define DLP_STALE 0x40 // prompt is not being shown by UI VM + #endif // __Q_SHARED_H Index: src/ui/ui_main.c =================================================================== --- src/ui/ui_main.c (revision 938) +++ src/ui/ui_main.c (working copy) @@ -3963,6 +3963,12 @@ Controls_GetConfig(); } else if (Q_stricmp(name, "clearError") == 0) { trap_Cvar_Set("com_errorMessage", ""); + } else if (Q_stricmp(name, "downloadIgnore") == 0) { + trap_Cvar_Set("com_downloadPrompt", va("%d", DLP_IGNORE)); + } else if (Q_stricmp(name, "downloadCURL") == 0) { + trap_Cvar_Set("com_downloadPrompt", va("%d", DLP_CURL)); + } else if (Q_stricmp(name, "downloadUDP") == 0) { + trap_Cvar_Set("com_downloadPrompt", va("%d", DLP_UDP)); } else if (Q_stricmp(name, "loadGameInfo") == 0) { /* UI_ParseGameInfo("gameinfo.txt"); UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);*/ @@ -6045,7 +6051,15 @@ break; case CA_CONNECTED: { char downloadName[MAX_INFO_VALUE]; + int prompt = trap_Cvar_VariableValue( "com_downloadPrompt" ); + if( prompt & DLP_SHOW ) { + Com_Printf("Opening download prompt...\n"); + trap_Key_SetCatcher( KEYCATCH_UI ); + Menus_ActivateByName("download_popmenu"); + trap_Cvar_Set( "com_downloadPrompt", "0" ); + } + trap_Cvar_VariableStringBuffer( "cl_downloadName", downloadName, sizeof(downloadName) ); if (*downloadName) { UI_DisplayDownloadInfo( downloadName, centerPoint, yStart, scale ); @@ -6497,4 +6511,3 @@ } } } - Index: src/ui/ui_gameinfo.c =================================================================== --- src/ui/ui_gameinfo.c (revision 938) +++ src/ui/ui_gameinfo.c (working copy) @@ -329,5 +329,7 @@ Info_ValueForKey( info, "g_unlagged" ) ); trap_Cvar_Set( "ui_serverinfo_ff", Info_ValueForKey( info, "ff" ) ); + trap_Cvar_Set( "ui_serverinfo_allowdl", + Info_ValueForKey( info, "sv_allowdownload" ) ); } } Index: src/client/cl_main.c =================================================================== --- src/client/cl_main.c (revision 938) +++ src/client/cl_main.c (working copy) @@ -67,6 +67,7 @@ cvar_t *cl_motdString; cvar_t *cl_allowDownload; +cvar_t *com_downloadPrompt; cvar_t *cl_conXOffset; cvar_t *cl_inGameVideo; @@ -1330,6 +1331,8 @@ */ void CL_DownloadsComplete( void ) { + Com_Printf("Downloads complete\n"); + #if USE_CURL // if we downloaded with cURL if(clc.cURLUsed) { @@ -1438,9 +1441,83 @@ char *s; char *remoteName, *localName; qboolean useCURL = qfalse; + int prompt; // We are looking to start a download here if (*clc.downloadList) { + + // Prompt if we do not allow automatic downloads + prompt = com_downloadPrompt->integer; + if( !( prompt & DLP_TYPE_MASK ) && + !( cl_allowDownload->integer & DLF_ENABLE ) ) { + char files[ MAX_INFO_STRING ], *name, *head, *pure_msg, + *url_msg = ""; + int i = 0, others = 0, swap = 0, max_list = 12; + + // Set the download URL message + if( ( clc.sv_allowDownload & DLF_ENABLE ) && + !( clc.sv_allowDownload & DLF_NO_REDIRECT ) ) { + url_msg = va("The server redirects to the following URL:\n%s", + clc.sv_dlURL); + max_list -= 6; + } + + // Make a pretty version of the download list + name = clc.downloadList; + if( *name == '@' ) + name++; + do { + // Copy remote name + head = name; + while( *head && *head != '@' ) + head++; + swap = *head; + *head = 0; + if( i++ < max_list ) + Com_sprintf( files, sizeof( files ), "%s%s%s", + files, i > 1 ? ", " : "", name ); + else + others++; + *head = swap; + if( !swap ) + break; + + // Skip local name + head++; + while( *head && *head != '@' ) + head++; + name = head + 1; + } while( *head ); + if( others ) + Com_sprintf( files, sizeof( files ), + "%s (%d other file%s)\n", files, others, + others > 1 ? "s" : "" ); + + // Set the pure message + if( cl_connectedToPureServer ) + if( !( clc.sv_allowDownload & DLF_ENABLE ) || + ( ( clc.sv_allowDownload & DLF_NO_UDP ) && + ( clc.sv_allowDownload * DLF_NO_REDIRECT ) ) ) + pure_msg = "You are missing files required by the server. " + "The server does not allow downloading. " + "You must install these files manually:"; + else + pure_msg = "You are missing files required by the server. " + "You must download these files or disconnect:"; + else + pure_msg = "You are missing optional files provided by the " + "server. You do not need them to play but can " + "choose to download them anyway:"; + + Cvar_Set( "com_downloadPromptText", + va("%s\n\n%s\n%s", pure_msg, files, url_msg ) ); + Cvar_Set( "com_downloadPrompt", va("%d", DLP_SHOW ) ); + return; + } + if( !( prompt & DLP_PROMPTED ) ) + Cvar_Set( "com_downloadPrompt", va("%d", prompt | DLP_PROMPTED ) ); + prompt &= DLP_TYPE_MASK; + s = clc.downloadList; // format is: @@ -1461,8 +1538,12 @@ *s++ = 0; else s = localName + strlen(localName); // point at the nul byte + #if USE_CURL - if(!(cl_allowDownload->integer & DLF_NO_REDIRECT)) { + if( ( ( cl_allowDownload->integer & DLF_ENABLE ) && + !( cl_allowDownload->integer & DLF_NO_REDIRECT ) ) || + prompt == DLP_CURL ) { + Com_Printf("Trying CURL download: %s; %s\n", localName, remoteName); if(clc.sv_allowDownload & DLF_NO_REDIRECT) { Com_Printf("WARNING: server does not " "allow download redirection " @@ -1492,13 +1573,22 @@ } #endif /* USE_CURL */ if(!useCURL) { - if((cl_allowDownload->integer & DLF_NO_UDP)) { - Com_Error(ERR_DROP, "UDP Downloads are " - "disabled on your client. " - "(cl_allowDownload is %d)", + Com_Printf("Trying UDP download: %s; %s\n", localName, remoteName); + if( ( !( cl_allowDownload->integer & DLF_ENABLE ) || + ( cl_allowDownload->integer & DLF_NO_UDP ) ) && + prompt != DLP_UDP ) { + if( cl_connectedToPureServer ) { + Com_Error(ERR_DROP, "Automatic downloads are " + "disabled on your client (cl_allowDownload is %d). " + "You can enable automatic downloads in the Options " + "menu.", cl_allowDownload->integer); return; } + Com_Printf("WARNING: UDP downloads are disabled.\n"); + CL_DownloadsComplete(); + return; + } else { CL_BeginDownload( localName, remoteName ); } @@ -1523,34 +1613,15 @@ ================= */ void CL_InitDownloads(void) { - char missingfiles[1024]; - - if ( !(cl_allowDownload->integer & DLF_ENABLE) ) - { - // autodownload is disabled on the client - // but it's possible that some referenced files on the server are missing - if (FS_ComparePaks( missingfiles, sizeof( missingfiles ), qfalse ) ) - { - // NOTE TTimo I would rather have that printed as a modal message box - // but at this point while joining the game we don't know wether we will successfully join or not - Com_Printf( "\nWARNING: You are missing some files referenced by the server:\n%s" - "You might not be able to join the game\n" - "Go to the setting menu to turn on autodownload, or get the file elsewhere\n\n", missingfiles ); - } - } - else if ( FS_ComparePaks( clc.downloadList, sizeof( clc.downloadList ) , qtrue ) ) { - + if ( FS_ComparePaks( clc.downloadList, sizeof( clc.downloadList ) , qtrue ) ) { Com_Printf("Need paks: %s\n", clc.downloadList ); - + Cvar_Set( "com_downloadPrompt", "0" ); if ( *clc.downloadList ) { - // if autodownloading is not enabled on the server cls.state = CA_CONNECTED; CL_NextDownload(); return; } - } - CL_DownloadsComplete(); } @@ -2077,6 +2148,27 @@ return; } + // We may have a download prompt ready + if( ( com_downloadPrompt->integer & DLP_TYPE_MASK ) && + !( com_downloadPrompt->integer & DLP_PROMPTED ) ) { + Com_Printf( "Download prompt returned %d\n", + com_downloadPrompt->integer ); + CL_NextDownload( ); + } + + // If the UI VM does not support the download prompt, we need to catch + // the prompt here and replicate regular behavior. + // One frame will always run between requesting and showing the prompt. + else if( com_downloadPrompt->integer & DLP_SHOW ) { + if( com_downloadPrompt->integer & DLP_STALE ) { + Com_Printf( "WARNING: UI VM does not support download prompt\n" ); + Cvar_Set( "com_downloadPrompt", va( "%d", DLP_IGNORE ) ); + CL_NextDownload( ); + } else + Cvar_Set( "com_downloadPrompt", + va( "%d", com_downloadPrompt->integer | DLP_STALE ) ); + } + #if USE_CURL if(clc.downloadCURLM) { CL_cURL_PerformDownload(); @@ -2566,6 +2658,8 @@ #if USE_CURL cl_cURLLib = Cvar_Get("cl_cURLLib", DEFAULT_CURL_LIB, CVAR_ARCHIVE); #endif + com_downloadPrompt = Cvar_Get ("com_downloadPrompt", "0", CVAR_TEMP); + Cvar_Get( "com_downloadPromptText", "", CVAR_TEMP ); cl_conXOffset = Cvar_Get ("cl_conXOffset", "0", 0); #ifdef MACOS_X Index: ui/download.menu =================================================================== --- ui/download.menu (revision 0) +++ ui/download.menu (revision 0) @@ -0,0 +1,181 @@ +#include "ui/menudef.h" + +{ + \\ DOWNLOAD \\ + + menuDef + { + name "download_popmenu" + visible 0 + fullscreen 0 + rect 158 80 320 320 + focusColor 1 .75 0 1 + style 1 + border 1 + popup + onClose { } + onOpen + { + uiScript loadServerInfo; + } + onESC + { + play "sound/misc/menu1.wav"; + close download_popmenu; + uiScript downloadIgnore; + } + + itemDef + { + name window + rect 10 15 300 320 + style WINDOW_STYLE_FILLED + backcolor 0 0 0 1 + visible 1 + decoration + + border WINDOW_BORDER_FULL + borderSize 1.0 + borderColor 0.5 0.5 0.5 1 + } + + itemDef + { + name downloadinfo + rect 0 50 320 20 + text "Download" + textalign 1 + textstyle 6 + textscale .333 + textalignx 160 + textaligny 23 + forecolor 1 1 1 1 + visible 1 + decoration + } + + itemDef + { + name downloadinfo + rect 60 80 200 270 + type ITEM_TYPE_TEXT + style 1 + textstyle 3 + autowrapped + cvar "com_downloadPromptText" + textalign ITEM_ALIGN_CENTER + textalignx 100 + textaligny 23 + textscale .25 + forecolor 1 1 1 1 + visible 1 + decoration + } + + + // BUTTON // + + + itemDef + { + name curl + text "Download from website" + type 1 + textscale .25 + group grpControlbutton + type ITEM_TYPE_BUTTON + style WINDOW_STYLE_EMPTY + rect 60 250 200 15 + textalign 1 + textalignx 100 + textaligny 13 + forecolor 1 1 1 1 + backcolor .37 .1 .1 1 + visible 1 + cvarTest "ui_serverinfo_allowdl" + showCvar { 1 5 9 13 } + action + { + play "sound/misc/menu1.wav"; + close download_popmenu; + uiScript downloadCURL; + } + } + + itemDef + { + name udp + text "Download from server" + type 1 + textscale .25 + group grpControlbutton + type ITEM_TYPE_BUTTON + style WINDOW_STYLE_EMPTY + rect 60 265 200 15 + textalign 1 + textalignx 100 + textaligny 13 + forecolor 1 1 1 1 + backcolor .37 .1 .1 1 + visible 1 + cvarTest "ui_serverinfo_allowdl" + showCvar { 1 3 9 11 } + action + { + play "sound/misc/menu1.wav"; + close download_popmenu; + uiScript downloadUDP; + } + } + + itemDef + { + name ignore + text "Ignore" + type 1 + textscale .25 + group grpControlbutton + type ITEM_TYPE_BUTTON + style WINDOW_STYLE_EMPTY + rect 60 280 200 15 + textalign 1 + textalignx 100 + textaligny 13 + forecolor 1 1 1 1 + backcolor .37 .1 .1 1 + visible 1 + cvarTest "sv_pure" + hideCvar { 1 } + action + { + play "sound/misc/menu1.wav"; + close download_popmenu; + uiScript downloadIgnore; + } + } + + itemDef + { + name disconnect + text "Disconnect" + type 1 + textscale .25 + group grpControlbutton + type ITEM_TYPE_BUTTON + style WINDOW_STYLE_EMPTY + rect 60 295 200 15 + textalign 1 + textalignx 100 + textaligny 13 + forecolor 1 1 1 1 + backcolor .37 .1 .1 1 + visible 1 + action + { + play "sound/misc/menu1.wav"; + close download_popmenu; + exec "disconnect"; + } + } + } +} Property changes on: ui/download.menu ___________________________________________________________________ Name: svn:executable + * Index: ui/menus.txt =================================================================== --- ui/menus.txt (revision 938) +++ ui/menus.txt (working copy) @@ -12,6 +12,7 @@ loadMenu { "ui/quit.menu" } loadMenu { "ui/addfilter.menu" } loadMenu { "ui/error.menu" } + loadMenu { "ui/download.menu" } loadMenu { "ui/drop.menu" } loadMenu { "ui/serverinfo.menu" } loadMenu { "ui/findplayer.menu" }