12 Mar 2018

This commit is contained in:
g-cont 2018-03-12 00:00:00 +03:00 committed by Alibek Omarov
parent e96b555d6b
commit 556275f912
29 changed files with 505 additions and 313 deletions

View File

@ -33,7 +33,7 @@ cvar_t weaponstay = {"mp_weaponstay","0", FCVAR_SERVER };
cvar_t forcerespawn= {"mp_forcerespawn","1", FCVAR_SERVER }; cvar_t forcerespawn= {"mp_forcerespawn","1", FCVAR_SERVER };
cvar_t flashlight = {"mp_flashlight","0", FCVAR_SERVER }; cvar_t flashlight = {"mp_flashlight","0", FCVAR_SERVER };
cvar_t aimcrosshair= {"mp_autocrosshair","1", 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 teamlist = {"mp_teamlist","hgrunt;scientist", FCVAR_SERVER };
cvar_t teamoverride = {"mp_teamoverride","1" }; cvar_t teamoverride = {"mp_teamoverride","1" };
cvar_t defaultteam = {"mp_defaultteam","0" }; cvar_t defaultteam = {"mp_defaultteam","0" };

View File

@ -1339,7 +1339,7 @@ void CL_PlayDemo_f( void )
demo.starttime = CL_GetDemoPlaybackClock(); // for determining whether to read another message 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 )); memset( demo.cmds, 0, sizeof( demo.cmds ));
demo.angle_position = 1; demo.angle_position = 1;

View File

@ -25,6 +25,8 @@ GNU General Public License for more details.
#define MAX_TOTAL_CMDS 32 #define MAX_TOTAL_CMDS 32
#define MAX_CMD_BUFFER 8000 #define MAX_CMD_BUFFER 8000
#define CONNECTION_PROBLEM_TIME 15.0 // 15 seconds #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( mp_decals, "300", FCVAR_ARCHIVE, "decals limit in multiplayer" );
CVAR_DEFINE_AUTO( dev_overview, "0", 0, "draw level in overview-mode" ); 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 CL_SignonReply
@ -702,7 +712,7 @@ void CL_WritePacket( void )
if( cl.maxclients == 1 || ( NET_IsLocalAddress( cls.netchan.remote_address ) && !host_limitlocal->value )) if( cl.maxclients == 1 || ( NET_IsLocalAddress( cls.netchan.remote_address ) && !host_limitlocal->value ))
send_command = true; 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; send_command = true;
if( cl.send_reply ) if( cl.send_reply )
@ -1064,16 +1074,40 @@ void CL_CheckForResend( void )
if( !NET_StringToAdr( cls.servername, &adr )) if( !NET_StringToAdr( cls.servername, &adr ))
{ {
MsgDev( D_ERROR, "CL_CheckForResend: bad server address\n" ); MsgDev( D_ERROR, "CL_CheckForResend: bad server address\n" );
cls.state = ca_disconnected; CL_Disconnect();
cls.signon = 0; 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; return;
} }
if( adr.port == 0 ) adr.port = MSG_BigShort( PORT_SERVER ); 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_time = host.realtime; // for retransmit requests
cls.connect_retry++;
Con_Printf( "Connecting to %s...\n", cls.servername ); Con_Printf( "Connecting to %s...\n", cls.servername );
#if 0
Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" ); 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 ) 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; cls.state = ca_connecting;
Q_strncpy( cls.servername, server, sizeof( cls.servername )); Q_strncpy( cls.servername, server, sizeof( cls.servername ));
cls.connect_time = MAX_HEARTBEAT; // CL_CheckForResend() will fire immediately 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.spectator = false;
cls.signon = 0; cls.signon = 0;
} }
@ -1229,16 +1265,17 @@ void CL_ClearState( void )
{ {
int i; int i;
CL_ClearResourceLists();
for( i = 0; i < MAX_CLIENTS; i++ )
COM_ClearCustomizationList( &cl.players[i].customdata, false );
S_StopAllSounds ( true ); S_StopAllSounds ( true );
CL_ClearEffects (); CL_ClearEffects ();
CL_FreeEdicts (); CL_FreeEdicts ();
CL_ClearPhysEnts (); CL_ClearPhysEnts ();
NetAPI_CancelAllRequests(); NetAPI_CancelAllRequests();
CL_ClearResourceLists();
for( i = 0; i < MAX_CLIENTS; i++ )
COM_ClearCustomizationList( &cl.players[i].customdata, false );
// wipe the entire cl structure // wipe the entire cl structure
memset( &cl, 0, sizeof( cl )); memset( &cl, 0, sizeof( cl ));
@ -1284,9 +1321,9 @@ void CL_SendDisconnectMessage( void )
cls.netchan.remote_address.type = NA_LOOPBACK; cls.netchan.remote_address.type = NA_LOOPBACK;
// make sure message will be delivered // make sure message will be delivered
Netchan_Transmit( &cls.netchan, MSG_GetNumBytesWritten( &buf ), MSG_GetData( &buf )); Netchan_TransmitBits( &cls.netchan, MSG_GetNumBitsWritten( &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_Transmit( &cls.netchan, MSG_GetNumBytesWritten( &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 ) 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 else
{ {
@ -1340,6 +1377,7 @@ void CL_Disconnect( void )
cls.connect_time = 0; cls.connect_time = 0;
cls.changedemo = false; cls.changedemo = false;
cls.max_fragment_size = FRAGMENT_MAX_SIZE; // reset fragment size
CL_Stop_f(); CL_Stop_f();
// send a disconnect message to the server // send a disconnect message to the server
@ -1353,6 +1391,7 @@ void CL_Disconnect( void )
Netchan_Clear( &cls.netchan ); Netchan_Clear( &cls.netchan );
cls.state = ca_disconnected; cls.state = ca_disconnected;
cls.connect_retry = 0;
cls.signon = 0; cls.signon = 0;
// back to menu in non-developer mode // back to menu in non-developer mode
@ -1741,6 +1780,60 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
// print command from somewhere // print command from somewhere
Con_Printf( "%s", MSG_ReadString( msg )); 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" )) else if( !Q_strcmp( c, "ping" ))
{ {
// ping from somewhere // ping from somewhere

View File

@ -865,17 +865,17 @@ void CL_RemoveCustomization( int nPlayerNum, customization_t *pRemove )
if( pList->bInUse && pList->pInfo ) if( pList->bInUse && pList->pInfo )
{ {
if ( pList->resource.type == t_decal ) if( pList->resource.type == t_decal )
{ {
if( cls.state == ca_active ) if( cls.state == ca_active )
R_DecalRemoveAll( ~nPlayerNum ); R_DecalRemoveAll( pList->nUserData1 );
FS_FreeImage( pList->pInfo ); FS_FreeImage( pList->pInfo );
} }
} }
cl.players[nPlayerNum].customdata.pNext = pNext; 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 ) void CL_ParseCustomization( sizebuf_t *msg )
{ {
customization_t *pExistingCustomization; customization_t *pExistingCustomization;
resource_t *resource;
customization_t *pList; customization_t *pList;
qboolean bFound; qboolean bFound;
resource_t *pRes;
int i; int i;
i = MSG_ReadByte( msg ); i = MSG_ReadByte( msg );
if( i >= MAX_CLIENTS ) if( i >= MAX_CLIENTS )
Host_Error( "Bogus player index during customization parsing.\n" ); Host_Error( "Bogus player index during customization parsing.\n" );
resource = Mem_Alloc( cls.mempool, sizeof( resource_t )); pRes = Mem_Alloc( cls.mempool, sizeof( resource_t ));
resource->type = MSG_ReadByte( msg ); pRes->type = MSG_ReadByte( msg );
Q_strncpy( resource->szFileName, MSG_ReadString( msg ), sizeof( resource->szFileName )); Q_strncpy( pRes->szFileName, MSG_ReadString( msg ), sizeof( pRes->szFileName ));
resource->nIndex = MSG_ReadShort( msg ); pRes->nIndex = MSG_ReadShort( msg );
resource->nDownloadSize = MSG_ReadLong( msg ); pRes->nDownloadSize = MSG_ReadLong( msg );
resource->ucFlags = MSG_ReadByte( msg ) & ~RES_WASMISSING; pRes->ucFlags = MSG_ReadByte( msg ) & ~RES_WASMISSING;
resource->pNext = resource->pPrev = NULL; pRes->pNext = pRes->pPrev = NULL;
if( FBitSet( resource->ucFlags, RES_CUSTOM )) if( FBitSet( pRes->ucFlags, RES_CUSTOM ))
MSG_ReadBytes( msg, resource->rgucMD5_hash, 16 ); MSG_ReadBytes( msg, pRes->rgucMD5_hash, 16 );
resource->playernum = i; pRes->playernum = i;
if( !cl_allow_download.value ) if( !cl_allow_download.value )
{ {
Con_DPrintf( "Refusing new resource, cl_allow_download set to 0\n" ); Con_DPrintf( "Refusing new resource, cl_allow_download set to 0\n" );
Mem_Free( resource ); Mem_Free( pRes );
return; return;
} }
if( cls.state == ca_active && !cl_download_ingame.value ) if( cls.state == ca_active && !cl_download_ingame.value )
{ {
Con_DPrintf( "Refusing new resource, cl_download_ingame set to 0\n" ); Con_DPrintf( "Refusing new resource, cl_download_ingame set to 0\n" );
Mem_Free( resource ); Mem_Free( pRes );
return; return;
} }
pExistingCustomization = CL_PlayerHasCustomization( i, resource->type ); pExistingCustomization = CL_PlayerHasCustomization( i, pRes->type );
if( pExistingCustomization ) if( pExistingCustomization )
CL_RemoveCustomization( i, pExistingCustomization ); CL_RemoveCustomization( i, pExistingCustomization );
bFound = false; 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; bFound = true;
break; break;
} }
} }
if( HPAK_GetDataPointer( CUSTOM_RES_PATH, resource, NULL, NULL )) if( HPAK_GetDataPointer( CUSTOM_RES_PATH, pRes, NULL, NULL ))
{ {
qboolean bError = false; qboolean bError = false;
if( !bFound ) 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; bError = true;
} }
else else
@ -954,13 +956,13 @@ void CL_ParseCustomization( sizebuf_t *msg )
} }
if( bError ) Con_DPrintf( "Error loading customization\n" ); if( bError ) Con_DPrintf( "Error loading customization\n" );
Mem_Free( resource ); Mem_Free( pRes );
} }
else else
{ {
resource->ucFlags |= RES_WASMISSING; SetBits( pRes->ucFlags, RES_WASMISSING );
CL_AddToResourceList( resource, &cl.resourcesneeded ); CL_AddToResourceList( pRes, &cl.resourcesneeded );
Con_Printf( "Requesting %s from server\n", resource ); Con_Printf( "Requesting %s from server\n", pRes->szFileName );
CL_StartResourceDownloading( "Custom resource propagation...\n", true ); 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 CL_ParseFileTransferFailed
@ -1157,6 +1184,10 @@ void CL_ParseServerData( sizebuf_t *msg )
cls.scrshot_request = scrshot_plaque; // request levelshot even if exist (check filetime) 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 // request resources from server
CL_ServerCommand( true, "sendres %i\n", cl.servercount ); CL_ServerCommand( true, "sendres %i\n", cl.servercount );

View File

@ -116,7 +116,16 @@ add client-side resource to list
*/ */
void CL_AddClientResource( const char *filename, int type ) 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 )); pResource = Mem_Alloc( cls.mempool, sizeof( resource_t ));
@ -2392,13 +2401,13 @@ void CL_ParseTempEntity( sizebuf_t *msg )
R_RicochetSound( pos ); R_RicochetSound( pos );
break; break;
case TE_PLAYERDECAL: case TE_PLAYERDECAL:
color = MSG_ReadByte( &buf ); // playernum color = MSG_ReadByte( &buf ) - 1; // playernum
pos[0] = MSG_ReadCoord( &buf ); pos[0] = MSG_ReadCoord( &buf );
pos[1] = MSG_ReadCoord( &buf ); pos[1] = MSG_ReadCoord( &buf );
pos[2] = MSG_ReadCoord( &buf ); pos[2] = MSG_ReadCoord( &buf );
entityIndex = MSG_ReadShort( &buf ); entityIndex = MSG_ReadShort( &buf );
decalIndex = MSG_ReadByte( &buf ); decalIndex = MSG_ReadByte( &buf );
CL_PlayerDecal( CL_DecalIndex( decalIndex ), entityIndex, pos ); CL_PlayerDecal( color, decalIndex, entityIndex, pos );
break; break;
case TE_BUBBLES: case TE_BUBBLES:
case TE_BUBBLETRAIL: case TE_BUBBLETRAIL:
@ -2973,9 +2982,28 @@ CL_PlayerDecal
spray custom colored decal (clan logo etc) 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 );
} }
/* /*

View File

@ -568,6 +568,8 @@ typedef struct
// connection information // connection information
char servername[MAX_QPATH]; // name of server from original connect char servername[MAX_QPATH]; // name of server from original connect
double connect_time; // for connection retransmits 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 qboolean spectator; // not a real player, just spectator
local_state_t spectator_state; // init as client startup local_state_t spectator_state; // init as client startup
@ -737,6 +739,7 @@ void CL_SendCommand( void );
void CL_Disconnect_f( void ); void CL_Disconnect_f( void );
void CL_ProcessFile( qboolean successfully_received, const char *filename ); void CL_ProcessFile( qboolean successfully_received, const char *filename );
void CL_WriteUsercmd( sizebuf_t *msg, int from, int to ); void CL_WriteUsercmd( sizebuf_t *msg, int from, int to );
int CL_GetFragmentSize( void *unused );
qboolean CL_PrecacheResources( void ); qboolean CL_PrecacheResources( void );
void CL_SetupOverviewParams( void ); void CL_SetupOverviewParams( void );
void CL_UpdateFrameLerp( 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_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_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_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 R_FreeDeadParticles( struct particle_s **ppparticles );
void CL_AddClientResource( const char *filename, int type );
void CL_AddClientResources( void ); void CL_AddClientResources( void );
int CL_FxBlend( cl_entity_t *e ); int CL_FxBlend( cl_entity_t *e );
void CL_InitParticles( void ); void CL_InitParticles( void );

View File

@ -1079,7 +1079,7 @@ void GL_DrawAliasFrame( aliashdr_t *paliashdr )
} }
else else
{ {
pglTexCoord2f (((float *)order)[0], ((float *)order)[1]); pglTexCoord2f( ((float *)order)[0], ((float *)order)[1] );
} }
order += 2; order += 2;

View File

@ -146,7 +146,7 @@ static void R_GetDecalDimensions( int texture, int *width, int *height )
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// compute the decal basis based on surface normal // 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; vec3_t surfaceNormal;
@ -155,9 +155,31 @@ void R_DecalComputeBasis( msurface_t *surf, vec3_t textureSpaceBasis[3] )
VectorNegate( surf->plane->normal, surfaceNormal ); VectorNegate( surf->plane->normal, surfaceNormal );
else VectorCopy( 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[0], textureSpaceBasis[0] );
VectorNormalize2( surf->texinfo->vecs[1], textureSpaceBasis[1] ); 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] ) 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; int width, height;
// Compute the non-scaled decal basis // Compute the non-scaled decal basis
R_DecalComputeBasis( surf, textureSpaceBasis ); R_DecalComputeBasis( surf, pDecal->flags, textureSpaceBasis );
R_GetDecalDimensions( texture, &width, &height ); R_GetDecalDimensions( texture, &width, &height );
// world width of decal = ptexture->width / pDecal->scale // 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 bigger decals and replace them with smaller decals
// Don't steal permanent decals // Don't steal permanent decals
if(!( pDecal->flags & FDECAL_PERMANENT )) if( !FBitSet( pDecal->flags, FDECAL_PERMANENT ))
{ {
vec3_t testBasis[3]; vec3_t testBasis[3];
vec3_t testPosition[2]; 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) // Determine the decal basis (measured in world space)
// Note that the decal basis vectors 0 and 1 will always lie in the same // Note that the decal basis vectors 0 and 1 will always lie in the same
// plane as the texture space basis vectorstextureVecsTexelsPerWorldUnits. // 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 // Compute an effective width and height (axis aligned) in the parent texture space
// How does this work? decalBasis[0] represents the u-direction (width) // 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_t *pdecals;
// decal is in use and is not a custom decal // 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; continue;
// compute depth // compute depth

View File

@ -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 )); VOX_LoadSound( target_chan, S_SkipSoundChar( sfx->name ));
Q_strncpy( target_chan->name, sfx->name, sizeof( target_chan->name )); Q_strncpy( target_chan->name, sfx->name, sizeof( target_chan->name ));
sfx = target_chan->sfx; sfx = target_chan->sfx;
pSource = sfx->cache; if( sfx ) pSource = sfx->cache;
} }
else else
{ {
@ -1092,7 +1092,7 @@ void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float
else else
{ {
sfx = target_chan->sfx; sfx = target_chan->sfx;
pSource = sfx->cache; if( sfx ) pSource = sfx->cache;
} }
} }
else 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 )); VOX_LoadSound( ch, S_SkipSoundChar( sfx->name ));
Q_strncpy( ch->name, sfx->name, sizeof( ch->name )); Q_strncpy( ch->name, sfx->name, sizeof( ch->name ));
sfx = ch->sfx; sfx = ch->sfx;
pSource = sfx->cache; if( sfx ) pSource = sfx->cache;
fvox = 1; fvox = 1;
} }
else else

View File

@ -32,24 +32,24 @@ qboolean CustomDecal_Validate( void *raw, int nFileSize )
void COM_ClearCustomizationList( customization_t *pHead, qboolean bCleanDecals ) 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; pNext = pCurrent->pNext;
if( pCurrent->bInUse && pCurrent->pBuffer ) if( pCurrent->bInUse && pCurrent->pBuffer )
{
Mem_Free( pCurrent->pBuffer ); Mem_Free( pCurrent->pBuffer );
}
if( pCurrent->bInUse && pCurrent->pInfo ) if( pCurrent->bInUse && pCurrent->pInfo )
{ {
if( pCurrent->resource.type == t_decal ) if( pCurrent->resource.type == t_decal )
{ {
if( bCleanDecals && CL_Active( )) if( bCleanDecals && CL_Active( ))
R_DecalRemoveAll( ~pCurrent->resource.playernum ); R_DecalRemoveAll( pCurrent->nUserData1 );
} }
FS_FreeImage( pCurrent->pInfo ); FS_FreeImage( pCurrent->pInfo );
} }
Mem_Free( pCurrent ); 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 ) qboolean COM_CreateCustomization( customization_t *pListHead, resource_t *pResource, int playernumber, int flags, customization_t **pOut, int *nLumps )
{ {
customization_t *pCust;
qboolean bError = false; qboolean bError = false;
void *pNewBuffer = NULL; int checksize = 0;
customization_t *pCust;
if( pOut ) *pOut = NULL; if( pOut ) *pOut = NULL;
@ -81,9 +81,10 @@ qboolean COM_CreateCustomization( customization_t *pListHead, resource_t *pResou
} }
else else
{ {
int checksize = 0;
pCust->pBuffer = COM_LoadFile( pResource->szFileName, 5, &checksize ); pCust->pBuffer = FS_LoadFile( pResource->szFileName, &checksize, true );
Msg( "loading %s, check %d, downoad %d\n", pResource->szFileName, checksize, pCust->resource.nDownloadSize ); if( checksize != pCust->resource.nDownloadSize )
bError = true;
} }
if( bError ) if( bError )
@ -99,6 +100,10 @@ qboolean COM_CreateCustomization( customization_t *pListHead, resource_t *pResou
{ {
if( pResource->nDownloadSize >= (1 * 1024) && pResource->nDownloadSize <= ( 16 * 1024 )) if( pResource->nDownloadSize >= (1 * 1024) && pResource->nDownloadSize <= ( 16 * 1024 ))
{ {
pCust->bTranslated = true;
pCust->nUserData1 = 0;
pCust->nUserData2 = 1;
if( !FBitSet( flags, FCUST_WIPEDATA )) if( !FBitSet( flags, FCUST_WIPEDATA ))
pCust->pInfo = FS_LoadImage( "#logo.bmp", pCust->pBuffer, pCust->resource.nDownloadSize ); pCust->pInfo = FS_LoadImage( "#logo.bmp", pCust->pBuffer, pCust->resource.nDownloadSize );
else pCust->pInfo = NULL; else pCust->pInfo = NULL;

View File

@ -850,6 +850,7 @@ void Host_FreeCommon( void )
Image_Shutdown(); Image_Shutdown();
Sound_Shutdown(); Sound_Shutdown();
Netchan_Shutdown(); Netchan_Shutdown();
HPAK_FlushHostQueue();
FS_Shutdown(); FS_Shutdown();
Mem_FreePool( &host.mempool ); Mem_FreePool( &host.mempool );

View File

@ -71,8 +71,9 @@ void HPAK_FlushHostQueue( void )
{ {
hash_pack_queue_t *p; 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 ); HPAK_AddLump( false, p->name, &p->resource, p->data, NULL );
freestring( p->name ); freestring( p->name );
Mem_Free( p->data ); 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 ) void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource, byte *pData, file_t *pFile )
{ {
int i, j, position, length; int i, j, position, length;
hpak_lump_t *pCurrentEntry = NULL;
string srcname, dstname; string srcname, dstname;
hpak_info_t srcpak, dstpak; hpak_info_t srcpak, dstpak;
hpak_lump_t *pCurrentEntry;
file_t *file_src; file_t *file_src;
file_t *file_dst; file_t *file_dst;
char md5[16]; 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++ ) 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]; pCurrentEntry = &dstpak.entries[i];
@ -516,7 +517,7 @@ qboolean HPAK_ResourceForHash( const char *filename, byte *hash, resource_t *pRe
file_t *f; file_t *f;
hash_pack_queue_t *p; hash_pack_queue_t *p;
if( !filename || !filename[0] ) if( !COM_CheckString( filename ))
return false; return false;
for( p = gp_hpak_queue; p != NULL; p = p->next ) 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; file_t *f;
int i; int i;
if( !filename || !filename[0] ) if( !COM_CheckString( filename ))
return false; return false;
if( buffer ) *buffer = NULL; if( buffer ) *buffer = NULL;

View File

@ -88,7 +88,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
return false; return false;
// special hack for loading qfont // 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 // NOTE: same as system font we can use 4-bit bmps only
// step1: move main layer into alpha-channel (give grayscale from RED channel) // 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 ); 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 ) if( host.overview_loading && bhdr.bitsPerPixel == 8 )
{ {
// convert green background into alpha-layer, make opacity for all other entries // 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 ) if( Image_CheckFlag( IL_KEEP_8BIT ) && bhdr.bitsPerPixel == 8 )
{ {
pixbuf = image.palette = Mem_Alloc( host.imagepool, 1024 ); pixbuf = image.palette = Mem_Alloc( host.imagepool, 1024 );
image.flags |= IMAGE_HAS_COLOR;
// bmp have a reversed palette colors // bmp have a reversed palette colors
for( i = 0; i < bhdr.colors; i++ ) for( i = 0; i < bhdr.colors; i++ )
{ {

View File

@ -106,9 +106,29 @@ qboolean MSG_CheckOverflow( sizebuf_t *sb )
return MSG_Overflow( sb, 0 ); 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; sb->iCurBit = bitPos;
return 0;
} }
void MSG_SeekToByte( sizebuf_t *sb, int bytePos ) 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; sizebuf_t temp;
MSG_StartWriting( &temp, sb->pData, MSG_GetMaxBytes( sb ), startbit, -1 ); 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++ ) for( i = 0; i < remaining_to_end; i++ )
{ {
MSG_WriteOneBit( &temp, MSG_ReadOneBit( sb )); MSG_WriteOneBit( &temp, MSG_ReadOneBit( sb ));
} }
MSG_SeekToBit( sb, startbit ); MSG_SeekToBit( sb, startbit, SEEK_SET );
sb->nDataBits -= bitstoremove; sb->nDataBits -= bitstoremove;
} }

View File

@ -58,10 +58,10 @@ typedef struct sizebuf_s
// common functions // common functions
void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits ); 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_InitMasks( void ); // called once at startup engine
void MSG_SeekToBit( sizebuf_t *sb, int bitPos ); int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence );
void MSG_SeekToByte( sizebuf_t *sb, int bytePos );
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove ); void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
_inline int MSG_TellBit( sizebuf_t *sb ) { return sb->iCurBit; } _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 ); qboolean MSG_CheckOverflow( sizebuf_t *sb );
short MSG_BigShort( short swap ); short MSG_BigShort( short swap );

View File

@ -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_AVG ( 2.0 / 3.0 ) // how fast to converge flow estimates
#define FLOW_INTERVAL 0.1 // don't compute more often than this #define FLOW_INTERVAL 0.1 // don't compute more often than this
#define MAX_RELIABLE_PAYLOAD 1400 // biggest packet that has frag and or reliable data
#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)
// forward declarations // forward declarations
void Netchan_FlushIncoming( netchan_t *chan, int stream ); void Netchan_FlushIncoming( netchan_t *chan, int stream );
@ -98,7 +94,7 @@ int net_drop;
netadr_t net_from; netadr_t net_from;
sizebuf_t net_message; sizebuf_t net_message;
byte *net_mempool; byte *net_mempool;
byte net_message_buffer[MAX_INIT_MSG]; byte net_message_buffer[NET_MAX_MESSAGE];
const char *ns_strings[NS_COUNT] = const char *ns_strings[NS_COUNT] =
{ {
@ -126,7 +122,7 @@ void Netchan_Init( void )
net_mempool = Mem_AllocPool( "Network Pool" ); net_mempool = Mem_AllocPool( "Network Pool" );
MSG_InitMasks (); // initialize bit-masks MSG_InitMasks(); // initialize bit-masks
} }
void Netchan_Shutdown( void ) void Netchan_Shutdown( void )
@ -159,10 +155,8 @@ detect a loopback message
*/ */
qboolean Netchan_IsLocal( netchan_t *chan ) qboolean Netchan_IsLocal( netchan_t *chan )
{ {
#if 0 // FIXME
if( !NET_IsActive() || NET_IsLocalAddress( chan->remote_address )) if( !NET_IsActive() || NET_IsLocalAddress( chan->remote_address ))
return true; return true;
#endif
return false; return false;
} }
@ -219,10 +213,10 @@ Netchan_CanPacket
Returns true if the bandwidth choke isn't active 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. // 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; chan->cleartime = host.realtime;
return true; return true;
@ -241,11 +235,7 @@ void Netchan_UnlinkFragment( fragbuf_t *buf, fragbuf_t **list )
{ {
fragbuf_t *search; fragbuf_t *search;
if( !list ) if( !list ) return;
{
MsgDev( D_ERROR, "Netchan_UnlinkFragment: Asked to unlink fragment from empty list, ignored\n" );
return;
}
// at head of list // at head of list
if( buf == *list ) if( buf == *list )
@ -271,9 +261,8 @@ void Netchan_UnlinkFragment( fragbuf_t *buf, fragbuf_t **list )
} }
search = search->next; search = search->next;
} }
MsgDev( D_ERROR, "Netchan_UnlinkFragment: Couldn't find fragment\n" );
} }
/* /*
============================== ==============================
Netchan_ClearFragbufs 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 ) void Netchan_OutOfBand( int net_socket, netadr_t adr, int length, byte *data )
{ {
byte send_buf[MAX_PRINT_MSG];
sizebuf_t send; sizebuf_t send;
byte send_buf[NET_MAX_PAYLOAD];
// write the packet header // write the packet header
MSG_Init( &send, "SequencePacket", send_buf, sizeof( send_buf )); 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, ... ) void Netchan_OutOfBandPrint( int net_socket, netadr_t adr, char *format, ... )
{ {
static char string[MAX_PRINT_MSG]; char string[MAX_PRINT_MSG];
va_list argptr; va_list argptr;
va_start( argptr, format ); va_start( argptr, format );
Q_vsnprintf( string, sizeof( string ) - 1, format, argptr ); 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; fragbuf_t *buf;
int chunksize; int chunksize;
int remaining; int remaining;
int bits, pos; int bytes, pos;
int bufferid = 1; int bufferid = 1;
fragbufwaiting_t *wait, *p; fragbufwaiting_t *wait, *p;
@ -587,38 +576,27 @@ static void Netchan_CreateFragments_( netchan_t *chan, sizebuf_t *msg )
if( chan->pfnBlockSize != NULL ) if( chan->pfnBlockSize != NULL )
chunksize = chan->pfnBlockSize( chan->client ); chunksize = chan->pfnBlockSize( chan->client );
else chunksize = FRAGMENT_SV2CL_MAX_SIZE; else chunksize = FRAGMENT_MAX_SIZE; // fallback
chunksize = 8192;
wait = (fragbufwaiting_t *)Mem_Alloc( net_mempool, sizeof( fragbufwaiting_t )); wait = (fragbufwaiting_t *)Mem_Alloc( net_mempool, sizeof( fragbufwaiting_t ));
remaining = MSG_GetNumBitsWritten( msg ); remaining = MSG_GetNumBytesWritten( msg );
chunksize <<= 3; // convert bytes to bits pos = 0; // current position in bytes
pos = 0; // current position in bits
while( remaining > 0 ) while( remaining > 0 )
{ {
byte buffer[NET_MAX_PAYLOAD]; bytes = Q_min( remaining, chunksize );
sizebuf_t temp; remaining -= bytes;
bits = Q_min( remaining, chunksize );
remaining -= bits;
buf = Netchan_AllocFragbuf(); buf = Netchan_AllocFragbuf();
buf->bufferid = bufferid++; buf->bufferid = bufferid++;
// Copy in data // Copy in data
MSG_Clear( &buf->frag_message ); MSG_Clear( &buf->frag_message );
MSG_WriteBits( &buf->frag_message, &msg->pData[pos], bytes << 3 );
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 );
Netchan_AddFragbufToTail( wait, buf ); Netchan_AddFragbufToTail( wait, buf );
pos += bits; pos += bytes;
} }
// now add waiting list item to end of buffer queue // 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 ) if( chan->pfnBlockSize != NULL )
chunksize = chan->pfnBlockSize( chan->client ); chunksize = chan->pfnBlockSize( chan->client );
else chunksize = FRAGMENT_SV2CL_MAX_SIZE; else chunksize = FRAGMENT_MAX_SIZE; // fallback
wait = ( fragbufwaiting_t * )Mem_Alloc( net_mempool, sizeof( fragbufwaiting_t ));
wait = (fragbufwaiting_t *)Mem_Alloc( net_mempool, sizeof( fragbufwaiting_t ));
remaining = size; remaining = size;
pos = 0; pos = 0;
@ -766,13 +743,13 @@ void Netchan_CreateFileFragmentsFromBuffer( netchan_t *chan, char *filename, byt
if( firstfragment ) if( firstfragment )
{ {
firstfragment = false;
// write filename // write filename
MSG_WriteString( &buf->frag_message, filename ); MSG_WriteString( &buf->frag_message, filename );
// send a bit less on first package // send a bit less on first package
send -= MSG_GetNumBytesWritten( &buf->frag_message ); send -= MSG_GetNumBytesWritten( &buf->frag_message );
firstfragment = false;
} }
buf->isbuffer = true; 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 ); MSG_WriteBits( &buf->frag_message, pbuf + pos, send << 3 );
pos += send;
remaining -= send; remaining -= send;
pos += send;
Netchan_AddFragbufToTail( wait, buf ); Netchan_AddFragbufToTail( wait, buf );
} }
@ -798,9 +775,7 @@ void Netchan_CreateFileFragmentsFromBuffer( netchan_t *chan, char *filename, byt
p = chan->waitlist[FRAG_FILE_STREAM]; p = chan->waitlist[FRAG_FILE_STREAM];
while( p->next ) while( p->next )
{
p = p->next; p = p->next;
}
p->next = wait; p->next = wait;
} }
} }
@ -822,17 +797,16 @@ int Netchan_CreateFileFragments( netchan_t *chan, const char *filename )
fragbufwaiting_t *wait, *p; fragbufwaiting_t *wait, *p;
fragbuf_t *buf; fragbuf_t *buf;
if( chan->pfnBlockSize != NULL ) if(( filesize = FS_FileSize( filename, false )) <= 0 )
chunksize = chan->pfnBlockSize( chan->client );
else chunksize = FRAGMENT_SV2CL_MAX_SIZE;
filesize = FS_FileSize( filename, false );
chunksize = 32768;
if( filesize <= 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; 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 )); wait = (fragbufwaiting_t *)Mem_Alloc( net_mempool, sizeof( fragbufwaiting_t ));
remaining = filesize; remaining = filesize;
pos = 0; pos = 0;
@ -849,13 +823,13 @@ chunksize = 32768;
if( firstfragment ) if( firstfragment )
{ {
firstfragment = false;
// Write filename // Write filename
MSG_WriteString( &buf->frag_message, filename ); MSG_WriteString( &buf->frag_message, filename );
// Send a bit less on first package // Send a bit less on first package
send -= MSG_GetNumBytesWritten( &buf->frag_message ); send -= MSG_GetNumBytesWritten( &buf->frag_message );
firstfragment = false;
} }
buf->isfile = true; buf->isfile = true;
@ -878,10 +852,7 @@ chunksize = 32768;
{ {
p = chan->waitlist[FRAG_FILE_STREAM]; p = chan->waitlist[FRAG_FILE_STREAM];
while( p->next ) while( p->next )
{
p = p->next; p = p->next;
}
p->next = wait; p->next = wait;
} }
@ -896,11 +867,12 @@ Netchan_FlushIncoming
*/ */
void Netchan_FlushIncoming( netchan_t *chan, int stream ) void Netchan_FlushIncoming( netchan_t *chan, int stream )
{ {
fragbuf_t *p, *n; fragbuf_t *p, *n;
MSG_Clear( &net_message ); MSG_Clear( &net_message );
p = chan->incomingbufs[ stream ]; p = chan->incomingbufs[ stream ];
while( p ) while( p )
{ {
n = p->next; n = p->next;
@ -919,7 +891,7 @@ Netchan_CopyNormalFragments
*/ */
qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *length ) 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; fragbuf_t *p, *n;
if( !chan->incomingready[FRAG_NORMAL_STREAM] ) 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] ) if( !chan->incomingbufs[FRAG_NORMAL_STREAM] )
{ {
MsgDev( D_ERROR, "Netchan_CopyNormalFragments: Called with no fragments readied\n" );
chan->incomingready[FRAG_NORMAL_STREAM] = false; chan->incomingready[FRAG_NORMAL_STREAM] = false;
return false; return false;
} }
@ -941,8 +912,8 @@ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *l
n = p->next; n = p->next;
// copy it in // copy it in
MSG_WriteBits( msg, MSG_GetData( &p->frag_message ), MSG_GetNumBitsWritten( &p->frag_message )); MSG_WriteBytes( msg, MSG_GetData( &p->frag_message ), MSG_GetNumBytesWritten( &p->frag_message ));
frag_num_bits += MSG_GetNumBitsWritten( &p->frag_message ); size += MSG_GetNumBytesWritten( &p->frag_message );
Mem_Free( p ); Mem_Free( p );
p = n; p = n;
@ -954,7 +925,7 @@ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *l
chan->incomingready[FRAG_NORMAL_STREAM] = false; chan->incomingready[FRAG_NORMAL_STREAM] = false;
// tell about message size // tell about message size
if( length ) *length = BitByte( frag_num_bits ); if( length ) *length = size;
return true; return true;
} }
@ -967,18 +938,16 @@ Netchan_CopyFileFragments
*/ */
qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg ) qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg )
{ {
fragbuf_t *p, *n; char filename[MAX_OSPATH];
char filename[MAX_QPATH]; int nsize, pos;
int nsize;
byte *buffer; byte *buffer;
int pos; fragbuf_t *p, *n;
if( !chan->incomingready[FRAG_FILE_STREAM] ) if( !chan->incomingready[FRAG_FILE_STREAM] )
return false; return false;
if( !chan->incomingbufs[FRAG_FILE_STREAM] ) if( !chan->incomingbufs[FRAG_FILE_STREAM] )
{ {
MsgDev( D_WARN, "Netchan_CopyFileFragments: Called with no fragments readied\n" );
chan->incomingready[FRAG_FILE_STREAM] = false; chan->incomingready[FRAG_FILE_STREAM] = false;
return 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 )); MSG_Init( msg, "NetMessage", net_message_buffer, sizeof( net_message_buffer ));
// copy in first chunk so we can get filename out // copy in first chunk so we can get filename out
MSG_WriteBits( msg, MSG_GetData( &p->frag_message ), MSG_GetNumBitsWritten( &p->frag_message )); MSG_WriteBytes( msg, MSG_GetData( &p->frag_message ), MSG_GetNumBytesWritten( &p->frag_message ));
MSG_SeekToBit( msg, 0 ); // rewind buffer MSG_Clear( msg );
Q_strncpy( filename, MSG_ReadString( msg ), sizeof( filename )); 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" ); Con_Printf( S_ERROR "file fragment received with no filename\nFlushing input queue\n" );
// clear out bufs
Netchan_FlushIncoming( chan, FRAG_FILE_STREAM ); Netchan_FlushIncoming( chan, FRAG_FILE_STREAM );
return false; 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" ); Con_Printf( S_ERROR "file fragment received with bad 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
Netchan_FlushIncoming( chan, FRAG_FILE_STREAM ); Netchan_FlushIncoming( chan, FRAG_FILE_STREAM );
return false; return false;
} }
@ -1032,9 +979,7 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg )
if( filename[0] != '!' && FS_FileExists( filename, false )) if( filename[0] != '!' && FS_FileExists( filename, false ))
{ {
MsgDev( D_ERROR, "Can't download %s, already exists\n", filename ); Con_Printf( S_ERROR "can't download %s, already exists\n", filename );
// clear out bufs
Netchan_FlushIncoming( chan, FRAG_FILE_STREAM ); Netchan_FlushIncoming( chan, FRAG_FILE_STREAM );
return true; 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 nsize += MSG_GetNumBytesWritten( &p->frag_message ); // Size will include a bit of slop, oh well
if( p == chan->incomingbufs[FRAG_FILE_STREAM] ) if( p == chan->incomingbufs[FRAG_FILE_STREAM] )
{
nsize -= MSG_GetNumBytesRead( msg ); nsize -= MSG_GetNumBytesRead( msg );
}
p = p->next; p = p->next;
} }
buffer = Mem_Alloc( net_mempool, nsize + 1 ); buffer = Mem_Alloc( net_mempool, nsize + 1 );
p = chan->incomingbufs[ FRAG_FILE_STREAM ]; p = chan->incomingbufs[FRAG_FILE_STREAM];
pos = 0; pos = 0;
while( p ) while( p )
@ -1077,19 +1020,15 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg )
} }
pos += cursize; pos += cursize;
Mem_Free( p ); Mem_Free( p );
p = n; p = n;
} }
// customization files goes int tempbuffer
if( filename[0] == '!' ) if( filename[0] == '!' )
{ {
if( chan->tempbuffer ) if( chan->tempbuffer )
{
Con_DPrintf( "Netchan_CopyFragments: Freeing holdover tempbuffer\n" );
Mem_Free( chan->tempbuffer ); Mem_Free( chan->tempbuffer );
}
chan->tempbuffer = buffer; chan->tempbuffer = buffer;
chan->tempbuffersize = nsize; chan->tempbuffersize = nsize;
} }
@ -1104,8 +1043,6 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg )
MSG_Clear( msg ); MSG_Clear( msg );
chan->incomingbufs[FRAG_FILE_STREAM] = NULL; chan->incomingbufs[FRAG_FILE_STREAM] = NULL;
// reset flag
chan->incomingready[FRAG_FILE_STREAM] = false; chan->incomingready[FRAG_FILE_STREAM] = false;
return true; return true;
@ -1116,8 +1053,6 @@ qboolean Netchan_Validate( netchan_t *chan, sizebuf_t *sb, qboolean *frag_messag
int i, buffer, offset; int i, buffer, offset;
int count, length; int count, length;
return true;
for( i = 0; i < MAX_STREAMS; i++ ) for( i = 0; i < MAX_STREAMS; i++ )
{ {
if( !frag_message[i] ) if( !frag_message[i] )
@ -1128,16 +1063,16 @@ return true;
offset = BitByte( frag_offset[i] ); offset = BitByte( frag_offset[i] );
length = BitByte( frag_length[i] ); length = BitByte( frag_length[i] );
if( buffer < 0 || buffer > 25000 ) if( buffer < 0 || buffer > NET_MAX_BUFFER_ID )
return false; return false;
if( count < 0 || count > 25000 ) if( count < 0 || count > NET_MAX_BUFFERS_COUNT )
return false; return false;
if( length < 0 || length > 2048 ) if( length < 0 || length > ( FRAGMENT_MAX_SIZE << 3 ))
return false; return false;
if( offset < 0 || offset > 16384 ) if( offset < 0 || offset > ( FRAGMENT_MAX_SIZE << 3 ))
return false; 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 ) void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
{ {
sizebuf_t send;
int max_send_size, statId;
byte send_buf[NET_MAX_MESSAGE]; byte send_buf[NET_MAX_MESSAGE];
qboolean send_reliable_fragment; qboolean send_reliable_fragment;
qboolean send_resending = false; uint w1, w2, statId;
qboolean send_reliable; qboolean send_reliable;
uint w1, w2; sizebuf_t send;
int i, j; int i, j;
float fRate; float fRate;
// check for message overflow // check for message overflow
if( MSG_CheckOverflow( &chan->message )) 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; return;
} }
@ -1263,10 +1196,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
send_reliable = false; send_reliable = false;
if( chan->incoming_acknowledged > chan->last_reliable_sequence && chan->incoming_reliable_acknowledged != chan->reliable_sequence ) if( chan->incoming_acknowledged > chan->last_reliable_sequence && chan->incoming_reliable_acknowledged != chan->reliable_sequence )
{
send_reliable = true; send_reliable = true;
send_resending = true;
}
// A packet can have "reliable payload + frag payload + unreliable payload // 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 // 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 // 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_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 // 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) // 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; send_from_regular = false;
// if the reliable buffer has gotten too big, queue it at the end of everything and clear out buffer // 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 ); Netchan_CreateFragments_( chan, &chan->message );
MSG_Clear( &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++ ) for( i = 0; i < MAX_STREAMS; i++ )
{ {
int newpayloadsize;
int fragment_size; int fragment_size;
// is there someting in the fragbuf? // is there someting in the fragbuf?
@ -1353,7 +1284,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
if( pbuf ) if( pbuf )
{ {
fragment_size = MSG_GetNumBitsWritten( &pbuf->frag_message ); fragment_size = MSG_GetNumBytesWritten( &pbuf->frag_message );
// files set size a bit differently. // files set size a bit differently.
if( pbuf->isfile && !pbuf->isbuffer ) 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 // 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; 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 it's not in-memory, then we'll need to copy it in frame the file handle.
if( pbuf->isfile && !pbuf->isbuffer ) if( pbuf->isfile && !pbuf->isbuffer )
{ {
byte filebuffer[NET_MAX_PAYLOAD]; byte filebuffer[NET_MAX_FRAGMENT];
file_t *file; file_t *file;
file = FS_Open( pbuf->filename, "rb", false ); 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 // send the qport if we are a client
if( chan->sock == NS_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 ) 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; chan->last_reliable_sequence = chan->outgoing_sequence - 1;
} }
// is there room for the unreliable payload? if( MSG_GetNumBitsLeft( &send ) >= length )
max_send_size = MAX_RESEND_PAYLOAD_BITS;
if( !send_resending )
max_send_size = MSG_GetMaxBits( &send );
if(( max_send_size - MSG_GetNumBitsWritten( &send )) >= length )
MSG_WriteBits( &send, data, 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 // 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 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 ); MSG_BeginClientCmd( &send, clc_nop );
else if( chan->sock == NS_SERVER ) else if( chan->sock == NS_SERVER )
MSG_BeginServerCmd( &send, svc_nop ); 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 ); 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 ) if( chan->cleartime < host.realtime )
chan->cleartime = host.realtime; chan->cleartime = host.realtime;
chan->cleartime += ( MSG_GetNumBytesWritten( &send ) + UDP_HEADER_SIZE ) * fRate; 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; Con_Printf( " %s --> sz=%i seq=%i ack=%i rel=%i tm=%f\n"
, ns_strings[chan->sock]
c = ( chan->sock == NS_CLIENT ) ? 'c' : 's';
Con_Printf( " %c --> sz=%i seq=%i ack=%i rel=%i tm=%f\n"
, c
, MSG_GetNumBytesWritten( &send ) , MSG_GetNumBytesWritten( &send )
, ( chan->outgoing_sequence - 1 ) , ( chan->outgoing_sequence - 1 ) & 63
, chan->incoming_sequence , chan->incoming_sequence & 63
, send_reliable ? 1 : 0 , send_reliable ? 1 : 0
, (float)host.realtime ); , (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 )) if( !CL_IsPlaybackDemo() && !NET_CompareAdr( net_from, chan->remote_address ))
return false; return false;
chan->last_received = host.realtime;
// get sequence numbers // get sequence numbers
MSG_Clear( msg ); MSG_Clear( msg );
sequence = MSG_ReadLong( 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( 30 );
sequence_ack &= ~BIT( 31 ); sequence_ack &= ~BIT( 31 );
if( net_showpackets->value == 2.0f ) if( net_showpackets->value && net_showpackets->value != 3.0f )
{ {
char c; Con_Printf( " %s <-- sz=%i seq=%i ack=%i rel=%i tm=%f\n"
, ns_strings[chan->sock]
c = ( chan->sock == NS_CLIENT ) ? 'c' : 's';
Con_Printf( " %c <-- sz=%i seq=%i ack=%i rel=%i tm=%f\n"
, c
, MSG_GetMaxBytes( msg ) , MSG_GetMaxBytes( msg )
, sequence , sequence & 63
, sequence_ack , sequence_ack & 63
, reliable_message , reliable_message
, host.realtime ); , 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 // dropped packets don't keep the message from being used
net_drop = sequence - ( chan->incoming_sequence + 1 ); net_drop = sequence - ( chan->incoming_sequence + 1 );
if( net_drop > 0 && net_showdrop->value ) 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 // if the current outgoing reliable message has been acknowledged
// clear the buffer to make way for the next // 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->incoming_reliable_sequence ^= 1;
} }
chan->last_received = host.realtime;
// Update data flow stats // Update data flow stats
statId = chan->flow[FLOW_INCOMING].current & MASK_LATENT; statId = chan->flow[FLOW_INCOMING].current & MASK_LATENT;
chan->flow[FLOW_INCOMING].stats[statId].size = MSG_GetMaxBytes( msg ) + UDP_HEADER_SIZE; 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++ ) for( i = 0; i < MAX_STREAMS; i++ )
{ {
fragbuf_t *pbuf;
int j, inbufferid; int j, inbufferid;
int intotalbuffers; int intotalbuffers;
int oldpos, curbit; int oldpos, curbit;
int numbitstoremove; int numbitstoremove;
fragbuf_t *pbuf;
if( !frag_message[i] ) if( !frag_message[i] )
continue; continue;
@ -1681,23 +1604,20 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg )
if( pbuf ) if( pbuf )
{ {
byte buffer[NET_MAX_PAYLOAD]; byte buffer[NET_MAX_FRAGMENT];
int bits, size;
sizebuf_t temp; sizebuf_t temp;
int bits;
size = MSG_GetNumBitsRead( msg ) + frag_offset[i];
bits = frag_length[i]; bits = frag_length[i];
// copy in data // copy in data
MSG_Clear( &pbuf->frag_message ); 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_ReadBits( &temp, buffer, bits );
MSG_WriteBits( &pbuf->frag_message, 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? // count # of incoming bufs we've queued? are we done?
Netchan_CheckForCompletion( chan, i, intotalbuffers ); Netchan_CheckForCompletion( chan, i, intotalbuffers );
@ -1709,12 +1629,10 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg )
numbitstoremove = frag_length[i]; numbitstoremove = frag_length[i];
MSG_ExciseBits( msg, curbit, numbitstoremove ); MSG_ExciseBits( msg, curbit, numbitstoremove );
MSG_SeekToBit( msg, oldpos ); MSG_SeekToBit( msg, oldpos, SEEK_SET );
for( j = i + 1; j < MAX_STREAMS; j++ ) for( j = i + 1; j < MAX_STREAMS; j++ )
{
frag_offset[j] -= frag_length[i]; frag_offset[j] -= frag_length[i];
}
} }
// is there anything left to process? // is there anything left to process?

View File

@ -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 we have no changes - kill the message
if( !numChanges ) if( !numChanges )
{ {
MSG_SeekToBit( msg, startBit ); MSG_SeekToBit( msg, startBit, SEEK_SET );
return false; return false;
} }
return true; return true;
@ -1583,7 +1583,7 @@ void MSG_WriteClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to,
if( numChanges ) return; // we have updates if( numChanges ) return; // we have updates
MSG_SeekToBit( msg, startBit ); MSG_SeekToBit( msg, startBit, SEEK_SET );
MSG_WriteOneBit( msg, 0 ); // no changes 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 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 we have no changes - kill the message
if( !numChanges && !force ) MSG_SeekToBit( msg, startBit ); if( !numChanges && !force ) MSG_SeekToBit( msg, startBit, SEEK_SET );
} }
/* /*

View File

@ -89,7 +89,7 @@ dll_info_t winsock_dll = { "wsock32.dll", winsock_funcs, false };
typedef struct typedef struct
{ {
byte data[MAX_INIT_MSG]; byte data[NET_MAX_MESSAGE];
int datalen; int datalen;
} net_loopmsg_t; } net_loopmsg_t;

View File

@ -24,7 +24,7 @@ typedef enum
} netsrc_t; } netsrc_t;
// Max length of unreliable message // Max length of unreliable message
#define MAX_DATAGRAM 4000 #define MAX_DATAGRAM 16384
// Max length of a multicast message // Max length of a multicast message
#define MAX_MULTICAST 8192 // some mods spamming for rain effect #define MAX_MULTICAST 8192 // some mods spamming for rain effect

View File

@ -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) // This is the packet payload without any header bytes (which are attached for actual sending)
#define NET_MAX_PAYLOAD MAX_INIT_MSG #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) // This is the payload plus any header info (excluding UDP header)
// Packet header is: // Packet header is:
@ -105,16 +114,13 @@ typedef struct
int totalbytes; int totalbytes;
} flow_t; } flow_t;
#define FRAGMENT_SV2CL_MIN_SIZE 256
#define FRAGMENT_SV2CL_MAX_SIZE 1024
// generic fragment structure // generic fragment structure
typedef struct fragbuf_s typedef struct fragbuf_s
{ {
struct fragbuf_s *next; // next buffer in chain struct fragbuf_s *next; // next buffer in chain
int bufferid; // id of this buffer int bufferid; // id of this buffer
sizebuf_t frag_message; // message buffer where raw data is stored 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 isfile; // is this a file buffer?
qboolean isbuffer; // is this file buffer from memory ( custom decal, etc. ). 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 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_from;
extern netadr_t net_local; extern netadr_t net_local;
extern sizebuf_t net_message; 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 *net_speeds;
extern convar_t sv_lan;
extern convar_t sv_lan_rate;
extern int net_drop; extern int net_drop;
void Netchan_Init( void ); 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 ); qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg );
void Netchan_UpdateProgress( netchan_t *chan ); void Netchan_UpdateProgress( netchan_t *chan );
qboolean Netchan_IncomingReady( 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_ReportFlow( netchan_t *chan );
void Netchan_FragSend( netchan_t *chan ); void Netchan_FragSend( netchan_t *chan );
void Netchan_Clear( netchan_t *chan ); void Netchan_Clear( netchan_t *chan );

View File

@ -154,10 +154,10 @@ GNU General Public License for more details.
// decal flags // decal flags
#define FDECAL_PERMANENT 0x01 // This decal should not be removed in favor of any new decals #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_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 #define FDECAL_CUSTOM 0x04 // This is a custom clan logo and should not be saved/restored
// reserved 0x08 // reserved
// reserved 0x10 // reserved
// reserved 0x20 #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_STUDIO 0x40 // Indicates a studio decal
#define FDECAL_LOCAL_SPACE 0x80 // decal is in local space (any decal after serialization) #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_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 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 *svc_strings[svc_lastmsg+1];
extern const char *clc_strings[clc_lastmsg+1]; extern const char *clc_strings[clc_lastmsg+1];

View File

@ -410,8 +410,6 @@ extern server_t sv; // local server
extern svgame_static_t svgame; // persistant game info extern svgame_static_t svgame; // persistant game info
extern areanode_t sv_areanodes[]; // AABB dynamic tree 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_logecho;
extern convar_t mp_logfile; extern convar_t mp_logfile;
extern convar_t sv_unlag; extern convar_t sv_unlag;

View File

@ -89,24 +89,15 @@ void SV_GetChallenge( netadr_t from )
int SV_GetFragmentSize( sv_client_t *cl ) int SV_GetFragmentSize( sv_client_t *cl )
{ {
int size = FRAGMENT_SV2CL_MAX_SIZE; int cl_frag_size;
int cl_size;
if( cl->state == cs_spawned ) if( Netchan_IsLocal( &cl->netchan ))
{ return FRAGMENT_LOCAL_SIZE;
cl_size = Q_atoi( Info_ValueForKey( cl->userinfo, "cl_dlmax" ));
if( cl_size != 0 ) cl_frag_size = Q_atoi( Info_ValueForKey( cl->userinfo, "cl_dlmax" ));
{ cl_frag_size = bound( FRAGMENT_MIN_SIZE, cl_frag_size, FRAGMENT_MAX_SIZE );
size = bound( FRAGMENT_SV2CL_MIN_SIZE, cl_size, FRAGMENT_SV2CL_MAX_SIZE );
}
else
{
size = FRAGMENT_SV2CL_MIN_SIZE;
}
}
return size; return cl_frag_size;
} }
/* /*
@ -689,6 +680,58 @@ const char *SV_GetClientIDString( sv_client_t *cl )
return result; 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 SV_Ack
@ -1817,15 +1860,15 @@ static qboolean SV_DownloadFile_f( sv_client_t *cl )
{ {
if( sv_send_resources.value ) 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 )) 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 ); Netchan_FragSend( &cl->netchan );
return true; return true;
} }
@ -2064,6 +2107,7 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
if( !Q_strcmp( pcmd, "ping" )) SV_Ping( from ); if( !Q_strcmp( pcmd, "ping" )) SV_Ping( from );
else if( !Q_strcmp( pcmd, "ack" )) SV_Ack( from ); else if( !Q_strcmp( pcmd, "ack" )) SV_Ack( from );
else if( !Q_strcmp( pcmd, "info" )) SV_Info( 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, "getchallenge" )) SV_GetChallenge( from );
else if( !Q_strcmp( pcmd, "connect" )) SV_ConnectClient( from ); else if( !Q_strcmp( pcmd, "connect" )) SV_ConnectClient( from );
else if( !Q_strcmp( pcmd, "rcon" )) SV_RemoteCommand( from, msg ); 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->resourcesneeded );
SV_ClearResourceList( &cl->resourcesonhand ); SV_ClearResourceList( &cl->resourcesonhand );
for ( i = 0; i < total; i++ ) for( i = 0; i < total; i++ )
{ {
resource = Z_Malloc( sizeof( resource_t ) ); resource = Z_Malloc( sizeof( resource_t ) );
Q_strncpy( resource->szFileName, MSG_ReadString( msg ), sizeof( resource->szFileName )); Q_strncpy( resource->szFileName, MSG_ReadString( msg ), sizeof( resource->szFileName ));

View File

@ -73,7 +73,7 @@ void SV_BroadcastPrintf( sv_client_t *ignore, char *fmt, ... )
} }
// echo to console // echo to console
Con_Printf( string ); Con_DPrintf( string );
} }
/* /*

View File

@ -56,7 +56,7 @@ void SV_CreateCustomizationList( sv_client_t *cl )
} }
else 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; 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_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_WriteByte( &cl->netchan.message, pResource->type );
MSG_WriteString( &cl->netchan.message, pResource->szFileName ); MSG_WriteString( &cl->netchan.message, pResource->szFileName );
MSG_WriteShort( &cl->netchan.message, pResource->nIndex ); MSG_WriteShort( &cl->netchan.message, pResource->nIndex );
@ -391,11 +391,11 @@ int SV_EstimateNeededResources( sv_client_t *cl )
if( p->type != t_decal ) if( p->type != t_decal )
continue; 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 ) if( p->nDownloadSize != 0 )
{ {
p->ucFlags |= RES_WASMISSING; SetBits( p->ucFlags, RES_WASMISSING );
size += p->nDownloadSize; size += p->nDownloadSize;
} }
else 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++ ) for( i = 0, cl = svs.clients; i < svs.maxclients; i++, cl++ )
{ {
if( !cl->state != cs_spawned ) if( cl->state != cs_spawned )
continue; continue;
if( FBitSet( cl->flags, FCL_FAKECLIENT )) 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 ) if( cl == pClient && bSkipPlayer )
continue; 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++ ) for( i = 0, cl = svs.clients; i < svs.maxclients; i++, cl++ )
{ {
if( !cl->state != cs_spawned ) if( cl->state != cs_spawned )
continue; continue;
if( FBitSet( cl->flags, FCL_FAKECLIENT )) if( FBitSet( cl->flags, FCL_FAKECLIENT ))
@ -452,7 +452,7 @@ void SV_PropagateCustomizations( sv_client_t *pHost )
{ {
if( !pCust->bInUse ) continue; if( !pCust->bInUse ) continue;
pResource = &pCust->resource; 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 )) 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 )) if( SV_CheckFile( &cl->netchan.message, filename ))
SV_MoveToOnHandList( cl, p ); SV_MoveToOnHandList( cl, p );

View File

@ -649,8 +649,9 @@ SV_SendClientDatagram
*/ */
void SV_SendClientDatagram( sv_client_t *cl ) void SV_SendClientDatagram( sv_client_t *cl )
{ {
static byte msg_buf[MAX_INIT_MSG]; static int message_peak = 0;
sizebuf_t msg; byte msg_buf[MAX_DATAGRAM];
sizebuf_t msg;
// if we running server with fixed fps so no reason // if we running server with fixed fps so no reason
// to send updates too fast: time just not changed // 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 // for this client out to the message
if( MSG_CheckOverflow( &cl->datagram )) 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 else
{ {
@ -685,10 +686,16 @@ void SV_SendClientDatagram( sv_client_t *cl )
MSG_Clear( &cl->datagram ); 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 )) if( MSG_CheckOverflow( &msg ))
{ {
// must have room left for the packet header // 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 ); MSG_Clear( &msg );
} }
@ -862,7 +869,7 @@ void SV_SendClientMessages( void )
if( FBitSet( cl->flags, FCL_SEND_NET_MESSAGE )) if( FBitSet( cl->flags, FCL_SEND_NET_MESSAGE ))
{ {
// bandwidth choke active? // bandwidth choke active?
if( !Netchan_CanPacket( &cl->netchan )) if( !Netchan_CanPacket( &cl->netchan, cl->state == cs_spawned ))
{ {
cl->chokecount++; cl->chokecount++;
continue; continue;
@ -875,7 +882,7 @@ void SV_SendClientMessages( void )
// NOTE: we should send frame even if server is not simulated to prevent overflow // NOTE: we should send frame even if server is not simulated to prevent overflow
if( cl->state == cs_spawned ) if( cl->state == cs_spawned )
SV_SendClientDatagram( cl ); SV_SendClientDatagram( cl );
else Netchan_Transmit( &cl->netchan, 0, NULL ); // just update reliable else Netchan_TransmitBits( &cl->netchan, 0, NULL ); // just update reliable
} }
} }

View File

@ -271,7 +271,7 @@ void SV_ProcessFile( sv_client_t *cl, const char *filename )
qboolean bFound; qboolean bFound;
qboolean bError; qboolean bError;
if( filename[0] == '!' ) if( filename[0] != '!' )
{ {
Con_Printf( "Ignoring non-customization file upload of %s\n", filename ); Con_Printf( "Ignoring non-customization file upload of %s\n", filename );
return; return;
@ -971,6 +971,7 @@ void SV_Shutdown( const char *finalmsg )
SV_FreeClients(); SV_FreeClients();
svs.maxclients = 0; svs.maxclients = 0;
HPAK_FlushHostQueue();
Log_Printf( "Server shutdown\n" ); Log_Printf( "Server shutdown\n" );
Log_Close(); Log_Close();

View File

@ -1758,7 +1758,7 @@ static void SV_Physics_Entity( edict_t *ent )
// g-cont. don't alow free entities during loading because // g-cont. don't alow free entities during loading because
// this produce a corrupted baselines // 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 ); SV_FreeEdict( ent );
} }

View File

@ -461,8 +461,6 @@ void ReapplyDecal( SAVERESTOREDATA *pSaveData, decallist_t *entry, qboolean adja
// these entities might not exist over transitions, // these entities might not exist over transitions,
// so we'll use the saved plane and do a traceline instead // 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 ); MsgDev( D_ERROR, "couldn't restore entity index %i, do trace for decal\n", entityIndex );
VectorCopy( entry->position, testspot ); VectorCopy( entry->position, testspot );
@ -2254,7 +2252,8 @@ void SV_SaveGame( const char *pName )
SV_BuildSaveComment( comment, sizeof( comment )); SV_BuildSaveComment( comment, sizeof( comment ));
SV_SaveGameSlot( savename, 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
} }
/* /*