diff --git a/dlls/game.cpp b/dlls/game.cpp index 70a42975..7f9e7eda 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -33,7 +33,7 @@ cvar_t weaponstay = {"mp_weaponstay","0", FCVAR_SERVER }; cvar_t forcerespawn= {"mp_forcerespawn","1", FCVAR_SERVER }; cvar_t flashlight = {"mp_flashlight","0", FCVAR_SERVER }; cvar_t aimcrosshair= {"mp_autocrosshair","1", FCVAR_SERVER }; -cvar_t decalfrequency = {"decalfrequency","30", FCVAR_SERVER }; +cvar_t decalfrequency = {"decalfrequency","30", FCVAR_SERVER|FCVAR_ARCHIVE }; cvar_t teamlist = {"mp_teamlist","hgrunt;scientist", FCVAR_SERVER }; cvar_t teamoverride = {"mp_teamoverride","1" }; cvar_t defaultteam = {"mp_defaultteam","0" }; diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 7a5daaf8..d63ecc13 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -1339,7 +1339,7 @@ void CL_PlayDemo_f( void ) demo.starttime = CL_GetDemoPlaybackClock(); // for determining whether to read another message - Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableValue( "net_qport" ), NULL, NULL ); + Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableInteger( "net_qport" ), NULL, CL_GetFragmentSize ); memset( demo.cmds, 0, sizeof( demo.cmds )); demo.angle_position = 1; diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 2bcec09c..9e0d20e0 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -25,6 +25,8 @@ GNU General Public License for more details. #define MAX_TOTAL_CMDS 32 #define MAX_CMD_BUFFER 8000 #define CONNECTION_PROBLEM_TIME 15.0 // 15 seconds +#define CL_CONNECTION_RETRIES 10 +#define CL_TEST_RETRIES 5 CVAR_DEFINE_AUTO( mp_decals, "300", FCVAR_ARCHIVE, "decals limit in multiplayer" ); CVAR_DEFINE_AUTO( dev_overview, "0", 0, "draw level in overview-mode" ); @@ -186,6 +188,14 @@ void CL_CheckClientState( void ) } } +int CL_GetFragmentSize( void *unused ) +{ + if( Netchan_IsLocal( &cls.netchan )) + return FRAGMENT_LOCAL_SIZE; + + return FRAGMENT_MAX_SIZE; +} + /* ===================== CL_SignonReply @@ -702,7 +712,7 @@ void CL_WritePacket( void ) if( cl.maxclients == 1 || ( NET_IsLocalAddress( cls.netchan.remote_address ) && !host_limitlocal->value )) send_command = true; - if(( host.realtime >= cls.nextcmdtime ) && Netchan_CanPacket( &cls.netchan )) + if(( host.realtime >= cls.nextcmdtime ) && Netchan_CanPacket( &cls.netchan, true )) send_command = true; if( cl.send_reply ) @@ -1064,16 +1074,40 @@ void CL_CheckForResend( void ) if( !NET_StringToAdr( cls.servername, &adr )) { MsgDev( D_ERROR, "CL_CheckForResend: bad server address\n" ); - cls.state = ca_disconnected; - cls.signon = 0; + CL_Disconnect(); + return; + } + + // only retry so many times before failure. + if( cls.connect_retry >= CL_CONNECTION_RETRIES ) + { + MsgDev( D_ERROR, "CL_CheckForResend: couldn't connected\n" ); + CL_Disconnect(); return; } if( adr.port == 0 ) adr.port = MSG_BigShort( PORT_SERVER ); + + if( cls.connect_retry == CL_TEST_RETRIES ) + { + // too many fails use default connection method + Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" ); + Cvar_SetValue( "cl_dlmax", FRAGMENT_MAX_SIZE ); + cls.connect_time = host.realtime; + cls.connect_retry++; + return; + } + + cls.max_fragment_size = Q_max( FRAGMENT_MAX_SIZE, cls.max_fragment_size >> Q_min( 1, cls.connect_retry )); cls.connect_time = host.realtime; // for retransmit requests + cls.connect_retry++; Con_Printf( "Connecting to %s...\n", cls.servername ); +#if 0 Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" ); +#else + Netchan_OutOfBandPrint( NS_CLIENT, adr, "bandwidth %i %i\n", PROTOCOL_VERSION, cls.max_fragment_size ); +#endif } resource_t *CL_AddResource( resourcetype_t type, const char *name, int size, qboolean bFatalIfMissing, int index ) @@ -1157,6 +1191,8 @@ void CL_Connect_f( void ) cls.state = ca_connecting; Q_strncpy( cls.servername, server, sizeof( cls.servername )); cls.connect_time = MAX_HEARTBEAT; // CL_CheckForResend() will fire immediately + cls.max_fragment_size = FRAGMENT_MAX_SIZE; // guess a we can establish connection with maximum fragment size + cls.connect_retry = 0; cls.spectator = false; cls.signon = 0; } @@ -1229,16 +1265,17 @@ void CL_ClearState( void ) { int i; + CL_ClearResourceLists(); + + for( i = 0; i < MAX_CLIENTS; i++ ) + COM_ClearCustomizationList( &cl.players[i].customdata, false ); + S_StopAllSounds ( true ); CL_ClearEffects (); CL_FreeEdicts (); CL_ClearPhysEnts (); NetAPI_CancelAllRequests(); - CL_ClearResourceLists(); - - for( i = 0; i < MAX_CLIENTS; i++ ) - COM_ClearCustomizationList( &cl.players[i].customdata, false ); // wipe the entire cl structure memset( &cl, 0, sizeof( cl )); @@ -1284,9 +1321,9 @@ void CL_SendDisconnectMessage( void ) cls.netchan.remote_address.type = NA_LOOPBACK; // make sure message will be delivered - Netchan_Transmit( &cls.netchan, MSG_GetNumBytesWritten( &buf ), MSG_GetData( &buf )); - Netchan_Transmit( &cls.netchan, MSG_GetNumBytesWritten( &buf ), MSG_GetData( &buf )); - Netchan_Transmit( &cls.netchan, MSG_GetNumBytesWritten( &buf ), MSG_GetData( &buf )); + Netchan_TransmitBits( &cls.netchan, MSG_GetNumBitsWritten( &buf ), MSG_GetData( &buf )); + Netchan_TransmitBits( &cls.netchan, MSG_GetNumBitsWritten( &buf ), MSG_GetData( &buf )); + Netchan_TransmitBits( &cls.netchan, MSG_GetNumBitsWritten( &buf ), MSG_GetData( &buf )); } /* @@ -1300,7 +1337,7 @@ void CL_Reconnect( qboolean setup_netchan ) { if( setup_netchan ) { - Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableValue( "net_qport" ), NULL, NULL ); + Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableInteger( "net_qport" ), NULL, CL_GetFragmentSize ); } else { @@ -1340,6 +1377,7 @@ void CL_Disconnect( void ) cls.connect_time = 0; cls.changedemo = false; + cls.max_fragment_size = FRAGMENT_MAX_SIZE; // reset fragment size CL_Stop_f(); // send a disconnect message to the server @@ -1353,6 +1391,7 @@ void CL_Disconnect( void ) Netchan_Clear( &cls.netchan ); cls.state = ca_disconnected; + cls.connect_retry = 0; cls.signon = 0; // back to menu in non-developer mode @@ -1741,6 +1780,60 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) // print command from somewhere Con_Printf( "%s", MSG_ReadString( msg )); } + else if( !Q_strcmp( c, "testpacket" )) + { + byte recv_buf[NET_MAX_FRAGMENT]; + dword crcValue = MSG_ReadLong( msg ); + int realsize = MSG_GetMaxBytes( msg ) - MSG_GetNumBytesRead( msg ); + dword crcValue2 = 0; + + if( cls.max_fragment_size != MSG_GetMaxBytes( msg )) + { + if( cls.connect_retry >= CL_TEST_RETRIES ) + { + // too many fails use default connection method + Netchan_OutOfBandPrint( NS_CLIENT, from, "getchallenge\n" ); + Cvar_SetValue( "cl_dlmax", FRAGMENT_MAX_SIZE ); + cls.connect_time = host.realtime; + return; + } + + // if we waiting more than cl_timeout or packet was trashed + Msg( "got testpacket, size mismatched %d should be %d\n", MSG_GetMaxBytes( msg ), cls.max_fragment_size ); + cls.connect_time = MAX_HEARTBEAT; + return; // just wait for a next responce + } + + // reading test buffer + MSG_ReadBytes( msg, recv_buf, realsize ); + + // procssing the CRC + CRC32_ProcessBuffer( &crcValue2, recv_buf, realsize ); + + if( crcValue == crcValue2 ) + { + // packet was sucessfully delivered, adjust the fragment size and get challenge + Msg( "CRC %p is matched, get challenge, fragment size %d\n", crcValue, cls.max_fragment_size ); + Netchan_OutOfBandPrint( NS_CLIENT, from, "getchallenge\n" ); + Cvar_SetValue( "cl_dlmax", cls.max_fragment_size ); + cls.connect_time = host.realtime; + } + else + { + if( cls.connect_retry >= CL_TEST_RETRIES ) + { + // too many fails use default connection method + Netchan_OutOfBandPrint( NS_CLIENT, from, "getchallenge\n" ); + Cvar_SetValue( "cl_dlmax", FRAGMENT_MAX_SIZE ); + cls.connect_time = host.realtime; + return; + } + + Msg( "got testpacket, CRC mismatched %p should be %p, trying next fragment size %d\n", crcValue2, crcValue, cls.max_fragment_size >> 1 ); + // trying the next size of packet + cls.connect_time = MAX_HEARTBEAT; + } + } else if( !Q_strcmp( c, "ping" )) { // ping from somewhere diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index dfcfabee..ce929e2f 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -865,17 +865,17 @@ void CL_RemoveCustomization( int nPlayerNum, customization_t *pRemove ) if( pList->bInUse && pList->pInfo ) { - if ( pList->resource.type == t_decal ) + if( pList->resource.type == t_decal ) { if( cls.state == ca_active ) - R_DecalRemoveAll( ~nPlayerNum ); - + R_DecalRemoveAll( pList->nUserData1 ); FS_FreeImage( pList->pInfo ); } } cl.players[nPlayerNum].customdata.pNext = pNext; - Mem_Free( pRemove ); + Mem_Free( pList ); + break; } } @@ -888,64 +888,66 @@ CL_ParseCustomization void CL_ParseCustomization( sizebuf_t *msg ) { customization_t *pExistingCustomization; - resource_t *resource; customization_t *pList; qboolean bFound; + resource_t *pRes; int i; i = MSG_ReadByte( msg ); if( i >= MAX_CLIENTS ) Host_Error( "Bogus player index during customization parsing.\n" ); - resource = Mem_Alloc( cls.mempool, sizeof( resource_t )); - resource->type = MSG_ReadByte( msg ); + pRes = Mem_Alloc( cls.mempool, sizeof( resource_t )); + pRes->type = MSG_ReadByte( msg ); - Q_strncpy( resource->szFileName, MSG_ReadString( msg ), sizeof( resource->szFileName )); - resource->nIndex = MSG_ReadShort( msg ); - resource->nDownloadSize = MSG_ReadLong( msg ); - resource->ucFlags = MSG_ReadByte( msg ) & ~RES_WASMISSING; - resource->pNext = resource->pPrev = NULL; + Q_strncpy( pRes->szFileName, MSG_ReadString( msg ), sizeof( pRes->szFileName )); + pRes->nIndex = MSG_ReadShort( msg ); + pRes->nDownloadSize = MSG_ReadLong( msg ); + pRes->ucFlags = MSG_ReadByte( msg ) & ~RES_WASMISSING; + pRes->pNext = pRes->pPrev = NULL; - if( FBitSet( resource->ucFlags, RES_CUSTOM )) - MSG_ReadBytes( msg, resource->rgucMD5_hash, 16 ); - resource->playernum = i; + if( FBitSet( pRes->ucFlags, RES_CUSTOM )) + MSG_ReadBytes( msg, pRes->rgucMD5_hash, 16 ); + pRes->playernum = i; if( !cl_allow_download.value ) { Con_DPrintf( "Refusing new resource, cl_allow_download set to 0\n" ); - Mem_Free( resource ); + Mem_Free( pRes ); return; } if( cls.state == ca_active && !cl_download_ingame.value ) { Con_DPrintf( "Refusing new resource, cl_download_ingame set to 0\n" ); - Mem_Free( resource ); + Mem_Free( pRes ); return; } - pExistingCustomization = CL_PlayerHasCustomization( i, resource->type ); + pExistingCustomization = CL_PlayerHasCustomization( i, pRes->type ); if( pExistingCustomization ) CL_RemoveCustomization( i, pExistingCustomization ); bFound = false; - for( pList = cl.players[resource->playernum].customdata.pNext; pList; pList = pList->pNext ) + for( pList = cl.players[pRes->playernum].customdata.pNext; pList; pList = pList->pNext ) { - if( !memcmp( pList->resource.rgucMD5_hash, resource->rgucMD5_hash, 16 ) ) + if( !memcmp( pList->resource.rgucMD5_hash, pRes->rgucMD5_hash, 16 )) { bFound = true; break; } } - if( HPAK_GetDataPointer( CUSTOM_RES_PATH, resource, NULL, NULL )) + if( HPAK_GetDataPointer( CUSTOM_RES_PATH, pRes, NULL, NULL )) { qboolean bError = false; if( !bFound ) { - if( !COM_CreateCustomization( &cl.players[resource->playernum].customdata, resource, resource->playernum, RES_FATALIFMISSING, NULL, NULL )) + pList = &cl.players[pRes->playernum].customdata; + + if( !COM_CreateCustomization( pList, pRes, pRes->playernum, FCUST_FROMHPAK, NULL, NULL )) bError = true; } else @@ -954,13 +956,13 @@ void CL_ParseCustomization( sizebuf_t *msg ) } if( bError ) Con_DPrintf( "Error loading customization\n" ); - Mem_Free( resource ); + Mem_Free( pRes ); } else { - resource->ucFlags |= RES_WASMISSING; - CL_AddToResourceList( resource, &cl.resourcesneeded ); - Con_Printf( "Requesting %s from server\n", resource ); + SetBits( pRes->ucFlags, RES_WASMISSING ); + CL_AddToResourceList( pRes, &cl.resourcesneeded ); + Con_Printf( "Requesting %s from server\n", pRes->szFileName ); CL_StartResourceDownloading( "Custom resource propagation...\n", true ); } } @@ -1016,6 +1018,31 @@ void CL_ParseResourceRequest( sizebuf_t *msg ) } } +/* +================== +CL_CreateCustomizationList + +loading custom decal for self +================== +*/ +void CL_CreateCustomizationList( void ) +{ + resource_t *pResource; + player_info_t *pPlayer; + int i; + + pPlayer = &cl.players[cl.playernum]; + pPlayer->customdata.pNext = NULL; + + for( i = 0; i < cl.num_resources; i++ ) + { + pResource = &cl.resourcelist[i]; + + if( !COM_CreateCustomization( &pPlayer->customdata, pResource, cl.playernum, 0, NULL, NULL )) + Con_Printf( "problem with client customization %i, ignoring...", pResource ); + } +} + /* ================== CL_ParseFileTransferFailed @@ -1157,6 +1184,10 @@ void CL_ParseServerData( sizebuf_t *msg ) cls.scrshot_request = scrshot_plaque; // request levelshot even if exist (check filetime) } + for( i = 0; i < MAX_CLIENTS; i++ ) + COM_ClearCustomizationList( &cl.players[i].customdata, true ); + CL_CreateCustomizationList(); + // request resources from server CL_ServerCommand( true, "sendres %i\n", cl.servercount ); diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 82ef26db..12fc95a5 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -116,7 +116,16 @@ add client-side resource to list */ void CL_AddClientResource( const char *filename, int type ) { - resource_t *pResource; + resource_t *p, *pResource; + + for( p = cl.resourcesneeded.pNext; p != &cl.resourcesneeded; p = p->pNext ) + { + if( !Q_stricmp( p->szFileName, filename )) + break; + } + + if( p == &cl.resourcesneeded ) + return; // already existed ? pResource = Mem_Alloc( cls.mempool, sizeof( resource_t )); @@ -2392,13 +2401,13 @@ void CL_ParseTempEntity( sizebuf_t *msg ) R_RicochetSound( pos ); break; case TE_PLAYERDECAL: - color = MSG_ReadByte( &buf ); // playernum + color = MSG_ReadByte( &buf ) - 1; // playernum pos[0] = MSG_ReadCoord( &buf ); pos[1] = MSG_ReadCoord( &buf ); pos[2] = MSG_ReadCoord( &buf ); entityIndex = MSG_ReadShort( &buf ); decalIndex = MSG_ReadByte( &buf ); - CL_PlayerDecal( CL_DecalIndex( decalIndex ), entityIndex, pos ); + CL_PlayerDecal( color, decalIndex, entityIndex, pos ); break; case TE_BUBBLES: case TE_BUBBLETRAIL: @@ -2973,9 +2982,28 @@ CL_PlayerDecal spray custom colored decal (clan logo etc) =============== */ -void CL_PlayerDecal( int textureIndex, int entityIndex, float *pos ) +void CL_PlayerDecal( int playernum, int customIndex, int entityIndex, float *pos ) { - R_DecalShoot( textureIndex, entityIndex, 0, pos, 0, 1.0f ); + int textureIndex = 0; + customization_t *pCust = NULL; + + if( playernum < MAX_CLIENTS ) + pCust = cl.players[playernum].customdata.pNext; + + if( pCust != NULL && pCust->pBuffer != NULL && pCust->pInfo != NULL ) + { + if( FBitSet( pCust->resource.ucFlags, RES_CUSTOM ) && pCust->resource.type == t_decal && pCust->bTranslated ) + { + if( !pCust->nUserData1 && pCust->pInfo != NULL ) + { + const char *decalname = va( "player%dlogo%d", playernum, customIndex ); + pCust->nUserData1 = GL_LoadTextureInternal( decalname, pCust->pInfo, TF_DECAL, false ); + } + textureIndex = pCust->nUserData1; + } + } + + R_DecalShoot( textureIndex, entityIndex, 0, pos, FDECAL_CUSTOM, 1.0f ); } /* diff --git a/engine/client/client.h b/engine/client/client.h index 03a5f54d..998b7512 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -568,6 +568,8 @@ typedef struct // connection information char servername[MAX_QPATH]; // name of server from original connect double connect_time; // for connection retransmits + int max_fragment_size; // we needs to test a real network bandwidth + int connect_retry; // how many times we send a connect packet to the server qboolean spectator; // not a real player, just spectator local_state_t spectator_state; // init as client startup @@ -737,6 +739,7 @@ void CL_SendCommand( void ); void CL_Disconnect_f( void ); void CL_ProcessFile( qboolean successfully_received, const char *filename ); void CL_WriteUsercmd( sizebuf_t *msg, int from, int to ); +int CL_GetFragmentSize( void *unused ); qboolean CL_PrecacheResources( void ); void CL_SetupOverviewParams( void ); void CL_UpdateFrameLerp( void ); @@ -935,8 +938,9 @@ void CL_TestLights( void ); void CL_DrawParticlesExternal( const ref_viewpass_t *rvp, qboolean trans_pass, float frametime ); void CL_FireCustomDecal( int textureIndex, int entityIndex, int modelIndex, float *pos, int flags, float scale ); void CL_DecalShoot( int textureIndex, int entityIndex, int modelIndex, float *pos, int flags ); -void CL_PlayerDecal( int textureIndex, int entityIndex, float *pos ); +void CL_PlayerDecal( int playerIndex, int textureIndex, int entityIndex, float *pos ); void R_FreeDeadParticles( struct particle_s **ppparticles ); +void CL_AddClientResource( const char *filename, int type ); void CL_AddClientResources( void ); int CL_FxBlend( cl_entity_t *e ); void CL_InitParticles( void ); diff --git a/engine/client/gl_alias.c b/engine/client/gl_alias.c index 0acd4bc2..f2190134 100644 --- a/engine/client/gl_alias.c +++ b/engine/client/gl_alias.c @@ -1079,7 +1079,7 @@ void GL_DrawAliasFrame( aliashdr_t *paliashdr ) } else { - pglTexCoord2f (((float *)order)[0], ((float *)order)[1]); + pglTexCoord2f( ((float *)order)[0], ((float *)order)[1] ); } order += 2; diff --git a/engine/client/gl_decals.c b/engine/client/gl_decals.c index 20718e32..cfba6f4f 100644 --- a/engine/client/gl_decals.c +++ b/engine/client/gl_decals.c @@ -146,7 +146,7 @@ static void R_GetDecalDimensions( int texture, int *width, int *height ) //----------------------------------------------------------------------------- // compute the decal basis based on surface normal //----------------------------------------------------------------------------- -void R_DecalComputeBasis( msurface_t *surf, vec3_t textureSpaceBasis[3] ) +void R_DecalComputeBasis( msurface_t *surf, int flags, vec3_t textureSpaceBasis[3] ) { vec3_t surfaceNormal; @@ -155,9 +155,31 @@ void R_DecalComputeBasis( msurface_t *surf, vec3_t textureSpaceBasis[3] ) VectorNegate( surf->plane->normal, surfaceNormal ); else VectorCopy( surf->plane->normal, surfaceNormal ); + VectorNormalize2( surfaceNormal, textureSpaceBasis[2] ); +#if 0 + if( FBitSet( flags, FDECAL_CUSTOM )) + { + vec3_t pSAxis = { 1, 0, 0 }; + + // T = S cross N + CrossProduct( pSAxis, textureSpaceBasis[2], textureSpaceBasis[1] ); + + // Name sure they aren't parallel or antiparallel + // In that case, fall back to the normal algorithm. + if( DotProduct( textureSpaceBasis[1], textureSpaceBasis[1] ) > 1e-6 ) + { + // S = N cross T + CrossProduct( textureSpaceBasis[2], textureSpaceBasis[1], textureSpaceBasis[0] ); + + VectorNormalizeFast( textureSpaceBasis[0] ); + VectorNormalizeFast( textureSpaceBasis[1] ); + return; + } + // Fall through to the standard algorithm for parallel or antiparallel + } +#endif VectorNormalize2( surf->texinfo->vecs[0], textureSpaceBasis[0] ); VectorNormalize2( surf->texinfo->vecs[1], textureSpaceBasis[1] ); - VectorNormalize2( surfaceNormal, textureSpaceBasis[2] ); } void R_SetupDecalTextureSpaceBasis( decal_t *pDecal, msurface_t *surf, int texture, vec3_t textureSpaceBasis[3], float decalWorldScale[2] ) @@ -165,7 +187,7 @@ void R_SetupDecalTextureSpaceBasis( decal_t *pDecal, msurface_t *surf, int textu int width, height; // Compute the non-scaled decal basis - R_DecalComputeBasis( surf, textureSpaceBasis ); + R_DecalComputeBasis( surf, pDecal->flags, textureSpaceBasis ); R_GetDecalDimensions( texture, &width, &height ); // world width of decal = ptexture->width / pDecal->scale @@ -427,7 +449,7 @@ static decal_t *R_DecalIntersect( decalinfo_t *decalinfo, msurface_t *surf, int // Don't steal bigger decals and replace them with smaller decals // Don't steal permanent decals - if(!( pDecal->flags & FDECAL_PERMANENT )) + if( !FBitSet( pDecal->flags, FDECAL_PERMANENT )) { vec3_t testBasis[3]; vec3_t testPosition[2]; @@ -624,7 +646,7 @@ void R_DecalSurface( msurface_t *surf, decalinfo_t *decalinfo ) // Determine the decal basis (measured in world space) // Note that the decal basis vectors 0 and 1 will always lie in the same // plane as the texture space basis vectorstextureVecsTexelsPerWorldUnits. - R_DecalComputeBasis( surf, decalinfo->m_Basis ); + R_DecalComputeBasis( surf, decalinfo->m_Flags, decalinfo->m_Basis ); // Compute an effective width and height (axis aligned) in the parent texture space // How does this work? decalBasis[0] represents the u-direction (width) @@ -1151,7 +1173,7 @@ int R_CreateDecalList( decallist_t *pList ) decal_t *pdecals; // decal is in use and is not a custom decal - if( decal->psurface == NULL || FBitSet( decal->flags, FDECAL_DONTSAVE )) + if( decal->psurface == NULL || ( decal->flags & FDECAL_DONTSAVE )) continue; // compute depth diff --git a/engine/client/s_main.c b/engine/client/s_main.c index 733cd90d..7006845d 100644 --- a/engine/client/s_main.c +++ b/engine/client/s_main.c @@ -946,7 +946,7 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv VOX_LoadSound( target_chan, S_SkipSoundChar( sfx->name )); Q_strncpy( target_chan->name, sfx->name, sizeof( target_chan->name )); sfx = target_chan->sfx; - pSource = sfx->cache; + if( sfx ) pSource = sfx->cache; } else { @@ -1092,7 +1092,7 @@ void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float else { sfx = target_chan->sfx; - pSource = sfx->cache; + if( sfx ) pSource = sfx->cache; } } else @@ -1183,7 +1183,7 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa VOX_LoadSound( ch, S_SkipSoundChar( sfx->name )); Q_strncpy( ch->name, sfx->name, sizeof( ch->name )); sfx = ch->sfx; - pSource = sfx->cache; + if( sfx ) pSource = sfx->cache; fvox = 1; } else diff --git a/engine/common/custom.c b/engine/common/custom.c index 60117982..027b92cd 100644 --- a/engine/common/custom.c +++ b/engine/common/custom.c @@ -32,24 +32,24 @@ qboolean CustomDecal_Validate( void *raw, int nFileSize ) void COM_ClearCustomizationList( customization_t *pHead, qboolean bCleanDecals ) { - customization_t *pNext, *pCurrent; + customization_t *pCurrent; + customization_t *pNext; - for( pCurrent = pHead->pNext; pCurrent; pCurrent = pNext ) + for( pCurrent = pHead->pNext; pCurrent != NULL; pCurrent = pNext ) { pNext = pCurrent->pNext; if( pCurrent->bInUse && pCurrent->pBuffer ) - { Mem_Free( pCurrent->pBuffer ); - } if( pCurrent->bInUse && pCurrent->pInfo ) { if( pCurrent->resource.type == t_decal ) { if( bCleanDecals && CL_Active( )) - R_DecalRemoveAll( ~pCurrent->resource.playernum ); + R_DecalRemoveAll( pCurrent->nUserData1 ); } + FS_FreeImage( pCurrent->pInfo ); } Mem_Free( pCurrent ); @@ -60,9 +60,9 @@ void COM_ClearCustomizationList( customization_t *pHead, qboolean bCleanDecals ) qboolean COM_CreateCustomization( customization_t *pListHead, resource_t *pResource, int playernumber, int flags, customization_t **pOut, int *nLumps ) { - customization_t *pCust; qboolean bError = false; - void *pNewBuffer = NULL; + int checksize = 0; + customization_t *pCust; if( pOut ) *pOut = NULL; @@ -81,9 +81,10 @@ qboolean COM_CreateCustomization( customization_t *pListHead, resource_t *pResou } else { - int checksize = 0; - pCust->pBuffer = COM_LoadFile( pResource->szFileName, 5, &checksize ); - Msg( "loading %s, check %d, downoad %d\n", pResource->szFileName, checksize, pCust->resource.nDownloadSize ); + + pCust->pBuffer = FS_LoadFile( pResource->szFileName, &checksize, true ); + if( checksize != pCust->resource.nDownloadSize ) + bError = true; } if( bError ) @@ -99,6 +100,10 @@ qboolean COM_CreateCustomization( customization_t *pListHead, resource_t *pResou { if( pResource->nDownloadSize >= (1 * 1024) && pResource->nDownloadSize <= ( 16 * 1024 )) { + pCust->bTranslated = true; + pCust->nUserData1 = 0; + pCust->nUserData2 = 1; + if( !FBitSet( flags, FCUST_WIPEDATA )) pCust->pInfo = FS_LoadImage( "#logo.bmp", pCust->pBuffer, pCust->resource.nDownloadSize ); else pCust->pInfo = NULL; diff --git a/engine/common/host.c b/engine/common/host.c index 0d4debad..758e252a 100644 --- a/engine/common/host.c +++ b/engine/common/host.c @@ -850,6 +850,7 @@ void Host_FreeCommon( void ) Image_Shutdown(); Sound_Shutdown(); Netchan_Shutdown(); + HPAK_FlushHostQueue(); FS_Shutdown(); Mem_FreePool( &host.mempool ); diff --git a/engine/common/hpak.c b/engine/common/hpak.c index 8d7fd138..c493d8b1 100644 --- a/engine/common/hpak.c +++ b/engine/common/hpak.c @@ -71,8 +71,9 @@ void HPAK_FlushHostQueue( void ) { hash_pack_queue_t *p; - for( p = gp_hpak_queue; p != NULL; p = p->next ) + for( p = gp_hpak_queue; p != NULL; p = gp_hpak_queue ) { + gp_hpak_queue = p->next; HPAK_AddLump( false, p->name, &p->resource, p->data, NULL ); freestring( p->name ); Mem_Free( p->data ); @@ -193,9 +194,9 @@ static qboolean HPAK_FindResource( hpak_info_t *hpk, byte *hash, resource_t *pRe void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource, byte *pData, file_t *pFile ) { int i, j, position, length; + hpak_lump_t *pCurrentEntry = NULL; string srcname, dstname; hpak_info_t srcpak, dstpak; - hpak_lump_t *pCurrentEntry; file_t *file_src; file_t *file_dst; char md5[16]; @@ -318,7 +319,7 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource, for( i = 0; i < srcpak.count; i++ ) { - if( memcmp( md5, srcpak.entries[i].resource.rgucMD5_hash, 16 ) < 0 ) + if( memcmp( md5, srcpak.entries[i].resource.rgucMD5_hash, 16 )) { pCurrentEntry = &dstpak.entries[i]; @@ -516,7 +517,7 @@ qboolean HPAK_ResourceForHash( const char *filename, byte *hash, resource_t *pRe file_t *f; hash_pack_queue_t *p; - if( !filename || !filename[0] ) + if( !COM_CheckString( filename )) return false; for( p = gp_hpak_queue; p != NULL; p = p->next ) @@ -639,7 +640,7 @@ qboolean HPAK_GetDataPointer( const char *filename, resource_t *pResource, byte file_t *f; int i; - if( !filename || !filename[0] ) + if( !COM_CheckString( filename )) return false; if( buffer ) *buffer = NULL; diff --git a/engine/common/imagelib/img_bmp.c b/engine/common/imagelib/img_bmp.c index 26f91e3f..1f4de1e2 100644 --- a/engine/common/imagelib/img_bmp.c +++ b/engine/common/imagelib/img_bmp.c @@ -88,7 +88,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize ) return false; // special hack for loading qfont - if( !Q_strncmp( "#XASH_SYSTEMFONT_001", name, 20 )) + if( !Q_strncmp( name, "#XASH_SYSTEMFONT_001", 20 )) { // NOTE: same as system font we can use 4-bit bmps only // step1: move main layer into alpha-channel (give grayscale from RED channel) @@ -112,6 +112,14 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize ) memcpy( palette, buf_p, cbPalBytes ); + // setup gradient alpha for player decal + if( !Q_strncmp( name, "#logo", 5 )) + { + for( i = 0; i < bhdr.colors; i++ ) + palette[i][3] = i; + image.flags |= IMAGE_HAS_ALPHA; + } + if( host.overview_loading && bhdr.bitsPerPixel == 8 ) { // convert green background into alpha-layer, make opacity for all other entries @@ -129,8 +137,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize ) if( Image_CheckFlag( IL_KEEP_8BIT ) && bhdr.bitsPerPixel == 8 ) { pixbuf = image.palette = Mem_Alloc( host.imagepool, 1024 ); - image.flags |= IMAGE_HAS_COLOR; - + // bmp have a reversed palette colors for( i = 0; i < bhdr.colors; i++ ) { diff --git a/engine/common/net_buffer.c b/engine/common/net_buffer.c index 1b14f6d2..842c2c73 100644 --- a/engine/common/net_buffer.c +++ b/engine/common/net_buffer.c @@ -106,9 +106,29 @@ qboolean MSG_CheckOverflow( sizebuf_t *sb ) return MSG_Overflow( sb, 0 ); } -void MSG_SeekToBit( sizebuf_t *sb, int bitPos ) +int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence ) { + // compute the file offset + switch( whence ) + { + case SEEK_CUR: + bitPos += sb->iCurBit; + break; + case SEEK_SET: + break; + case SEEK_END: + bitPos += sb->nDataBits; + break; + default: + return -1; + } + + if( bitPos < 0 || bitPos > sb->nDataBits ) + return -1; + sb->iCurBit = bitPos; + + return 0; } void MSG_SeekToByte( sizebuf_t *sb, int bytePos ) @@ -656,13 +676,13 @@ void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove ) sizebuf_t temp; MSG_StartWriting( &temp, sb->pData, MSG_GetMaxBytes( sb ), startbit, -1 ); - MSG_SeekToBit( sb, endbit ); + MSG_SeekToBit( sb, endbit, SEEK_SET ); for( i = 0; i < remaining_to_end; i++ ) { MSG_WriteOneBit( &temp, MSG_ReadOneBit( sb )); } - MSG_SeekToBit( sb, startbit ); + MSG_SeekToBit( sb, startbit, SEEK_SET ); sb->nDataBits -= bitstoremove; } \ No newline at end of file diff --git a/engine/common/net_buffer.h b/engine/common/net_buffer.h index 08b8668a..356cdaa5 100644 --- a/engine/common/net_buffer.h +++ b/engine/common/net_buffer.h @@ -58,10 +58,10 @@ typedef struct sizebuf_s // common functions void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits ); void MSG_InitMasks( void ); // called once at startup engine -void MSG_SeekToBit( sizebuf_t *sb, int bitPos ); -void MSG_SeekToByte( sizebuf_t *sb, int bytePos ); +int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence ); void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove ); _inline int MSG_TellBit( sizebuf_t *sb ) { return sb->iCurBit; } +_inline const char *MSG_GetName( sizebuf_t *sb ) { return sb->pDebugName; } qboolean MSG_CheckOverflow( sizebuf_t *sb ); short MSG_BigShort( short swap ); diff --git a/engine/common/net_chan.c b/engine/common/net_chan.c index bf10ab54..e434eba4 100644 --- a/engine/common/net_chan.c +++ b/engine/common/net_chan.c @@ -27,11 +27,7 @@ GNU General Public License for more details. #define FLOW_AVG ( 2.0 / 3.0 ) // how fast to converge flow estimates #define FLOW_INTERVAL 0.1 // don't compute more often than this - -#define MAX_RELIABLE_PAYLOAD 32768 // biggest packet that has frag and or reliable data -#define MAX_RELIABLE_PAYLOAD_BITS (MAX_RELIABLE_PAYLOAD<<3) -#define MAX_RESEND_PAYLOAD 36000 -#define MAX_RESEND_PAYLOAD_BITS (MAX_RESEND_PAYLOAD<<3) +#define MAX_RELIABLE_PAYLOAD 1400 // biggest packet that has frag and or reliable data // forward declarations void Netchan_FlushIncoming( netchan_t *chan, int stream ); @@ -98,7 +94,7 @@ int net_drop; netadr_t net_from; sizebuf_t net_message; byte *net_mempool; -byte net_message_buffer[MAX_INIT_MSG]; +byte net_message_buffer[NET_MAX_MESSAGE]; const char *ns_strings[NS_COUNT] = { @@ -126,7 +122,7 @@ void Netchan_Init( void ) net_mempool = Mem_AllocPool( "Network Pool" ); - MSG_InitMasks (); // initialize bit-masks + MSG_InitMasks(); // initialize bit-masks } void Netchan_Shutdown( void ) @@ -159,10 +155,8 @@ detect a loopback message */ qboolean Netchan_IsLocal( netchan_t *chan ) { -#if 0 // FIXME if( !NET_IsActive() || NET_IsLocalAddress( chan->remote_address )) return true; -#endif return false; } @@ -219,10 +213,10 @@ Netchan_CanPacket Returns true if the bandwidth choke isn't active ================ */ -qboolean Netchan_CanPacket( netchan_t *chan ) +qboolean Netchan_CanPacket( netchan_t *chan, qboolean choke ) { // never choke loopback packets. - if( !net_chokeloopback->value && NET_IsLocalAddress( chan->remote_address )) + if( !choke || !net_chokeloopback->value && NET_IsLocalAddress( chan->remote_address )) { chan->cleartime = host.realtime; return true; @@ -241,11 +235,7 @@ void Netchan_UnlinkFragment( fragbuf_t *buf, fragbuf_t **list ) { fragbuf_t *search; - if( !list ) - { - MsgDev( D_ERROR, "Netchan_UnlinkFragment: Asked to unlink fragment from empty list, ignored\n" ); - return; - } + if( !list ) return; // at head of list if( buf == *list ) @@ -271,9 +261,8 @@ void Netchan_UnlinkFragment( fragbuf_t *buf, fragbuf_t **list ) } search = search->next; } - - MsgDev( D_ERROR, "Netchan_UnlinkFragment: Couldn't find fragment\n" ); } + /* ============================== Netchan_ClearFragbufs @@ -372,8 +361,8 @@ Sends an out-of-band datagram */ void Netchan_OutOfBand( int net_socket, netadr_t adr, int length, byte *data ) { + byte send_buf[MAX_PRINT_MSG]; sizebuf_t send; - byte send_buf[NET_MAX_PAYLOAD]; // write the packet header MSG_Init( &send, "SequencePacket", send_buf, sizeof( send_buf )); @@ -397,8 +386,8 @@ Sends a text message in an out-of-band datagram */ void Netchan_OutOfBandPrint( int net_socket, netadr_t adr, char *format, ... ) { - static char string[MAX_PRINT_MSG]; - va_list argptr; + char string[MAX_PRINT_MSG]; + va_list argptr; va_start( argptr, format ); Q_vsnprintf( string, sizeof( string ) - 1, format, argptr ); @@ -578,7 +567,7 @@ static void Netchan_CreateFragments_( netchan_t *chan, sizebuf_t *msg ) fragbuf_t *buf; int chunksize; int remaining; - int bits, pos; + int bytes, pos; int bufferid = 1; fragbufwaiting_t *wait, *p; @@ -587,38 +576,27 @@ static void Netchan_CreateFragments_( netchan_t *chan, sizebuf_t *msg ) if( chan->pfnBlockSize != NULL ) chunksize = chan->pfnBlockSize( chan->client ); - else chunksize = FRAGMENT_SV2CL_MAX_SIZE; - -chunksize = 8192; + else chunksize = FRAGMENT_MAX_SIZE; // fallback wait = (fragbufwaiting_t *)Mem_Alloc( net_mempool, sizeof( fragbufwaiting_t )); - remaining = MSG_GetNumBitsWritten( msg ); - chunksize <<= 3; // convert bytes to bits - pos = 0; // current position in bits + remaining = MSG_GetNumBytesWritten( msg ); + pos = 0; // current position in bytes while( remaining > 0 ) { - byte buffer[NET_MAX_PAYLOAD]; - sizebuf_t temp; - - bits = Q_min( remaining, chunksize ); - remaining -= bits; + bytes = Q_min( remaining, chunksize ); + remaining -= bytes; buf = Netchan_AllocFragbuf(); buf->bufferid = bufferid++; // Copy in data MSG_Clear( &buf->frag_message ); - - MSG_StartReading( &temp, MSG_GetData( msg ), MSG_GetMaxBytes( msg ), MSG_GetNumBitsWritten( msg ), -1 ); - MSG_SeekToBit( &temp, pos ); - - MSG_ReadBits( &temp, buffer, bits ); - MSG_WriteBits( &buf->frag_message, buffer, bits ); + MSG_WriteBits( &buf->frag_message, &msg->pData[pos], bytes << 3 ); Netchan_AddFragbufToTail( wait, buf ); - pos += bits; + pos += bytes; } // now add waiting list item to end of buffer queue @@ -747,10 +725,9 @@ void Netchan_CreateFileFragmentsFromBuffer( netchan_t *chan, char *filename, byt if( chan->pfnBlockSize != NULL ) chunksize = chan->pfnBlockSize( chan->client ); - else chunksize = FRAGMENT_SV2CL_MAX_SIZE; - - wait = ( fragbufwaiting_t * )Mem_Alloc( net_mempool, sizeof( fragbufwaiting_t )); + else chunksize = FRAGMENT_MAX_SIZE; // fallback + wait = (fragbufwaiting_t *)Mem_Alloc( net_mempool, sizeof( fragbufwaiting_t )); remaining = size; pos = 0; @@ -766,13 +743,13 @@ void Netchan_CreateFileFragmentsFromBuffer( netchan_t *chan, char *filename, byt if( firstfragment ) { - firstfragment = false; - // write filename MSG_WriteString( &buf->frag_message, filename ); // send a bit less on first package send -= MSG_GetNumBytesWritten( &buf->frag_message ); + + firstfragment = false; } buf->isbuffer = true; @@ -782,8 +759,8 @@ void Netchan_CreateFileFragmentsFromBuffer( netchan_t *chan, char *filename, byt MSG_WriteBits( &buf->frag_message, pbuf + pos, send << 3 ); - pos += send; remaining -= send; + pos += send; Netchan_AddFragbufToTail( wait, buf ); } @@ -798,9 +775,7 @@ void Netchan_CreateFileFragmentsFromBuffer( netchan_t *chan, char *filename, byt p = chan->waitlist[FRAG_FILE_STREAM]; while( p->next ) - { p = p->next; - } p->next = wait; } } @@ -822,17 +797,16 @@ int Netchan_CreateFileFragments( netchan_t *chan, const char *filename ) fragbufwaiting_t *wait, *p; fragbuf_t *buf; - if( chan->pfnBlockSize != NULL ) - chunksize = chan->pfnBlockSize( chan->client ); - else chunksize = FRAGMENT_SV2CL_MAX_SIZE; - filesize = FS_FileSize( filename, false ); -chunksize = 32768; - if( filesize <= 0 ) + if(( filesize = FS_FileSize( filename, false )) <= 0 ) { - MsgDev( D_WARN, "Unable to open %s for transfer\n", filename ); + Con_Printf( S_WARN "Unable to open %s for transfer\n", filename ); return 0; } + if( chan->pfnBlockSize != NULL ) + chunksize = chan->pfnBlockSize( chan->client ); + else chunksize = FRAGMENT_MAX_SIZE; // fallback + wait = (fragbufwaiting_t *)Mem_Alloc( net_mempool, sizeof( fragbufwaiting_t )); remaining = filesize; pos = 0; @@ -849,13 +823,13 @@ chunksize = 32768; if( firstfragment ) { - firstfragment = false; - // Write filename MSG_WriteString( &buf->frag_message, filename ); // Send a bit less on first package send -= MSG_GetNumBytesWritten( &buf->frag_message ); + + firstfragment = false; } buf->isfile = true; @@ -878,10 +852,7 @@ chunksize = 32768; { p = chan->waitlist[FRAG_FILE_STREAM]; while( p->next ) - { p = p->next; - } - p->next = wait; } @@ -896,11 +867,12 @@ Netchan_FlushIncoming */ void Netchan_FlushIncoming( netchan_t *chan, int stream ) { - fragbuf_t *p, *n; + fragbuf_t *p, *n; MSG_Clear( &net_message ); p = chan->incomingbufs[ stream ]; + while( p ) { n = p->next; @@ -919,7 +891,7 @@ Netchan_CopyNormalFragments */ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *length ) { - size_t frag_num_bits = 0; + size_t size = 0; fragbuf_t *p, *n; if( !chan->incomingready[FRAG_NORMAL_STREAM] ) @@ -927,7 +899,6 @@ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *l if( !chan->incomingbufs[FRAG_NORMAL_STREAM] ) { - MsgDev( D_ERROR, "Netchan_CopyNormalFragments: Called with no fragments readied\n" ); chan->incomingready[FRAG_NORMAL_STREAM] = false; return false; } @@ -941,8 +912,8 @@ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *l n = p->next; // copy it in - MSG_WriteBits( msg, MSG_GetData( &p->frag_message ), MSG_GetNumBitsWritten( &p->frag_message )); - frag_num_bits += MSG_GetNumBitsWritten( &p->frag_message ); + MSG_WriteBytes( msg, MSG_GetData( &p->frag_message ), MSG_GetNumBytesWritten( &p->frag_message )); + size += MSG_GetNumBytesWritten( &p->frag_message ); Mem_Free( p ); p = n; @@ -954,7 +925,7 @@ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *l chan->incomingready[FRAG_NORMAL_STREAM] = false; // tell about message size - if( length ) *length = BitByte( frag_num_bits ); + if( length ) *length = size; return true; } @@ -967,18 +938,16 @@ Netchan_CopyFileFragments */ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg ) { - fragbuf_t *p, *n; - char filename[MAX_QPATH]; - int nsize; + char filename[MAX_OSPATH]; + int nsize, pos; byte *buffer; - int pos; + fragbuf_t *p, *n; if( !chan->incomingready[FRAG_FILE_STREAM] ) return false; if( !chan->incomingbufs[FRAG_FILE_STREAM] ) { - MsgDev( D_WARN, "Netchan_CopyFileFragments: Called with no fragments readied\n" ); chan->incomingready[FRAG_FILE_STREAM] = false; return false; } @@ -988,42 +957,20 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg ) MSG_Init( msg, "NetMessage", net_message_buffer, sizeof( net_message_buffer )); // copy in first chunk so we can get filename out - MSG_WriteBits( msg, MSG_GetData( &p->frag_message ), MSG_GetNumBitsWritten( &p->frag_message )); - MSG_SeekToBit( msg, 0 ); // rewind buffer + MSG_WriteBytes( msg, MSG_GetData( &p->frag_message ), MSG_GetNumBytesWritten( &p->frag_message )); + MSG_Clear( msg ); Q_strncpy( filename, MSG_ReadString( msg ), sizeof( filename )); - if( Q_strlen( filename ) <= 0 ) + if( !COM_CheckString( filename )) { - MsgDev( D_ERROR, "File fragment received with no filename\nFlushing input queue\n" ); - - // clear out bufs + Con_Printf( S_ERROR "file fragment received with no filename\nFlushing input queue\n" ); Netchan_FlushIncoming( chan, FRAG_FILE_STREAM ); return false; } - else if( Q_strstr( filename, ".." )) + else if( filename[0] != '!' && !COM_IsSafeFileToDownload( filename )) { - MsgDev( D_ERROR, "File fragment received with relative path, ignoring\n" ); - - // clear out bufs - Netchan_FlushIncoming( chan, FRAG_FILE_STREAM ); - return false; - } - - if( filename[0] != '!' && !COM_IsSafeFileToDownload( filename )) - { - Con_Printf( "File fragment received with bad path, ignoring\n" ); - - // Clear out bufs - Netchan_FlushIncoming( chan, FRAG_FILE_STREAM ); - return false; - } - - if( host.type == HOST_DEDICATED && filename[0] != '!' ) - { - Con_Printf( "File fragment received with bad path, ignoring (2)\n" ); - - // Clear out bufs + Con_Printf( S_ERROR "file fragment received with bad path, ignoring\n" ); Netchan_FlushIncoming( chan, FRAG_FILE_STREAM ); return false; } @@ -1032,9 +979,7 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg ) if( filename[0] != '!' && FS_FileExists( filename, false )) { - MsgDev( D_ERROR, "Can't download %s, already exists\n", filename ); - - // clear out bufs + Con_Printf( S_ERROR "can't download %s, already exists\n", filename ); Netchan_FlushIncoming( chan, FRAG_FILE_STREAM ); return true; } @@ -1045,14 +990,12 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg ) { nsize += MSG_GetNumBytesWritten( &p->frag_message ); // Size will include a bit of slop, oh well if( p == chan->incomingbufs[FRAG_FILE_STREAM] ) - { nsize -= MSG_GetNumBytesRead( msg ); - } p = p->next; } buffer = Mem_Alloc( net_mempool, nsize + 1 ); - p = chan->incomingbufs[ FRAG_FILE_STREAM ]; + p = chan->incomingbufs[FRAG_FILE_STREAM]; pos = 0; while( p ) @@ -1077,19 +1020,15 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg ) } pos += cursize; - Mem_Free( p ); p = n; } + // customization files goes int tempbuffer if( filename[0] == '!' ) { if( chan->tempbuffer ) - { - Con_DPrintf( "Netchan_CopyFragments: Freeing holdover tempbuffer\n" ); Mem_Free( chan->tempbuffer ); - } - chan->tempbuffer = buffer; chan->tempbuffersize = nsize; } @@ -1104,8 +1043,6 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg ) MSG_Clear( msg ); chan->incomingbufs[FRAG_FILE_STREAM] = NULL; - - // reset flag chan->incomingready[FRAG_FILE_STREAM] = false; return true; @@ -1116,8 +1053,6 @@ qboolean Netchan_Validate( netchan_t *chan, sizebuf_t *sb, qboolean *frag_messag int i, buffer, offset; int count, length; -return true; - for( i = 0; i < MAX_STREAMS; i++ ) { if( !frag_message[i] ) @@ -1128,16 +1063,16 @@ return true; offset = BitByte( frag_offset[i] ); length = BitByte( frag_length[i] ); - if( buffer < 0 || buffer > 25000 ) + if( buffer < 0 || buffer > NET_MAX_BUFFER_ID ) return false; - if( count < 0 || count > 25000 ) + if( count < 0 || count > NET_MAX_BUFFERS_COUNT ) return false; - if( length < 0 || length > 2048 ) + if( length < 0 || length > ( FRAGMENT_MAX_SIZE << 3 )) return false; - if( offset < 0 || offset > 16384 ) + if( offset < 0 || offset > ( FRAGMENT_MAX_SIZE << 3 )) return false; } @@ -1242,20 +1177,18 @@ A 0 length will still generate a packet and deal with the reliable messages. */ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data ) { - sizebuf_t send; - int max_send_size, statId; byte send_buf[NET_MAX_MESSAGE]; qboolean send_reliable_fragment; - qboolean send_resending = false; + uint w1, w2, statId; qboolean send_reliable; - uint w1, w2; + sizebuf_t send; int i, j; float fRate; // check for message overflow if( MSG_CheckOverflow( &chan->message )) { - MsgDev( D_ERROR, "%s:outgoing message overflow\n", NET_AdrToString( chan->remote_address )); + Con_Printf( S_ERROR "%s:outgoing message overflow\n", NET_AdrToString( chan->remote_address )); return; } @@ -1263,10 +1196,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data ) send_reliable = false; if( chan->incoming_acknowledged > chan->last_reliable_sequence && chan->incoming_reliable_acknowledged != chan->reliable_sequence ) - { send_reliable = true; - send_resending = true; - } // A packet can have "reliable payload + frag payload + unreliable payload // frag payload can be a file chunk, if so, it needs to be parsed on the receiving end and reliable payload + unreliable payload need @@ -1281,7 +1211,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data ) // will be true if we are active and should let chan->message get some bandwidth int send_from_frag[MAX_STREAMS] = { 0, 0 }; - int send_from_regular = false; + int send_from_regular = 0; // if we have data in the waiting list(s) and we have cleared the current queue(s), then // push the waitlist(s) into the current queue(s) @@ -1303,7 +1233,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data ) send_from_regular = false; // if the reliable buffer has gotten too big, queue it at the end of everything and clear out buffer - if( MSG_GetNumBitsWritten( &chan->message ) > MAX_RELIABLE_PAYLOAD_BITS ) + if( MSG_GetNumBytesWritten( &chan->message ) > MAX_RELIABLE_PAYLOAD ) { Netchan_CreateFragments_( chan, &chan->message ); MSG_Clear( &chan->message ); @@ -1345,6 +1275,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data ) for( i = 0; i < MAX_STREAMS; i++ ) { + int newpayloadsize; int fragment_size; // is there someting in the fragbuf? @@ -1353,7 +1284,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data ) if( pbuf ) { - fragment_size = MSG_GetNumBitsWritten( &pbuf->frag_message ); + fragment_size = MSG_GetNumBytesWritten( &pbuf->frag_message ); // files set size a bit differently. if( pbuf->isfile && !pbuf->isbuffer ) @@ -1362,8 +1293,10 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data ) } } + newpayloadsize = (( chan->reliable_length + ( fragment_size << 3 )) + 7 ) >> 3; + // make sure we have enought space left - if( send_from_frag[i] && pbuf && (( chan->reliable_length + fragment_size ) < MAX_RELIABLE_PAYLOAD_BITS )) + if( send_from_frag[i] && pbuf && newpayloadsize < NET_MAX_FRAGMENT ) { sizebuf_t temp; @@ -1373,7 +1306,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data ) // if it's not in-memory, then we'll need to copy it in frame the file handle. if( pbuf->isfile && !pbuf->isbuffer ) { - byte filebuffer[NET_MAX_PAYLOAD]; + byte filebuffer[NET_MAX_FRAGMENT]; file_t *file; file = FS_Open( pbuf->filename, "rb", false ); @@ -1430,7 +1363,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data ) // send the qport if we are a client if( chan->sock == NS_CLIENT ) { - MSG_WriteWord( &send, Cvar_VariableValue( "net_qport" )); + MSG_WriteWord( &send, Cvar_VariableInteger( "net_qport" )); } if( send_reliable && send_reliable_fragment ) @@ -1458,14 +1391,9 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data ) chan->last_reliable_sequence = chan->outgoing_sequence - 1; } - // is there room for the unreliable payload? - max_send_size = MAX_RESEND_PAYLOAD_BITS; - if( !send_resending ) - max_send_size = MSG_GetMaxBits( &send ); - - if(( max_send_size - MSG_GetNumBitsWritten( &send )) >= length ) + if( MSG_GetNumBitsLeft( &send ) >= length ) MSG_WriteBits( &send, data, length ); - else MsgDev( D_WARN, "Netchan_Transmit: unreliable message overflow\n" ); + else Con_Printf( S_WARN "Netchan_Transmit: unreliable message overflow\n" ); // deal with packets that are too small for some networks if( MSG_GetNumBytesWritten( &send ) < 16 && !NET_IsLocalAddress( chan->remote_address )) // packet too small for some networks @@ -1477,6 +1405,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data ) MSG_BeginClientCmd( &send, clc_nop ); else if( chan->sock == NS_SERVER ) MSG_BeginServerCmd( &send, svc_nop ); + else break; } } @@ -1496,24 +1425,22 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data ) NET_SendPacket( chan->sock, MSG_GetNumBytesWritten( &send ), MSG_GetData( &send ), chan->remote_address ); } - fRate = 1.0f / chan->rate; + if( SV_Active() && sv_lan.value && sv_lan_rate.value > 1000.0 ) + fRate = 1.0f / sv_lan_rate.value; + else fRate = 1.0f / chan->rate; if( chan->cleartime < host.realtime ) chan->cleartime = host.realtime; chan->cleartime += ( MSG_GetNumBytesWritten( &send ) + UDP_HEADER_SIZE ) * fRate; - if( net_showpackets->value == 1.0f ) + if( net_showpackets->value && net_showpackets->value != 2.0f ) { - char c; - - c = ( chan->sock == NS_CLIENT ) ? 'c' : 's'; - - Con_Printf( " %c --> sz=%i seq=%i ack=%i rel=%i tm=%f\n" - , c + Con_Printf( " %s --> sz=%i seq=%i ack=%i rel=%i tm=%f\n" + , ns_strings[chan->sock] , MSG_GetNumBytesWritten( &send ) - , ( chan->outgoing_sequence - 1 ) - , chan->incoming_sequence + , ( chan->outgoing_sequence - 1 ) & 63 + , chan->incoming_sequence & 63 , send_reliable ? 1 : 0 , (float)host.realtime ); } @@ -1556,8 +1483,6 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg ) if( !CL_IsPlaybackDemo() && !NET_CompareAdr( net_from, chan->remote_address )) return false; - chan->last_received = host.realtime; - // get sequence numbers MSG_Clear( msg ); sequence = MSG_ReadLong( msg ); @@ -1594,17 +1519,13 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg ) sequence_ack &= ~BIT( 30 ); sequence_ack &= ~BIT( 31 ); - if( net_showpackets->value == 2.0f ) + if( net_showpackets->value && net_showpackets->value != 3.0f ) { - char c; - - c = ( chan->sock == NS_CLIENT ) ? 'c' : 's'; - - Con_Printf( " %c <-- sz=%i seq=%i ack=%i rel=%i tm=%f\n" - , c + Con_Printf( " %s <-- sz=%i seq=%i ack=%i rel=%i tm=%f\n" + , ns_strings[chan->sock] , MSG_GetMaxBytes( msg ) - , sequence - , sequence_ack + , sequence & 63 + , sequence_ack & 63 , reliable_message , host.realtime ); } @@ -1626,7 +1547,7 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg ) // dropped packets don't keep the message from being used net_drop = sequence - ( chan->incoming_sequence + 1 ); if( net_drop > 0 && net_showdrop->value ) - Con_Printf( "%s:Dropped %i packets at %i\n", NET_AdrToString( chan->remote_address ), sequence - (chan->incoming_sequence + 1), sequence ); + Con_Printf( "%s:dropped %i packets at %i\n", NET_AdrToString( chan->remote_address ), net_drop, sequence ); // if the current outgoing reliable message has been acknowledged // clear the buffer to make way for the next @@ -1648,6 +1569,8 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg ) chan->incoming_reliable_sequence ^= 1; } + chan->last_received = host.realtime; + // Update data flow stats statId = chan->flow[FLOW_INCOMING].current & MASK_LATENT; chan->flow[FLOW_INCOMING].stats[statId].size = MSG_GetMaxBytes( msg ) + UDP_HEADER_SIZE; @@ -1663,11 +1586,11 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg ) { for( i = 0; i < MAX_STREAMS; i++ ) { - fragbuf_t *pbuf; int j, inbufferid; int intotalbuffers; int oldpos, curbit; int numbitstoremove; + fragbuf_t *pbuf; if( !frag_message[i] ) continue; @@ -1681,23 +1604,20 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg ) if( pbuf ) { - byte buffer[NET_MAX_PAYLOAD]; + byte buffer[NET_MAX_FRAGMENT]; + int bits, size; sizebuf_t temp; - int bits; + size = MSG_GetNumBitsRead( msg ) + frag_offset[i]; bits = frag_length[i]; // copy in data MSG_Clear( &pbuf->frag_message ); - MSG_StartReading( &temp, msg->pData, MSG_GetMaxBytes( msg ), MSG_GetNumBitsRead( msg ) + frag_offset[i], -1 ); + MSG_StartReading( &temp, msg->pData, MSG_GetMaxBytes( msg ), size, -1 ); MSG_ReadBits( &temp, buffer, bits ); MSG_WriteBits( &pbuf->frag_message, buffer, bits ); } - else - { - MsgDev( D_ERROR, "Netchan_Process: Couldn't find buffer %i\n", inbufferid ); - } // count # of incoming bufs we've queued? are we done? Netchan_CheckForCompletion( chan, i, intotalbuffers ); @@ -1709,12 +1629,10 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg ) numbitstoremove = frag_length[i]; MSG_ExciseBits( msg, curbit, numbitstoremove ); - MSG_SeekToBit( msg, oldpos ); + MSG_SeekToBit( msg, oldpos, SEEK_SET ); for( j = i + 1; j < MAX_STREAMS; j++ ) - { frag_offset[j] -= frag_length[i]; - } } // is there anything left to process? diff --git a/engine/common/net_encode.c b/engine/common/net_encode.c index 02c5b331..3f6dfa14 100644 --- a/engine/common/net_encode.c +++ b/engine/common/net_encode.c @@ -1512,7 +1512,7 @@ qboolean MSG_WriteDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *t // if we have no changes - kill the message if( !numChanges ) { - MSG_SeekToBit( msg, startBit ); + MSG_SeekToBit( msg, startBit, SEEK_SET ); return false; } return true; @@ -1583,7 +1583,7 @@ void MSG_WriteClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to, if( numChanges ) return; // we have updates - MSG_SeekToBit( msg, startBit ); + MSG_SeekToBit( msg, startBit, SEEK_SET ); MSG_WriteOneBit( msg, 0 ); // no changes } @@ -1662,7 +1662,7 @@ void MSG_WriteWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to } // if we have no changes - kill the message - if( !numChanges ) MSG_SeekToBit( msg, startBit ); + if( !numChanges ) MSG_SeekToBit( msg, startBit, SEEK_SET ); } /* @@ -1790,7 +1790,7 @@ void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t * } // if we have no changes - kill the message - if( !numChanges && !force ) MSG_SeekToBit( msg, startBit ); + if( !numChanges && !force ) MSG_SeekToBit( msg, startBit, SEEK_SET ); } /* diff --git a/engine/common/net_ws.c b/engine/common/net_ws.c index 35661da3..324ca1e0 100644 --- a/engine/common/net_ws.c +++ b/engine/common/net_ws.c @@ -89,7 +89,7 @@ dll_info_t winsock_dll = { "wsock32.dll", winsock_funcs, false }; typedef struct { - byte data[MAX_INIT_MSG]; + byte data[NET_MAX_MESSAGE]; int datalen; } net_loopmsg_t; diff --git a/engine/common/net_ws.h b/engine/common/net_ws.h index 0ac35c4e..5f872f82 100644 --- a/engine/common/net_ws.h +++ b/engine/common/net_ws.h @@ -24,7 +24,7 @@ typedef enum } netsrc_t; // Max length of unreliable message -#define MAX_DATAGRAM 4000 +#define MAX_DATAGRAM 16384 // Max length of a multicast message #define MAX_MULTICAST 8192 // some mods spamming for rain effect diff --git a/engine/common/netchan.h b/engine/common/netchan.h index 44630efc..6ef144c6 100644 --- a/engine/common/netchan.h +++ b/engine/common/netchan.h @@ -40,6 +40,15 @@ GNU General Public License for more details. // This is the packet payload without any header bytes (which are attached for actual sending) #define NET_MAX_PAYLOAD MAX_INIT_MSG +// Theoretically maximum size of UDP-packet without header and hardware-specific data +#define NET_MAX_FRAGMENT 65536 + +// because encoded as highpart of uint32 +#define NET_MAX_BUFFER_ID 32767 + +// because encoded as lowpart of uint32 +#define NET_MAX_BUFFERS_COUNT 32767 + // This is the payload plus any header info (excluding UDP header) // Packet header is: @@ -105,16 +114,13 @@ typedef struct int totalbytes; } flow_t; -#define FRAGMENT_SV2CL_MIN_SIZE 256 -#define FRAGMENT_SV2CL_MAX_SIZE 1024 - // generic fragment structure typedef struct fragbuf_s { struct fragbuf_s *next; // next buffer in chain int bufferid; // id of this buffer sizebuf_t frag_message; // message buffer where raw data is stored - byte frag_message_buf[NET_MAX_MESSAGE]; // the actual data sits here + byte frag_message_buf[NET_MAX_FRAGMENT]; // the actual data sits here qboolean isfile; // is this a file buffer? qboolean isbuffer; // is this file buffer from memory ( custom decal, etc. ). char filename[MAX_OSPATH]; // name of the file to save out on remote host @@ -197,8 +203,10 @@ typedef struct netchan_s extern netadr_t net_from; extern netadr_t net_local; extern sizebuf_t net_message; -extern byte net_message_buffer[MAX_INIT_MSG]; +extern byte net_message_buffer[NET_MAX_MESSAGE]; extern convar_t *net_speeds; +extern convar_t sv_lan; +extern convar_t sv_lan_rate; extern int net_drop; void Netchan_Init( void ); @@ -216,7 +224,8 @@ void Netchan_OutOfBandPrint( int net_socket, netadr_t adr, char *format, ... ); qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg ); void Netchan_UpdateProgress( netchan_t *chan ); qboolean Netchan_IncomingReady( netchan_t *chan ); -qboolean Netchan_CanPacket( netchan_t *chan ); +qboolean Netchan_CanPacket( netchan_t *chan, qboolean choke ); +qboolean Netchan_IsLocal( netchan_t *chan ); void Netchan_ReportFlow( netchan_t *chan ); void Netchan_FragSend( netchan_t *chan ); void Netchan_Clear( netchan_t *chan ); diff --git a/engine/common/protocol.h b/engine/common/protocol.h index bfef640c..5bc18251 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -154,10 +154,10 @@ GNU General Public License for more details. // decal flags #define FDECAL_PERMANENT 0x01 // This decal should not be removed in favor of any new decals #define FDECAL_USE_LANDMARK 0x02 // This is a decal applied on a bmodel without origin-brush so we done in absoulute pos -#define FDECAL_DONTSAVE 0x04 // Decal was loaded from adjacent level, don't save it for this level -// reserved 0x08 -// reserved 0x10 -// reserved 0x20 +#define FDECAL_CUSTOM 0x04 // This is a custom clan logo and should not be saved/restored +// reserved +// reserved +#define FDECAL_DONTSAVE 0x20 // Decal was loaded from adjacent level, don't save it for this level #define FDECAL_STUDIO 0x40 // Indicates a studio decal #define FDECAL_LOCAL_SPACE 0x80 // decal is in local space (any decal after serialization) @@ -174,6 +174,10 @@ GNU General Public License for more details. #define MAX_RESOURCES (MAX_MODELS+MAX_SOUNDS+MAX_CUSTOM+MAX_EVENTS) #define MAX_RESOURCE_BITS 13 // 13 bits 8192 resource (4096 models + 2048 sounds + 1024 events + 1024 files) +#define FRAGMENT_MIN_SIZE 1200 // default MTU +#define FRAGMENT_MAX_SIZE 64000 // minimal acceptable value without testing network bandwith +#define FRAGMENT_LOCAL_SIZE FRAGMENT_MAX_SIZE // local connection + extern const char *svc_strings[svc_lastmsg+1]; extern const char *clc_strings[clc_lastmsg+1]; diff --git a/engine/server/server.h b/engine/server/server.h index 81fde643..1edca61b 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -410,8 +410,6 @@ extern server_t sv; // local server extern svgame_static_t svgame; // persistant game info extern areanode_t sv_areanodes[]; // AABB dynamic tree -extern convar_t sv_lan; -extern convar_t sv_lan_rate; extern convar_t mp_logecho; extern convar_t mp_logfile; extern convar_t sv_unlag; diff --git a/engine/server/sv_client.c b/engine/server/sv_client.c index 6480b913..f560ec2d 100644 --- a/engine/server/sv_client.c +++ b/engine/server/sv_client.c @@ -89,24 +89,15 @@ void SV_GetChallenge( netadr_t from ) int SV_GetFragmentSize( sv_client_t *cl ) { - int size = FRAGMENT_SV2CL_MAX_SIZE; - int cl_size; + int cl_frag_size; - if( cl->state == cs_spawned ) - { - cl_size = Q_atoi( Info_ValueForKey( cl->userinfo, "cl_dlmax" )); + if( Netchan_IsLocal( &cl->netchan )) + return FRAGMENT_LOCAL_SIZE; - if( cl_size != 0 ) - { - size = bound( FRAGMENT_SV2CL_MIN_SIZE, cl_size, FRAGMENT_SV2CL_MAX_SIZE ); - } - else - { - size = FRAGMENT_SV2CL_MIN_SIZE; - } - } + cl_frag_size = Q_atoi( Info_ValueForKey( cl->userinfo, "cl_dlmax" )); + cl_frag_size = bound( FRAGMENT_MIN_SIZE, cl_frag_size, FRAGMENT_MAX_SIZE ); - return size; + return cl_frag_size; } /* @@ -689,6 +680,58 @@ const char *SV_GetClientIDString( sv_client_t *cl ) return result; } +/* +================ +SV_TestBandWidth + +================ +*/ +void SV_TestBandWidth( netadr_t from ) +{ + int version = Q_atoi( Cmd_Argv( 1 )); + int packetsize = Q_atoi( Cmd_Argv( 2 )); + byte send_buf[FRAGMENT_MAX_SIZE]; + dword crcValue = 0; + byte *filepos; + int crcpos; + file_t *test; + sizebuf_t send; + + // don't waste time of protocol mismatched + if( version != PROTOCOL_VERSION ) + { + SV_RejectConnection( from, "unsupported protocol (%i should be %i)\n", version, PROTOCOL_VERSION ); + return; + } + + test = FS_Open( "gfx.wad", "rb", false ); + + if( FS_FileLength( test ) < sizeof( send_buf )) + { + // skip the test and just get challenge + SV_GetChallenge( from ); + return; + } + + // write the packet header + MSG_Init( &send, "BandWidthPacket", send_buf, sizeof( send_buf )); + MSG_WriteLong( &send, -1 ); // -1 sequence means out of band + MSG_WriteString( &send, "testpacket" ); + crcpos = MSG_GetNumBytesWritten( &send ); + MSG_WriteLong( &send, 0 ); // reserve space for crc + filepos = send.pData + MSG_GetNumBytesWritten( &send ); + packetsize = packetsize - MSG_GetNumBytesWritten( &send ); // adjust the packet size + FS_Read( test, filepos, packetsize ); + FS_Close( test ); + + CRC32_ProcessBuffer( &crcValue, filepos, packetsize ); // calc CRC + MSG_SeekToBit( &send, packetsize << 3, SEEK_CUR ); + *(uint *)&send.pData[crcpos] = crcValue; + + // send the datagram + NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &send ), MSG_GetData( &send ), from ); +} + /* ================ SV_Ack @@ -1817,15 +1860,15 @@ static qboolean SV_DownloadFile_f( sv_client_t *cl ) { if( sv_send_resources.value ) { + // also check the model textures + if( !Q_stricmp( COM_FileExtension( name ), "mdl" )) + { + if( FS_FileExists( Mod_StudioTexName( name ), false ) > 0 ) + Netchan_CreateFileFragments( &cl->netchan, Mod_StudioTexName( name )); + } + if( Netchan_CreateFileFragments( &cl->netchan, name )) { - // also check the model textures - if( !Q_stricmp( COM_FileExtension( name ), "mdl" )) - { - if( FS_FileExists( Mod_StudioTexName( name ), false ) > 0 ) - Netchan_CreateFileFragments( &cl->netchan, Mod_StudioTexName( name )); - } - Netchan_FragSend( &cl->netchan ); return true; } @@ -2064,6 +2107,7 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) if( !Q_strcmp( pcmd, "ping" )) SV_Ping( from ); else if( !Q_strcmp( pcmd, "ack" )) SV_Ack( from ); else if( !Q_strcmp( pcmd, "info" )) SV_Info( from ); + else if( !Q_strcmp( pcmd, "bandwidth" )) SV_TestBandWidth( from ); else if( !Q_strcmp( pcmd, "getchallenge" )) SV_GetChallenge( from ); else if( !Q_strcmp( pcmd, "connect" )) SV_ConnectClient( from ); else if( !Q_strcmp( pcmd, "rcon" )) SV_RemoteCommand( from, msg ); @@ -2231,7 +2275,7 @@ void SV_ParseResourceList( sv_client_t *cl, sizebuf_t *msg ) SV_ClearResourceList( &cl->resourcesneeded ); SV_ClearResourceList( &cl->resourcesonhand ); - for ( i = 0; i < total; i++ ) + for( i = 0; i < total; i++ ) { resource = Z_Malloc( sizeof( resource_t ) ); Q_strncpy( resource->szFileName, MSG_ReadString( msg ), sizeof( resource->szFileName )); diff --git a/engine/server/sv_cmds.c b/engine/server/sv_cmds.c index 45c3543b..1027e5a4 100644 --- a/engine/server/sv_cmds.c +++ b/engine/server/sv_cmds.c @@ -73,7 +73,7 @@ void SV_BroadcastPrintf( sv_client_t *ignore, char *fmt, ... ) } // echo to console - Con_Printf( string ); + Con_DPrintf( string ); } /* diff --git a/engine/server/sv_custom.c b/engine/server/sv_custom.c index bc5fb069..3180dbc2 100644 --- a/engine/server/sv_custom.c +++ b/engine/server/sv_custom.c @@ -56,7 +56,7 @@ void SV_CreateCustomizationList( sv_client_t *cl ) } else { - MsgDev( D_REPORT, "SV_CreateCustomization list, ignoring dup. resource for player %s\n", cl->name ); + Con_Printf( S_WARN "SV_CreateCustomization list, ignoring dup. resource for player %s\n", cl->name ); } } } @@ -335,10 +335,10 @@ void SV_AddToResourceList( resource_t *pResource, resource_t *pList ) pList->pPrev = pResource; } -void SV_SendCustomization( sv_client_t *cl, resource_t *pResource ) +void SV_SendCustomization( sv_client_t *cl, int playernum, resource_t *pResource ) { MSG_BeginServerCmd( &cl->netchan.message, svc_customization ); - MSG_WriteByte( &cl->netchan.message, ( cl - svs.clients )); // playernum + MSG_WriteByte( &cl->netchan.message, playernum ); // playernum MSG_WriteByte( &cl->netchan.message, pResource->type ); MSG_WriteString( &cl->netchan.message, pResource->szFileName ); MSG_WriteShort( &cl->netchan.message, pResource->nIndex ); @@ -391,11 +391,11 @@ int SV_EstimateNeededResources( sv_client_t *cl ) if( p->type != t_decal ) continue; - if( HPAK_ResourceForHash( CUSTOM_RES_PATH, p->rgucMD5_hash, NULL )) + if( !HPAK_ResourceForHash( CUSTOM_RES_PATH, p->rgucMD5_hash, NULL )) { if( p->nDownloadSize != 0 ) { - p->ucFlags |= RES_WASMISSING; + SetBits( p->ucFlags, RES_WASMISSING ); size += p->nDownloadSize; } else @@ -420,7 +420,7 @@ void SV_Customization( sv_client_t *pClient, resource_t *pResource, qboolean bSk for( i = 0, cl = svs.clients; i < svs.maxclients; i++, cl++ ) { - if( !cl->state != cs_spawned ) + if( cl->state != cs_spawned ) continue; if( FBitSet( cl->flags, FCL_FAKECLIENT )) @@ -429,7 +429,7 @@ void SV_Customization( sv_client_t *pClient, resource_t *pResource, qboolean bSk if( cl == pClient && bSkipPlayer ) continue; - SV_SendCustomization( cl, pResource ); + SV_SendCustomization( cl, nPlayerNumber, pResource ); } } @@ -442,7 +442,7 @@ void SV_PropagateCustomizations( sv_client_t *pHost ) for( i = 0, cl = svs.clients; i < svs.maxclients; i++, cl++ ) { - if( !cl->state != cs_spawned ) + if( cl->state != cs_spawned ) continue; if( FBitSet( cl->flags, FCL_FAKECLIENT )) @@ -452,7 +452,7 @@ void SV_PropagateCustomizations( sv_client_t *pHost ) { if( !pCust->bInUse ) continue; pResource = &pCust->resource; - SV_SendCustomization( pHost, pResource ); + SV_SendCustomization( pHost, i, pResource ); } } } @@ -517,7 +517,7 @@ void SV_BatchUploadRequest( sv_client_t *cl ) { if( FBitSet( p->ucFlags, RES_CUSTOM )) { - Q_snprintf( filename, sizeof( filename ) - 4, "!MD5%s", MD5_Print( p->rgucMD5_hash )); + Q_snprintf( filename, sizeof( filename ), "!MD5%s", MD5_Print( p->rgucMD5_hash )); if( SV_CheckFile( &cl->netchan.message, filename )) SV_MoveToOnHandList( cl, p ); diff --git a/engine/server/sv_frame.c b/engine/server/sv_frame.c index 6df2a09d..97f9c365 100644 --- a/engine/server/sv_frame.c +++ b/engine/server/sv_frame.c @@ -649,8 +649,9 @@ SV_SendClientDatagram */ void SV_SendClientDatagram( sv_client_t *cl ) { - static byte msg_buf[MAX_INIT_MSG]; - sizebuf_t msg; + static int message_peak = 0; + byte msg_buf[MAX_DATAGRAM]; + sizebuf_t msg; // if we running server with fixed fps so no reason // to send updates too fast: time just not changed @@ -674,7 +675,7 @@ void SV_SendClientDatagram( sv_client_t *cl ) // for this client out to the message if( MSG_CheckOverflow( &cl->datagram )) { - MsgDev( D_WARN, "datagram overflowed for %s\n", cl->name ); + Con_Printf( S_WARN "%s overflowed for %s\n", MSG_GetName( &cl->datagram ), cl->name ); } else { @@ -685,10 +686,16 @@ void SV_SendClientDatagram( sv_client_t *cl ) MSG_Clear( &cl->datagram ); + if( MSG_GetNumBytesWritten( &msg ) > message_peak ) + { + Msg( "max bytes %d for datagram\n", MSG_GetNumBytesWritten( &msg )); + message_peak = MSG_GetNumBytesWritten( &msg ); + } + if( MSG_CheckOverflow( &msg )) { // must have room left for the packet header - MsgDev( D_WARN, "msg overflowed for %s\n", cl->name ); + Con_Printf( S_ERROR, "%s overflowed for %s\n", MSG_GetName( &msg ), cl->name ); MSG_Clear( &msg ); } @@ -862,7 +869,7 @@ void SV_SendClientMessages( void ) if( FBitSet( cl->flags, FCL_SEND_NET_MESSAGE )) { // bandwidth choke active? - if( !Netchan_CanPacket( &cl->netchan )) + if( !Netchan_CanPacket( &cl->netchan, cl->state == cs_spawned )) { cl->chokecount++; continue; @@ -875,7 +882,7 @@ void SV_SendClientMessages( void ) // NOTE: we should send frame even if server is not simulated to prevent overflow if( cl->state == cs_spawned ) SV_SendClientDatagram( cl ); - else Netchan_Transmit( &cl->netchan, 0, NULL ); // just update reliable + else Netchan_TransmitBits( &cl->netchan, 0, NULL ); // just update reliable } } diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 1141ae7f..4cd94116 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -271,7 +271,7 @@ void SV_ProcessFile( sv_client_t *cl, const char *filename ) qboolean bFound; qboolean bError; - if( filename[0] == '!' ) + if( filename[0] != '!' ) { Con_Printf( "Ignoring non-customization file upload of %s\n", filename ); return; @@ -971,6 +971,7 @@ void SV_Shutdown( const char *finalmsg ) SV_FreeClients(); svs.maxclients = 0; + HPAK_FlushHostQueue(); Log_Printf( "Server shutdown\n" ); Log_Close(); diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index a93891a3..95972c67 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -1758,7 +1758,7 @@ static void SV_Physics_Entity( edict_t *ent ) // g-cont. don't alow free entities during loading because // this produce a corrupted baselines - if( sv.state == ss_active && ent->v.flags & FL_KILLME ) + if( sv.state == ss_active && FBitSet( ent->v.flags, FL_KILLME )) SV_FreeEdict( ent ); } diff --git a/engine/server/sv_save.c b/engine/server/sv_save.c index a6af383b..37026a50 100644 --- a/engine/server/sv_save.c +++ b/engine/server/sv_save.c @@ -461,8 +461,6 @@ void ReapplyDecal( SAVERESTOREDATA *pSaveData, decallist_t *entry, qboolean adja // these entities might not exist over transitions, // so we'll use the saved plane and do a traceline instead - flags |= FDECAL_DONTSAVE; - MsgDev( D_ERROR, "couldn't restore entity index %i, do trace for decal\n", entityIndex ); VectorCopy( entry->position, testspot ); @@ -2254,7 +2252,8 @@ void SV_SaveGame( const char *pName ) SV_BuildSaveComment( comment, sizeof( comment )); SV_SaveGameSlot( savename, comment ); - CL_HudMessage( "GAMESAVED" ); // defined in titles.txt + if( !FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE )) + CL_HudMessage( "GAMESAVED" ); // defined in titles.txt } /*