367 lines
8.6 KiB
C
367 lines
8.6 KiB
C
/*
|
|
sv_custom.c - downloading custom resources
|
|
Copyright (C) 2010 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 "server.h"
|
|
|
|
#define RES_CHECK_CONSISTENCY (1<<7) // check consistency for this resource
|
|
|
|
//=======================================================================
|
|
//
|
|
// UNDER CONSTRUCTION
|
|
//
|
|
//=======================================================================
|
|
|
|
typedef struct
|
|
{
|
|
char *filename;
|
|
int num_items;
|
|
file_t *file; // pointer to wadfile
|
|
} cachewad_t;
|
|
|
|
int CustomDecal_Init( cachewad_t *wad, byte *data, int size, int playernum )
|
|
{
|
|
// TODO: implement
|
|
return 0;
|
|
}
|
|
|
|
void *CustomDecal_Validate( byte *data, int size )
|
|
{
|
|
// TODO: implement
|
|
return NULL;
|
|
}
|
|
|
|
int SV_CreateCustomization( customization_t *pListHead, resource_t *pResource, int playernumber, int flags, customization_t **pCust, int *nLumps )
|
|
{
|
|
customization_t *pRes;
|
|
cachewad_t *pldecal;
|
|
qboolean found_problem;
|
|
|
|
found_problem = false;
|
|
|
|
ASSERT( pResource != NULL );
|
|
|
|
if( pCust != NULL ) *pCust = NULL;
|
|
|
|
pRes = Z_Malloc( sizeof( customization_t ));
|
|
pRes->resource = *pResource;
|
|
|
|
if( pResource->nDownloadSize <= 0 )
|
|
{
|
|
found_problem = true;
|
|
}
|
|
else
|
|
{
|
|
pRes->bInUse = true;
|
|
|
|
if(( flags & FCUST_FROMHPAK ) && !HPAK_GetDataPointer( "custom.hpk", pResource, (byte **)&(pRes->pBuffer), NULL ))
|
|
{
|
|
found_problem = true;
|
|
}
|
|
else
|
|
{
|
|
pRes->pBuffer = FS_LoadFile( pResource->szFileName, NULL, false );
|
|
|
|
if(!( pRes->resource.ucFlags & RES_CUSTOM ) || pRes->resource.type != t_decal )
|
|
{
|
|
// break, except we're not in a loop
|
|
}
|
|
else
|
|
{
|
|
pRes->resource.playernum = playernumber;
|
|
|
|
if( !CustomDecal_Validate( pRes->pBuffer, pResource->nDownloadSize ))
|
|
{
|
|
found_problem = true;
|
|
}
|
|
else if( flags & RES_CUSTOM )
|
|
{
|
|
}
|
|
else
|
|
{
|
|
pRes->pInfo = Z_Malloc( sizeof( cachewad_t ));
|
|
pldecal = pRes->pInfo;
|
|
|
|
if( pResource->nDownloadSize < 1024 || pResource->nDownloadSize > 16384 )
|
|
{
|
|
found_problem = true;
|
|
}
|
|
else if( !CustomDecal_Init( pldecal, pRes->pBuffer, pResource->nDownloadSize, playernumber ))
|
|
{
|
|
found_problem = true;
|
|
}
|
|
else if( pldecal->num_items <= 0 )
|
|
{
|
|
found_problem = true;
|
|
}
|
|
else
|
|
{
|
|
if( nLumps ) *nLumps = pldecal->num_items;
|
|
|
|
pRes->bTranslated = 1;
|
|
pRes->nUserData1 = 0;
|
|
pRes->nUserData2 = pldecal->num_items;
|
|
|
|
if( flags & FCUST_WIPEDATA )
|
|
{
|
|
Mem_Free( pldecal->filename );
|
|
FS_Close( pldecal->file );
|
|
Mem_Free( pldecal );
|
|
pRes->pInfo = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !found_problem )
|
|
{
|
|
if( pCust ) *pCust = pRes;
|
|
|
|
pRes->pNext = pListHead->pNext;
|
|
pListHead->pNext = pRes;
|
|
}
|
|
else
|
|
{
|
|
if( pRes->pBuffer ) Mem_Free( pRes->pBuffer );
|
|
if( pRes->pInfo ) Mem_Free( pRes->pInfo );
|
|
Mem_Free( pRes );
|
|
}
|
|
|
|
return !found_problem;
|
|
}
|
|
|
|
void SV_CreateCustomizationList( sv_client_t *cl )
|
|
{
|
|
resource_t *pRes;
|
|
customization_t *pCust, *pNewCust;
|
|
int duplicated, lump_count;
|
|
|
|
cl->customdata.pNext = NULL;
|
|
|
|
for( pRes = cl->resourcesonhand.pNext; pRes != &cl->resourcesonhand; pRes = pRes->pNext )
|
|
{
|
|
duplicated = false;
|
|
|
|
for( pCust = cl->customdata.pNext; pCust != NULL; pCust = pCust->pNext )
|
|
{
|
|
if( !memcmp( pCust->resource.rgucMD5_hash, pRes->rgucMD5_hash, 16 ))
|
|
{
|
|
duplicated = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( duplicated )
|
|
{
|
|
MsgDev( D_WARN, "CreateCustomizationList: duplicate resource detected.\n" );
|
|
continue;
|
|
}
|
|
|
|
// create it.
|
|
lump_count = 0;
|
|
|
|
if( !SV_CreateCustomization( &cl->customdata, pRes, -1, 3, &pNewCust, &lump_count ))
|
|
{
|
|
MsgDev( D_WARN, "CreateCustomizationList: ignoring custom decal.\n" );
|
|
continue;
|
|
}
|
|
|
|
pNewCust->nUserData2 = lump_count;
|
|
svgame.dllFuncs.pfnPlayerCustomization( cl->edict, pNewCust );
|
|
}
|
|
}
|
|
|
|
void SV_ClearCustomizationList( customization_t *pHead )
|
|
{
|
|
customization_t *pNext, *pCur;
|
|
cachewad_t *wad;
|
|
|
|
if( !pHead || !pHead->pNext )
|
|
return;
|
|
|
|
pCur = pHead->pNext;
|
|
|
|
do
|
|
{
|
|
pNext = pCur->pNext;
|
|
|
|
if( pCur->bInUse && pCur->pBuffer )
|
|
Mem_Free( pCur->pBuffer );
|
|
|
|
if( pCur->bInUse && pCur->pInfo )
|
|
{
|
|
if( pCur->resource.type == t_decal )
|
|
{
|
|
wad = (cachewad_t *)pCur->pInfo;
|
|
Mem_Free( wad->filename );
|
|
FS_Close( wad->file );
|
|
}
|
|
|
|
Mem_Free( pCur->pInfo );
|
|
}
|
|
|
|
Mem_Free( pCur );
|
|
pCur = pNext;
|
|
} while( pCur != NULL );
|
|
|
|
pCur->pNext = NULL;
|
|
}
|
|
|
|
qboolean SV_FileInConsistencyList( resource_t *resource, sv_consistency_t **out )
|
|
{
|
|
int i = 0;
|
|
|
|
while( 1 )
|
|
{
|
|
if( !sv.consistency_files[i].name )
|
|
return false; // end of consistency res
|
|
|
|
if( !Q_stricmp( sv.consistency_files[i].name, resource->szFileName ))
|
|
break;
|
|
i++;
|
|
}
|
|
|
|
// get pointer on a matched record
|
|
if( out ) *out = &sv.consistency_files[i];
|
|
|
|
return true;
|
|
}
|
|
|
|
int SV_TransferConsistencyInfo( void )
|
|
{
|
|
sv_consistency_t *check;
|
|
string filepath;
|
|
vec3_t mins, maxs;
|
|
int i, total = 0;
|
|
resource_t *res;
|
|
|
|
for( i = 0; i < sv.num_resources; i++ )
|
|
{
|
|
res = &sv.resources[i];
|
|
|
|
if( res->ucFlags & RES_CHECK_CONSISTENCY )
|
|
continue; // already checked?
|
|
|
|
if( !SV_FileInConsistencyList( res, &check ))
|
|
continue;
|
|
|
|
res->ucFlags |= RES_CHECK_CONSISTENCY;
|
|
|
|
if( res->type == t_sound )
|
|
Q_snprintf( filepath, sizeof( filepath ), "sound/%s", res->szFileName );
|
|
else Q_strncpy( filepath, res->szFileName, sizeof( filepath ));
|
|
|
|
MD5_HashFile( res->rgucMD5_hash, filepath, NULL );
|
|
|
|
if( res->type == t_model )
|
|
{
|
|
switch( check->force_state )
|
|
{
|
|
case force_exactfile:
|
|
// only MD5 hash compare
|
|
break;
|
|
case force_model_samebounds:
|
|
if( !Mod_GetStudioBounds( filepath, mins, maxs ))
|
|
Host_Error( "Mod_GetStudioBounds: couldn't get bounds for %s\n", filepath );
|
|
|
|
res->rguc_reserved[0x00] = check->force_state;
|
|
memcpy( &res->rguc_reserved[0x01], mins, sizeof( mins ));
|
|
memcpy( &res->rguc_reserved[0x0D], maxs, sizeof( maxs ));
|
|
break;
|
|
case force_model_specifybounds:
|
|
res->rguc_reserved[0x00] = check->force_state;
|
|
memcpy( &res->rguc_reserved[0x01], check->mins, sizeof( check->mins ));
|
|
memcpy( &res->rguc_reserved[0x0D], check->maxs, sizeof( check->maxs ));
|
|
break;
|
|
}
|
|
}
|
|
total++;
|
|
}
|
|
|
|
return total;
|
|
}
|
|
|
|
void SV_SendConsistencyList( sizebuf_t *msg )
|
|
{
|
|
resource_t *res;
|
|
int resIndex;
|
|
int lastIndex;
|
|
int i;
|
|
|
|
if( sv_consistency.value && ( sv.num_consistency_resources > 0 ) && !FBitSet( svs.currentPlayer->flags, FCL_HLTV_PROXY ))
|
|
{
|
|
lastIndex = 0;
|
|
MSG_WriteOneBit( msg, 1 );
|
|
|
|
for( i = 0; i < sv.num_resources; i++ )
|
|
{
|
|
res = &sv.resources[i];
|
|
|
|
if(!( res->ucFlags & RES_CHECK_CONSISTENCY ))
|
|
continue;
|
|
|
|
resIndex = (i - lastIndex);
|
|
MSG_WriteOneBit( msg, 1 );
|
|
MSG_WriteSBitLong( msg, resIndex, MAX_MODEL_BITS );
|
|
lastIndex = i;
|
|
}
|
|
}
|
|
|
|
// write end of the list
|
|
MSG_WriteOneBit( msg, 0 );
|
|
}
|
|
|
|
void SV_SendResources( sizebuf_t *msg )
|
|
{
|
|
byte nullrguc[32];
|
|
int i;
|
|
|
|
memset( nullrguc, 0, sizeof( nullrguc ));
|
|
|
|
MSG_BeginServerCmd( msg, svc_customization );
|
|
MSG_WriteLong( msg, svs.spawncount );
|
|
|
|
// g-cont. This is more than HL limit but unmatched with GoldSrc protocol
|
|
MSG_WriteSBitLong( msg, sv.num_resources, MAX_MODEL_BITS );
|
|
|
|
for( i = 0; i < sv.num_resources; i++ )
|
|
{
|
|
MSG_WriteSBitLong( msg, sv.resources[i].type, 4 );
|
|
MSG_WriteString( msg, sv.resources[i].szFileName );
|
|
MSG_WriteSBitLong( msg, sv.resources[i].nIndex, MAX_MODEL_BITS );
|
|
MSG_WriteSBitLong( msg, sv.resources[i].nDownloadSize, 24 ); // prevent to download a very big files?
|
|
MSG_WriteSBitLong( msg, sv.resources[i].ucFlags, 3 ); // g-cont. why only first three flags?
|
|
|
|
if( sv.resources[i].ucFlags & RES_CUSTOM )
|
|
{
|
|
MSG_WriteBits( msg, sv.resources[i].rgucMD5_hash, sizeof( sv.resources[i].rgucMD5_hash ));
|
|
}
|
|
|
|
if( memcmp( nullrguc, sv.resources[i].rguc_reserved, sizeof( nullrguc )))
|
|
{
|
|
MSG_WriteOneBit( msg, 1 );
|
|
MSG_WriteBits( msg, sv.resources[i].rguc_reserved, sizeof( sv.resources[i].rguc_reserved ));
|
|
|
|
}
|
|
else
|
|
{
|
|
MSG_WriteOneBit( msg, 0 );
|
|
}
|
|
}
|
|
|
|
SV_SendConsistencyList( msg );
|
|
} |