Exemplo n.º 1
0
static void
SV_Restart_f (void)
{
	client_t   *client;
	int         j;

	SZ_Clear (net_message->message);

	MSG_WriteByte (net_message->message, svc_print);
	MSG_WriteByte (net_message->message, PRINT_HIGH);
	MSG_WriteString (net_message->message,
		"\x9d\x9e\x9e\x9e\x9e\x9e\x9e\x9e"
		"\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e"
		"\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e"
		"\x9e\x9e\x9f\n"
		" Server \xf2\xe5\xf3\xf4\xe1\xf2\xf4 engaged\xae\xae\xae\n"
		"\x9d\x9e\x9e\x9e\x9e\x9e\x9e\x9e"
		"\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e"
		"\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e"
		"\x9e\x9e\x9f\n\n");
	MSG_WriteByte (net_message->message, svc_stufftext);
	MSG_WriteString (net_message->message, RESTART_CLSTUFF);
	MSG_WriteByte (net_message->message, svc_disconnect);

	for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++) {
		if (client->state >= cs_spawned)
			Netchan_Transmit (&client->netchan, net_message->message->cursize,
							  net_message->message->data);
	}
	Sys_Printf ("Shutting down: server restart, shell must relaunch server\n");
	SV_Shutdown ();
	// Error code 2 on exit, indication shell must restart the server
	exit (2);
}
Exemplo n.º 2
0
/*
=======================
SV_SendClientMessages
=======================
*/
void SV_SendClientMessages( void )
{
	sv_client_t	*cl;
	int		i;

	if( sv.state == ss_dead )
		return;

	// send a message to each connected client
	for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
	{
		if( !cl->state ) continue;
			
		if( !cl->edict || (cl->edict->v.flags & (FL_FAKECLIENT|FL_SPECTATOR)))
			continue;

		// update any userinfo packets that have changed
		if( cl->sendinfo )
		{
			cl->sendinfo = false;
			SV_FullClientUpdate( cl, &sv.multicast );
		}
                    
		if( cl->sendmovevars )
		{
			cl->sendmovevars = false;
			SV_UpdatePhysinfo( cl, &sv.multicast );
                    }

		// if the reliable message overflowed, drop the client
		if( cl->netchan.message.overflowed )
		{
			MSG_Clear( &cl->netchan.message );
			MSG_Clear( &cl->reliable );
			MSG_Clear( &cl->datagram );
			SV_BroadcastPrintf( PRINT_HIGH, "%s overflowed\n", cl->name );
			SV_DropClient( cl );
			cl->send_message = true;
		}

		// only send messages if the client has sent one
		if( !cl->send_message ) continue;

		if( cl->state == cs_spawned )
		{
			// don't overrun bandwidth
			if( SV_RateDrop( cl )) continue;
			SV_SendClientDatagram( cl );
		}
		else
		{
			// just update reliable
			if( cl->netchan.message.cursize || svs.realtime - cl->netchan.last_sent > 1000 )
				Netchan_Transmit( &cl->netchan, 0, NULL );
		}

		// yes, message really sended 
		cl->send_message = false;
	}
}
Exemplo n.º 3
0
/*
===============
CL_Netchan_Transmit
================
*/
void CL_Netchan_Transmit(netchan_t * chan, msg_t * msg)
{
	MSG_WriteByte(msg, clc_EOF);

	CL_Netchan_Encode(msg);
	Netchan_Transmit(chan, msg->cursize, msg->data);
}
Exemplo n.º 4
0
/*
 * @brief Called when the player is totally leaving the server, either willingly
 * or unwillingly. This is NOT called if the entire server is quitting
 * or crashing.
 */
void Sv_DropClient(sv_client_t *cl) {
	g_entity_t *ent;

	Mem_ClearBuffer(&cl->net_chan.message);
	Mem_ClearBuffer(&cl->datagram.buffer);

	if (cl->datagram.messages) {
		g_list_free_full(cl->datagram.messages, Mem_Free);
	}

	if (cl->state > SV_CLIENT_FREE) { // send the disconnect

		if (cl->state == SV_CLIENT_ACTIVE) { // after informing the game module
			svs.game->ClientDisconnect(cl->entity);
		}

		Net_WriteByte(&cl->net_chan.message, SV_CMD_DISCONNECT);
		Netchan_Transmit(&cl->net_chan, cl->net_chan.message.data, cl->net_chan.message.size);
	}

	if (cl->download.buffer) {
		Fs_Free(cl->download.buffer);
	}

	ent = cl->entity;

	memset(cl, 0, sizeof(*cl));

	cl->entity = ent;
	cl->last_frame = -1;
}
Exemplo n.º 5
0
/*
=================
SV_Netchan_TransmitNextFragment
=================
*/
void SV_Netchan_TransmitNextFragment(client_t *client)
{
	Netchan_TransmitNextFragment(&client->netchan);
	while (!client->netchan.unsentFragments && client->netchan_start_queue)
	{
		// make sure the netchan queue has been properly initialized (you never know)
		//if (!client->netchan_end_queue) {
		//  Com_Error(ERR_DROP, "netchan queue is not properly initialized in SV_Netchan_TransmitNextFragment");
		//}
		// the last fragment was transmitted, check wether we have queued messages
		netchan_buffer_t *netbuf = client->netchan_start_queue;

		// pop from queue
		client->netchan_start_queue = netbuf->next;
		if (!client->netchan_start_queue)
		{
			client->netchan_end_queue = NULL;
		}

		SV_Netchan_Encode(client, &netbuf->msg, netbuf->lastClientCommandString);

		Netchan_Transmit(&client->netchan, netbuf->msg.cursize, netbuf->msg.data);

		Z_Free(netbuf);
	}
}
/*
=================
SV_Netchan_TransmitNextFragment
=================
*/
void SV_Netchan_TransmitNextFragment(client_t *client) {
    Netchan_TransmitNextFragment(&client->netchan);
    if (!client->netchan.unsentFragments)
    {
        // make sure the netchan queue has been properly initialized (you never know)
        if ((!client->netchan_end_queue) && (client->state >= CS_CONNECTED)) {
            Com_Error(ERR_DROP, "netchan queue is not properly initialized in SV_Netchan_TransmitNextFragment\n");
        }
        // the last fragment was transmitted, check wether we have queued messages
        if (client->netchan_start_queue) {
            netchan_buffer_t *netbuf;
            Com_DPrintf("#462 Netchan_TransmitNextFragment: popping a queued message for transmit\n");
            netbuf = client->netchan_start_queue;
            SV_Netchan_Encode(client, &netbuf->msg);
            Netchan_Transmit(&client->netchan, netbuf->msg.cursize, netbuf->msg.data);
            // pop from queue
            client->netchan_start_queue = netbuf->next;
            if (!client->netchan_start_queue) {
                Com_DPrintf("#462 Netchan_TransmitNextFragment: emptied queue\n");
                client->netchan_end_queue = &client->netchan_start_queue;
            }
            else
                Com_DPrintf("#462 Netchan_TransmitNextFragment: remaining queued message\n");
            Z_Free(netbuf);
        }
    }    
}
Exemplo n.º 7
0
void SV_Netchan_TransmitNextInQueue(client_t *client) {
	netchan_buffer_t *netbuf;
		
	Com_DPrintf("#462 Netchan_TransmitNextFragment: popping a queued message for transmit\n");
	netbuf = client->netchan_start_queue;

#ifdef LEGACY_PROTOCOL
	if(client->compat)
		SV_Netchan_Encode(client, &netbuf->msg, netbuf->clientCommandString);
#endif

	Netchan_Transmit(&client->netchan, netbuf->msg.cursize, netbuf->msg.data);

	// pop from queue
	client->netchan_start_queue = netbuf->next;
	if(!client->netchan_start_queue)
	{
		Com_DPrintf("#462 Netchan_TransmitNextFragment: emptied queue\n");
		client->netchan_end_queue = &client->netchan_start_queue;
	}
	else
		Com_DPrintf("#462 Netchan_TransmitNextFragment: remaining queued message\n");

	Z_Free(netbuf);
}
Exemplo n.º 8
0
/*
==============
CL_CheckingResFile

==============
*/
void CL_CheckingResFile( char *pResFileName )
{
	sizebuf_t	buf;
	byte	data[32];

	if( FS_FileExists( pResFileName, false ))
		return;	// already existing

	cls.downloadcount++;

	Msg( "Starting downloads file: %s\n", pResFileName );

	if( cls.state == ca_disconnected ) return;

	BF_Init( &buf, "ClientPacket", data, sizeof( data ));
	BF_WriteByte( &buf, clc_resourcelist );
	BF_WriteString( &buf, pResFileName );

	if( !cls.netchan.remote_address.type )	// download in singleplayer ???
		cls.netchan.remote_address.type = NA_LOOPBACK;

	// make sure message will be delivered
	Netchan_Transmit( &cls.netchan, BF_GetNumBytesWritten( &buf ), BF_GetData( &buf ));

}
Exemplo n.º 9
0
/*
=======================================================================================================================================
SV_Netchan_Transmit

https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=462
If there are some unsent fragments (which may happen if the snapshots and the gamestate are fragmenting, and collide on send for
instance) then buffer them and make sure they get sent in correct order.
=======================================================================================================================================
*/
void SV_Netchan_Transmit(client_t *client, msg_t *msg) {

	MSG_WriteByte(msg, svc_EOF);

	if (client->netchan.unsentFragments || client->netchan_start_queue) {
		netchan_buffer_t *netbuf;

		Com_DPrintf("#462 SV_Netchan_Transmit: unsent fragments, stacked\n");

		netbuf = (netchan_buffer_t *)Z_Malloc(sizeof(netchan_buffer_t));
		// store the msg, we can't store it encoded, as the encoding depends on stuff we still have to finish sending
		MSG_Copy(&netbuf->msg, netbuf->msgBuffer, sizeof(netbuf->msgBuffer), msg);
#ifdef LEGACY_PROTOCOL
		if (client->compat) {
			Q_strncpyz(netbuf->clientCommandString, client->lastClientCommandString, sizeof(netbuf->clientCommandString));
		}
#endif
		netbuf->next = NULL;
		// insert it in the queue, the message will be encoded and sent later
		*client->netchan_end_queue = netbuf;
		client->netchan_end_queue = &(*client->netchan_end_queue)->next;
	} else {
#ifdef LEGACY_PROTOCOL
		if (client->compat) {
			SV_Netchan_Encode(client, msg, client->lastClientCommandString);
		}
#endif
		Netchan_Transmit(&client->netchan, msg->cursize, msg->data);
	}
}
Exemplo n.º 10
0
/*
 * Sv_DropClient
 *
 * Called when the player is totally leaving the server, either willingly
 * or unwillingly.  This is NOT called if the entire server is quitting
 * or crashing.
 */
void Sv_DropClient(sv_client_t *cl) {
	g_edict_t *ent;

	if (cl->state > SV_CLIENT_FREE) { // send the disconnect

		if (cl->state == SV_CLIENT_ACTIVE) { // after informing the game module
			svs.game->ClientDisconnect(cl->edict);
		}

		Msg_WriteByte(&cl->netchan.message, SV_CMD_DISCONNECT);
		Netchan_Transmit(&cl->netchan, cl->netchan.message.size,
				cl->netchan.message.data);
	}

	if (cl->download) {
		Fs_FreeFile(cl->download);
		cl->download = NULL;
	}

	ent = cl->edict;

	memset(cl, 0, sizeof(*cl));

	cl->edict = ent;
	cl->last_frame = -1;
}
Exemplo n.º 11
0
/*
=======================================================================================================================================
CL_Netchan_Transmit
=======================================================================================================================================
*/
void CL_Netchan_Transmit(netchan_t *chan, msg_t *msg) {

	MSG_WriteByte(msg, clc_EOF);
	Netchan_Transmit(chan, msg->cursize, msg->data);
	// transmit all fragments without delay
	while (CL_Netchan_TransmitNextFragment(chan)) {
		Com_DPrintf("WARNING: #462 unsent fragments (not supposed to happen!)\n");
	}
}
Exemplo n.º 12
0
/*
================
CL_Netchan_Transmit
================
*/
void CL_Netchan_Transmit( netchan_t *chan, msg_t* msg ) {
	MSG_WriteByte( msg, clc_EOF );
	CL_WriteBinaryMessage( msg );

	if ( !SV_GameIsSinglePlayer() ) {
		CL_Netchan_Encode( msg );
	}
	Netchan_Transmit( chan, msg->cursize, msg->data );
}
Exemplo n.º 13
0
/*
=====================
CL_SendDisconnectMessage

Sends a disconnect message to the server
=====================
*/
void CL_SendDisconnectMessage( void )
{
	sizebuf_t	buf;
	byte	data[32];

	if( cls.state == ca_disconnected ) return;

	BF_Init( &buf, "LastMessage", data, sizeof( data ));
	BF_WriteByte( &buf, clc_stringcmd );
	BF_WriteString( &buf, "disconnect" );

	if( !cls.netchan.remote_address.type )
		cls.netchan.remote_address.type = NA_LOOPBACK;

	// make sure message will be delivered
	Netchan_Transmit( &cls.netchan, BF_GetNumBytesWritten( &buf ), BF_GetData( &buf ));
	Netchan_Transmit( &cls.netchan, BF_GetNumBytesWritten( &buf ), BF_GetData( &buf ));
	Netchan_Transmit( &cls.netchan, BF_GetNumBytesWritten( &buf ), BF_GetData( &buf ));
}
Exemplo n.º 14
0
//extern byte chksum[65536];
void SV_Netchan_Transmit( client_t *client, msg_t *msg) {	//int length, const byte *data ) {
//	int i;
	MSG_WriteByte( msg, svc_EOF );
//	for(i=SV_ENCODE_START;i<msg->cursize;i++) {
//		chksum[i-SV_ENCODE_START] = msg->data[i];
//	}
//	Huff_Compress( msg, SV_ENCODE_START );
	SV_Netchan_Encode( client, msg );
	Netchan_Transmit( &client->netchan, msg->cursize, msg->data );
}
Exemplo n.º 15
0
/**
 * @brief Pumps the command cycle, sending the most recently gathered movement to the server.
 * @details Commands must meet a certain duration, in milliseconds, in order to be sent. This
 * prevents saturating the network channel with very small movement commands, which are also
 * problematic for the physics and prediction code.
 */
void Cl_SendCommands(void) {

	const uint32_t delta = quetoo.ticks - cls.net_chan.last_sent;

	if (delta < 8 && !r_swap_interval->value) {
		return;
	}

	switch (cls.state) {
		case CL_CONNECTED:
		case CL_LOADING:

			if (cls.net_chan.message.size || delta > 1000) {
				Netchan_Transmit(&cls.net_chan, NULL, 0);
				cl.packet_counter++;
			}

			break;

		case CL_ACTIVE:

			Cl_WriteUserInfoCommand();

			Cl_FinalizeMovementCommand();

			mem_buf_t buf;
			byte data[sizeof(cl_cmd_t) * 3];

			Mem_InitBuffer(&buf, data, sizeof(data));

			Cl_WriteMovementCommand(&buf);

			Netchan_Transmit(&cls.net_chan, buf.data, buf.size);
			cl.packet_counter++;

			Cl_InitMovementCommand();

			break;

		default:
			break;
	}
}
Exemplo n.º 16
0
/*
===============
CL_Netchan_Transmit
================
*/
void CL_Netchan_Transmit( netchan_t *chan, msg_t* msg ) {
//	int i;
	MSG_WriteByte( msg, clc_EOF );
//	for(i=CL_ENCODE_START;i<msg->cursize;i++) {
//		chksum[i-CL_ENCODE_START] = msg->data[i];
//	}

//	Huff_Compress( msg, CL_ENCODE_START );
	CL_Netchan_Encode( msg );
	Netchan_Transmit( chan, msg->cursize, msg->data );
}
Exemplo n.º 17
0
/*
 * ==================
 * SV_FinalMessage
 *
 * Used by SV_Shutdown to send a final message to all
 * connected clients before the server goes down.  The messages are sent immediately,
 * not just stuck on the outgoing message list, because the server is going
 * to totally exit after returning from this function.
 * ==================
 */
void SV_FinalMessage(char *message, qboolean reconnect)
{
    int      i;
    client_t *cl;

    SZ_Clear(&net_message);
    MSG_WriteByte(&net_message, svc_print);
    MSG_WriteByte(&net_message, PRINT_HIGH);
    MSG_WriteString(&net_message, message);

    if (reconnect)
    {
        MSG_WriteByte(&net_message, svc_reconnect);
    }
    else
    {
        MSG_WriteByte(&net_message, svc_disconnect);
    }

    // send it twice
    // stagger the packets to crutch operating system limited buffers

    for (i = 0, cl = svs.clients; i < maxclients->value; i++, cl++)
    {
        if (cl->state >= cs_connected)
        {
            Netchan_Transmit(&cl->netchan, net_message.cursize
                             , net_message.data);
        }
    }

    for (i = 0, cl = svs.clients; i < maxclients->value; i++, cl++)
    {
        if (cl->state >= cs_connected)
        {
            Netchan_Transmit(&cl->netchan, net_message.cursize
                             , net_message.data);
        }
    }
}
Exemplo n.º 18
0
/*
=======================
SV_SendClientDatagram
=======================
*/
bool SV_SendClientDatagram( sv_client_t *cl )
{
	byte		msg_buf[MAX_MSGLEN];
	sizebuf_t		msg;

	SV_BuildClientFrame( cl );

	MSG_Init( &msg, msg_buf, sizeof( msg_buf ));

	// send over all the relevant entity_state_t
	// and the player state
	SV_WriteFrameToClient( cl, &msg );

	// copy the accumulated reliable datagram
	// for this client out to the message
	// it is necessary for this to be after the WriteEntities
	// so that entity references will be current
	if( cl->reliable.overflowed ) MsgDev( D_ERROR, "reliable datagram overflowed for %s\n", cl->name );
	else MSG_WriteData( &msg, cl->reliable.data, cl->reliable.cursize );
	MSG_Clear( &cl->reliable );

	if( msg.overflowed )
	{	
		// must have room left for the packet header
		MsgDev( D_WARN, "msg overflowed for %s\n", cl->name );
		MSG_Clear( &msg );
	}

	// copy the accumulated multicast datagram
	// for this client out to the message
	// it is necessary for this to be after the WriteEntities
	// so that entity references will be current
	if( cl->datagram.overflowed ) MsgDev( D_WARN, "datagram overflowed for %s\n", cl->name );
	else MSG_WriteData( &msg, cl->datagram.data, cl->datagram.cursize );
	MSG_Clear( &cl->datagram );

	if( msg.overflowed )
	{	
		// must have room left for the packet header
		MsgDev( D_WARN, "msg overflowed for %s\n", cl->name );
		MSG_Clear( &msg );
	}

	// send the datagram
	Netchan_Transmit( &cl->netchan, msg.cursize, msg.data );

	// record the size for rate estimation
	cl->message_size[sv.framenum % RATE_MESSAGES] = msg.cursize;

	return true;
}
Exemplo n.º 19
0
/*
=======================================================================================================================================
CL_Netchan_Transmit
=======================================================================================================================================
*/
void CL_Netchan_Transmit(netchan_t *chan, msg_t *msg) {

	MSG_WriteByte(msg, clc_EOF);
#ifdef LEGACY_PROTOCOL
	if (chan->compat) {
		CL_Netchan_Encode(msg);
	}
#endif
	Netchan_Transmit(chan, msg->cursize, msg->data);
	// transmit all fragments without delay
	while (CL_Netchan_TransmitNextFragment(chan)) {
		Com_DPrintf("WARNING: #462 unsent fragments (not supposed to happen!)\n");
	}
}
Exemplo n.º 20
0
/*
===============
CL_Netchan_Transmit
================
*/
void CL_Netchan_Transmit( netchan_t *chan, msg_t* msg )
{
	MSG_WriteByte( msg, clc_EOF );

	CL_Netchan_Encode( msg );
	if( !Netchan_Transmit( chan, msg->cursize, msg->data ) )
	{
		// Don't call Com_Error if we're already disconnecting!
		if( com_errorEntered )
			return;

		// Quickly detect dead connections: (may want to put in some relaxation here?)
		Com_Error( ERR_DROP, "@MENUS_LOST_CONNECTION" );
	}
}
Exemplo n.º 21
0
/*
===============
SV_Netchan_Transmit

TTimo
show_bug.cgi?id=462
if there are some unsent fragments (which may happen if the snapshots
and the gamestate are fragmenting, and collide on send for instance)
then buffer them and make sure they get sent in correct order
================
*/
void SV_Netchan_Transmit( client_t *client, msg_t *msg )
{
	//int length, const byte *data ) {
	MSG_WriteByte( msg, svc_EOF );
	SV_WriteBinaryMessage( msg, client );

	if ( client->netchan.unsentFragments )
	{
		netchan_buffer_t *netbuf;

		//Com_DPrintf("SV_Netchan_Transmit: there are unsent fragments remaining\n");
		netbuf = ( netchan_buffer_t * ) Z_Malloc( sizeof( netchan_buffer_t ) );

		// store the msg, we can't store it encoded, as the encoding depends on stuff we still have to finish sending
		MSG_Copy( &netbuf->msg, netbuf->msgBuffer, sizeof( netbuf->msgBuffer ), msg );

		// copy the command, since the command number used for encryption is
		// already compressed in the buffer, and receiving a new command would
		// otherwise lose the proper encryption key
		strcpy( netbuf->lastClientCommandString, client->lastClientCommandString );

		// insert it in the queue, the message will be encoded and sent later
		//% *client->netchan_end_queue = netbuf;
		//% client->netchan_end_queue = &(*client->netchan_end_queue)->next;
		netbuf->next = NULL;

		if ( !client->netchan_start_queue )
		{
			client->netchan_start_queue = netbuf;
		}
		else
		{
			client->netchan_end_queue->next = netbuf;
		}

		client->netchan_end_queue = netbuf;

		// emit the next fragment of the current message for now
		Netchan_TransmitNextFragment( &client->netchan );
	}
	else
	{
		SV_Netchan_Encode( client, msg, client->lastClientCommandString );
		Netchan_Transmit( &client->netchan, msg->cursize, msg->data );
	}
}
Exemplo n.º 22
0
/*
==================
SV_FinalMessage

Used by SV_Error and SV_Quit_f to send a final message to all connected
clients before the server goes down.  The messages are sent immediately,
not just stuck on the outgoing message list, because the server is going
to totally exit after returning from this function.
==================
*/
void SV_FinalMessage (const char *message)
{
	int			i;
	client_t	*cl;

	SZ_Clear (&net_message);
	MSG_WriteByte (&net_message, svc_print);
	MSG_WriteByte (&net_message, PRINT_HIGH);
	MSG_WriteString (&net_message, message);
	MSG_WriteByte (&net_message, svc_disconnect);

	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
	{
		if (cl->state >= cs_spawned)
			Netchan_Transmit (&cl->netchan, net_message.cursize, net_message.data);
	}
}
Exemplo n.º 23
0
/*
===============
SV_Netchan_Transmit

TTimo
show_bug.cgi?id=462
if there are some unsent fragments (which may happen if the snapshots
and the gamestate are fragmenting, and collide on send for instance)
then buffer them and make sure they get sent in correct order
================
*/
void SV_Netchan_Transmit( client_t *client, msg_t *msg ) {   //int length, const byte *data ) {
	MSG_WriteByte( msg, svc_EOF );
	if ( client->netchan.unsentFragments ) {
		netchan_buffer_t *netbuf;
		//Com_DPrintf("SV_Netchan_Transmit: there are unsent fragments remaining\n");
		netbuf = (netchan_buffer_t *)Z_Malloc( sizeof( netchan_buffer_t ) );
		// store the msg, we can't store it encoded, as the encoding depends on stuff we still have to finish sending
		MSG_Copy( &netbuf->msg, netbuf->msgBuffer, sizeof( netbuf->msgBuffer ), msg );
		netbuf->next = NULL;
		// insert it in the queue, the message will be encoded and sent later
		*client->netchan_end_queue = netbuf;
		client->netchan_end_queue = &( *client->netchan_end_queue )->next;
		// emit the next fragment of the current message for now
		Netchan_TransmitNextFragment( &client->netchan );
	} else {
		SV_Netchan_Encode( client, msg );
		Netchan_Transmit( &client->netchan, msg->cursize, msg->data );
	}
}
Exemplo n.º 24
0
/*
* SV_Netchan_Transmit
*/
bool SV_Netchan_Transmit( netchan_t *netchan, msg_t *msg )
{
	int zerror;

	// if we got here with unsent fragments, fire them all now
	if( !Netchan_PushAllFragments( netchan ) )
		return false;

	if( sv_compresspackets->integer )
	{
		zerror = Netchan_CompressMessage( msg );
		if( zerror < 0 )
		{          // it's compression error, just send uncompressed
			Com_DPrintf( "SV_Netchan_Transmit (ignoring compression): Compression error %i\n", zerror );
		}
	}

	return Netchan_Transmit( netchan, msg );
}
Exemplo n.º 25
0
//extern byte chksum[65536];
void SV_Netchan_Transmit( client_t *client, msg_t *msg) {	//int length, const byte *data ) {

	// To avoid endless recursion:
	static bool droppingClient = false;

	MSG_WriteByte( msg, svc_EOF );
	SV_Netchan_Encode( client, msg );

	if( !Netchan_Transmit( &client->netchan, msg->cursize, msg->data ) &&
		!droppingClient )
	{
		// Don't fail when we get around to sending the removepeer to this person again!
		droppingClient = true;

		// Quick detection of dropped clients!
		SV_DropClient( client, "@MENUS_LOST_CONNECTION" );

		droppingClient = false;
	}
}
Exemplo n.º 26
0
/*
* TV_Downstream_Netchan_Transmit
*/
static qboolean TV_Downstream_Netchan_Transmit( netchan_t *netchan, msg_t *msg )
{
	int zerror;

	// if we got here with unsent fragments, fire them all now
	if( !Netchan_PushAllFragments( netchan ) )
		return qfalse;

	if( tv_compresspackets->integer )
	{
		zerror = Netchan_CompressMessage( msg );
		if( zerror < 0 )
		{
			// it's compression error, just send uncompressed
			Com_Printf( "Compression error (%i), sending packet uncompressed\n", zerror );
		}
	}

	return Netchan_Transmit( netchan, msg );
}
Exemplo n.º 27
0
/*
===============
SV_Netchan_Transmit

TTimo
show_bug.cgi?id=462
if there are some unsent fragments (which may happen if the snapshots
and the gamestate are fragmenting, and collide on send for instance)
then buffer them and make sure they get sent in correct order
================
*/
void SV_Netchan_Transmit( client_t *client, msg_t *msg )
{
    //int length, const byte *data ) {
    MSG_WriteByte( msg, svc_EOF );
    SV_WriteBinaryMessage( msg, client );

    if ( client->netchan.unsentFragments )
    {
        netchan_buffer_t *netbuf;

        //Log::Debug("SV_Netchan_Transmit: there are unsent fragments remaining");
        netbuf = ( netchan_buffer_t * ) Z_Malloc( sizeof( netchan_buffer_t ) );

        MSG_Copy( &netbuf->msg, netbuf->msgBuffer, sizeof( netbuf->msgBuffer ), msg );

        // copy the command, since the command number used for encryption is
        // already compressed in the buffer, and receiving a new command would
        // otherwise lose the proper encryption key
        strcpy( netbuf->lastClientCommandString, client->lastClientCommandString );

        netbuf->next = nullptr;

        if ( !client->netchan_start_queue )
        {
            client->netchan_start_queue = netbuf;
        }
        else
        {
            client->netchan_end_queue->next = netbuf;
        }

        client->netchan_end_queue = netbuf;

        // emit the next fragment of the current message for now
        Netchan_TransmitNextFragment( &client->netchan );
    }
    else
    {
        Netchan_Transmit( &client->netchan, msg->cursize, msg->data );
    }
}
Exemplo n.º 28
0
/*
=======================================================================================================================================
SV_Netchan_TransmitNextInQueue
=======================================================================================================================================
*/
void SV_Netchan_TransmitNextInQueue(client_t *client) {
	netchan_buffer_t *netbuf;

	Com_DPrintf("Netchan_TransmitNextFragment: popping a queued message for transmit\n");

	netbuf = client->netchan_start_queue;

	SV_Netchan_Encode(client, &netbuf->msg, netbuf->lastClientCommandString);
	Netchan_Transmit(&client->netchan, netbuf->msg.cursize, netbuf->msg.data);
	// pop from queue
	client->netchan_start_queue = netbuf->next;

	if (!client->netchan_start_queue) {
		Com_DPrintf("Netchan_TransmitNextFragment: emptied queue\n");
		client->netchan_end_queue = &client->netchan_start_queue;
	} else {
		Com_DPrintf("Netchan_TransmitNextFragment: remaining queued message\n");
	}

	Z_Free(netbuf);
}
Exemplo n.º 29
0
void SV_SendMessageToClient( msg_t *msg, client_t *client ) {
	int			rateMsec;

	// record information about the message
	client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSize = msg->cursize;
	client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSent = sv.time;

	// send the datagram
	Netchan_Transmit( &client->netchan, msg->cursize, msg->data );

	// set nextSnapshotTime based on rate and requested number of updates

	// local clients get snapshots every frame (FIXME: also treat LAN clients)
	if ( client->netchan.remoteAddress.type == NA_LOOPBACK ) {
		client->nextSnapshotTime = sv.time - 1;
		return;
	}

	// normal rate / snapshotMsec calculation
	rateMsec = ( msg->cursize + HEADER_RATE_BYTES ) * 1000 / client->rate;
	if ( rateMsec < client->snapshotMsec ) {
		rateMsec = client->snapshotMsec;
		client->rateDelayed = qfalse;
	} else {
		client->rateDelayed = qtrue;
	}

	client->nextSnapshotTime = sv.time + rateMsec;

	// if we haven't gotten a message from the client in over a second, we will
	// drop to only sending one snapshot a second until they timeout
	if ( sv.time - client->lastPacketTime > 1000 || client->state != CS_ACTIVE ) {
		if ( client->nextSnapshotTime < sv.time + 1000 ) {
			client->nextSnapshotTime = sv.time + 1000;
		}
		return;
	}

}
Exemplo n.º 30
0
void CL_SendCmd (void)
{
	sizebuf_t buf;
	byte data[128];
	usercmd_t *cmd, *oldcmd;
	int i, checksumIndex, lost;
	qbool dontdrop;
	static float pps_balance = 0;
	static int dropcount = 0;

	if (cls.demoplayback && !cls.mvdplayback)
		return; // sendcmds come from the demo

	#ifdef FTE_PEXT_CHUNKEDDOWNLOADS
	CL_SendChunkDownloadReq();
	#endif

	// save this command off for prediction
	i = cls.netchan.outgoing_sequence & UPDATE_MASK;
	cmd = &cl.frames[i].cmd;
	cl.frames[i].senttime = cls.realtime;
	cl.frames[i].receivedtime = -1;		// we haven't gotten a reply yet

	// update network stats table
	i = cls.netchan.outgoing_sequence&NETWORK_STATS_MASK;
	network_stats[i].delta = 0;     // filled-in later
	network_stats[i].sentsize = 0;  // filled-in later
	network_stats[i].senttime = cls.realtime;
	network_stats[i].receivedtime = -1;

	// get basic movement from keyboard
	CL_BaseMove (cmd);

	// allow mice or other external controllers to add to the move

	if (cl_independentPhysics.value == 0 || (physframe && cl_independentPhysics.value != 0))
	{
		IN_Move(cmd);
	}

	// if we are spectator, try autocam
	if (cl.spectator)
		Cam_Track(cmd);

	CL_FinishMove(cmd);
	cmdtime_msec += cmd->msec;

	Cam_FinishMove(cmd);

	if (cls.mvdplayback)
	{
		CL_CalcPlayerFPS(&cl.players[cl.playernum], cmd->msec);
        cls.netchan.outgoing_sequence++;
		return;
	}

	SZ_Init (&buf, data, sizeof(data));

	SZ_Write (&buf, cls.cmdmsg.data, cls.cmdmsg.cursize);
	if (cls.cmdmsg.overflowed)
		Com_DPrintf("cls.cmdmsg overflowed\n");
	SZ_Clear (&cls.cmdmsg);

	// begin a client move command
	MSG_WriteByte (&buf, clc_move);

	// save the position for a checksum byte
	checksumIndex = buf.cursize;
	MSG_WriteByte (&buf, 0);

	// write our lossage percentage
	lost = CL_CalcNet();
	MSG_WriteByte (&buf, (byte)lost);

	// send this and the previous two cmds in the message, so if the last packet was dropped, it can be recovered
	dontdrop = false;

	i = (cls.netchan.outgoing_sequence - 2) & UPDATE_MASK;
	cmd = &cl.frames[i].cmd;
	if (cl_c2sImpulseBackup.value >= 2)
		dontdrop = dontdrop || cmd->impulse;
	MSG_WriteDeltaUsercmd (&buf, &nullcmd, cmd);
	oldcmd = cmd;

	i = (cls.netchan.outgoing_sequence - 1) & UPDATE_MASK;
	cmd = &cl.frames[i].cmd;
	if (cl_c2sImpulseBackup.value >= 3)
		dontdrop = dontdrop || cmd->impulse;
	MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
	oldcmd = cmd;

	i = (cls.netchan.outgoing_sequence) & UPDATE_MASK;
	cmd = &cl.frames[i].cmd;
	if (cl_c2sImpulseBackup.value >= 1)
		dontdrop = dontdrop || cmd->impulse;
	MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);

	// calculate a checksum over the move commands
	buf.data[checksumIndex] = COM_BlockSequenceCRCByte(
		buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1,
		cls.netchan.outgoing_sequence);

	// request delta compression of entities
	if (cls.netchan.outgoing_sequence - cl.validsequence >= UPDATE_BACKUP - 1)
	{
		cl.validsequence = 0;
		cl.delta_sequence = 0;
	}

	if (cl.delta_sequence && !cl_nodelta.value && cls.state == ca_active)
	{
		cl.frames[cls.netchan.outgoing_sequence & UPDATE_MASK].delta_sequence = cl.delta_sequence;
		MSG_WriteByte (&buf, clc_delta);
		MSG_WriteByte (&buf, cl.delta_sequence & 255);

		// network stats table
		network_stats[cls.netchan.outgoing_sequence&NETWORK_STATS_MASK].delta = 1;
	}
	else
	{
		cl.frames[cls.netchan.outgoing_sequence & UPDATE_MASK].delta_sequence = -1;
	}

	if (cls.demorecording)
		CL_WriteDemoCmd (cmd);

	if (cl_c2spps.value)
	{
		pps_balance += cls.frametime;
		// never drop more than 2 messages in a row -- that'll cause PL
		// and don't drop if one of the last two movemessages have an impulse
		if (pps_balance > 0 || dropcount >= 2 || dontdrop)
		{
			float	pps;
			pps = cl_c2spps.value;
			if (pps < 10) pps = 10;
			if (pps > 72) pps = 72;
			pps_balance -= 1 / pps;
			// bound pps_balance. FIXME: is there a better way?
			if (pps_balance > 0.1) pps_balance = 0.1;
			if (pps_balance < -0.1) pps_balance = -0.1;
			dropcount = 0;
		}
		else
		{
			// don't count this message when calculating PL
			cl.frames[i].receivedtime = -3;
			// drop this message
			cls.netchan.outgoing_sequence++;
			dropcount++;
			return;
		}
	}
	else
	{
		pps_balance = 0;
		dropcount = 0;
	}

#ifdef FTE_PEXT2_VOICECHAT
	S_Voip_Transmit(clc_voicechat, &buf);
#endif

	cl.frames[cls.netchan.outgoing_sequence&UPDATE_MASK].sentsize = buf.cursize + 8;    // 8 = PACKET_HEADER
	// network stats table
	network_stats[cls.netchan.outgoing_sequence&NETWORK_STATS_MASK].sentsize = buf.cursize + 8;

	// deliver the message
	Netchan_Transmit (&cls.netchan, buf.cursize, buf.data);
}