/* cl_custom.c - downloading custom resources Copyright (C) 2018 Uncle Mike This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #include "common.h" #include "client.h" #include "net_encode.h" qboolean CL_CheckFile( sizebuf_t *msg, resource_t *pResource ) { char filepath[MAX_QPATH]; switch( pResource->type ) { case t_sound: case t_model: // built-in resources not needs to be downloaded if( pResource->szFileName[0] == '*' ) return true; break; } // resource was missed on server if( pResource->nDownloadSize == -1 ) { ClearBits( pResource->ucFlags, RES_FATALIFMISSING ); return true; } if( pResource->type == t_sound ) Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", pResource->szFileName ); else Q_strncpy( filepath, pResource->szFileName, sizeof( filepath )); if( !COM_IsSafeFileToDownload( filepath )) { Con_Reportf( "refusing to download %s\n", filepath ); return true; } if( !cl_allow_download.value ) { Con_Reportf( "Download refused, cl_allow_download is 0\n" ); return true; } if( cls.state == ca_active && !cl_download_ingame.value ) { Con_Reportf( "In-game download refused...\n" ); return true; } // don't request downloads from local client it's silly if( Host_IsLocalClient() || FS_FileExists( filepath, false )) return true; if( cls.demoplayback ) { Con_Reportf( S_WARN "file %s missing during demo playback.\n", filepath ); return true; } if( cl.downloadUrl[0] ) { HTTP_AddDownload( filepath, pResource->nDownloadSize, true ); host.downloadcount++; return false; } MSG_BeginClientCmd( msg, clc_stringcmd ); MSG_WriteStringf( msg, "dlfile %s", filepath ); host.downloadcount++; return false; } void CL_AddToResourceList( resource_t *pResource, resource_t *pList ) { if( pResource->pPrev != NULL || pResource->pNext != NULL ) { Con_Reportf( S_ERROR "Resource already linked\n" ); return; } if( pList->pPrev == NULL || pList->pNext == NULL ) Host_Error( "Resource list corrupted.\n" ); pResource->pPrev = pList->pPrev; pResource->pNext = pList; pList->pPrev->pNext = pResource; pList->pPrev = pResource; } void CL_RemoveFromResourceList( resource_t *pResource ) { if( pResource->pPrev == NULL || pResource->pNext == NULL ) Host_Error( "mislinked resource in CL_RemoveFromResourceList\n" ); if( pResource->pNext == pResource || pResource->pPrev == pResource ) Host_Error( "attempt to free last entry in list.\n" ); pResource->pPrev->pNext = pResource->pNext; pResource->pNext->pPrev = pResource->pPrev; pResource->pPrev = NULL; pResource->pNext = NULL; } void CL_MoveToOnHandList( resource_t *pResource ) { if( !pResource ) { Con_Reportf( "Null resource passed to CL_MoveToOnHandList\n" ); return; } CL_RemoveFromResourceList( pResource ); CL_AddToResourceList( pResource, &cl.resourcesonhand ); } static void CL_ClearResourceList( resource_t *pList ) { resource_t *p, *n; for( p = pList->pNext; p != pList && p; p = n ) { n = p->pNext; CL_RemoveFromResourceList( p ); Mem_Free( p ); } pList->pPrev = pList; pList->pNext = pList; } void CL_ClearResourceLists( void ) { CL_ClearResourceList( &cl.resourcesneeded ); CL_ClearResourceList( &cl.resourcesonhand ); }