Пример #1
0
/*
=================
CL_SendDefaultCmd
=================
*/
static void CL_SendDefaultCmd( void ) {
    size_t cursize, checksumIndex;
    usercmd_t *cmd, *oldcmd;
    client_history_t *history;

    // archive this packet
    history = &cl.history[cls.netchan->outgoing_sequence & CMD_MASK];
    history->cmdNumber = cl.cmdNumber;
    history->sent = cls.realtime;    // for ping calculation
    history->rcvd = 0;

    cl.lastTransmitCmdNumber = cl.cmdNumber;

    // see if we are ready to send this packet
    if( !ready_to_send_hacked() ) {
        cls.netchan->outgoing_sequence++; // just drop the packet
        return;
    }

    cl.lastTransmitTime = cls.realtime;
    cl.lastTransmitCmdNumberReal = cl.cmdNumber;

    // begin a client move command
    MSG_WriteByte( clc_move );

    // save the position for a checksum byte
    checksumIndex = 0;
    if( cls.serverProtocol <= PROTOCOL_VERSION_DEFAULT ) {
        checksumIndex = msg_write.cursize;
        SZ_GetSpace( &msg_write, 1 );
    }

    // let the server know what the last frame we
    // got was, so the next message can be delta compressed
    if( cl_nodelta->integer || !cl.frame.valid /*|| cls.demowaiting*/ ) {
        MSG_WriteLong( -1 ); // no compression
    } else {
        MSG_WriteLong( cl.frame.number );
    }

    // send this and the previous cmds in the message, so
    // if the last packet was dropped, it can be recovered
    cmd = &cl.cmds[( cl.cmdNumber - 2 ) & CMD_MASK];
    MSG_WriteDeltaUsercmd( NULL, cmd, cls.protocolVersion );
    MSG_WriteByte( cl.lightlevel );
    oldcmd = cmd;

    cmd = &cl.cmds[( cl.cmdNumber - 1 ) & CMD_MASK];
    MSG_WriteDeltaUsercmd( oldcmd, cmd, cls.protocolVersion );
    MSG_WriteByte( cl.lightlevel );
    oldcmd = cmd;

    cmd = &cl.cmds[cl.cmdNumber & CMD_MASK];
    MSG_WriteDeltaUsercmd( oldcmd, cmd, cls.protocolVersion );
    MSG_WriteByte( cl.lightlevel );

    if( cls.serverProtocol <= PROTOCOL_VERSION_DEFAULT ) {
        // calculate a checksum over the move commands
        msg_write.data[checksumIndex] = COM_BlockSequenceCRCByte(
            msg_write.data + checksumIndex + 1,
            msg_write.cursize - checksumIndex - 1,
            cls.netchan->outgoing_sequence );
    }

    P_FRAMES++;

    //
    // deliver the message
    //
    cursize = cls.netchan->Transmit( cls.netchan, msg_write.cursize, msg_write.data, 1 );
#ifdef _DEBUG
    if( cl_showpackets->integer ) {
        Com_Printf( "%"PRIz" ", cursize );
    }
#endif

    SZ_Clear( &msg_write );
}
Пример #2
0
int	Datagram_GetMessage (qsocket_t *sock)
{
	unsigned int	length;
	unsigned int	flags;
	int				ret = 0;
	struct qsockaddr readaddr;
	unsigned int	sequence;
	unsigned int	count;

	if (!sock->canSend)
		if ((net_time - sock->lastSendTime) > 1.0)
			ReSendMessage (sock);

	while(1)
	{	
		length = sfunc.Read (sock->socket, (byte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr);

//	if ((rand() & 255) > 220)
//		continue;

		if (length == 0)
			break;

// >>> FIX: For Nintendo Wii using devkitPPC / libogc
// sfunc.Read might return error values other than -1. Changing:
		//if (length == -1)
		if (length < 0)
// <<< FIX
		{
			Con_Printf("Read error\n");
			return -1;
		}

		if (sfunc.AddrCompare(&readaddr, &sock->addr) != 0)
		{
#ifdef DEBUG
			Con_DPrintf("Forged packet received\n");
			Con_DPrintf("Expected: %s\n", StrAddr (&sock->addr));
			Con_DPrintf("Received: %s\n", StrAddr (&readaddr));
#endif
			continue;
		}

		if (length < NET_HEADERSIZE)
		{
			shortPacketCount++;
			continue;
		}

		length = BigLong(packetBuffer.length);
		flags = length & (~NETFLAG_LENGTH_MASK);
		length &= NETFLAG_LENGTH_MASK;

		if (flags & NETFLAG_CTL)
			continue;

		sequence = BigLong(packetBuffer.sequence);
		packetsReceived++;

		if (flags & NETFLAG_UNRELIABLE)
		{
			if (sequence < sock->unreliableReceiveSequence)
			{
				Con_DPrintf("Got a stale datagram\n");
				ret = 0;
				break;
			}
			if (sequence != sock->unreliableReceiveSequence)
			{
				count = sequence - sock->unreliableReceiveSequence;
				droppedDatagrams += count;
				Con_DPrintf("Dropped %u datagram(s)\n", count);
			}
			sock->unreliableReceiveSequence = sequence + 1;

			length -= NET_HEADERSIZE;

			SZ_Clear (&net_message);
			SZ_Write (&net_message, packetBuffer.data, length);

			ret = 2;
			break;
		}

		if (flags & NETFLAG_ACK)
		{
			if (sequence != (sock->sendSequence - 1))
			{
				Con_DPrintf("Stale ACK received\n");
				continue;
			}
			if (sequence == sock->ackSequence)
			{
				sock->ackSequence++;
				if (sock->ackSequence != sock->sendSequence)
					Con_DPrintf("ack sequencing error\n");
			}
			else
			{
				Con_DPrintf("Duplicate ACK received\n");
				continue;
			}
			sock->sendMessageLength -= MAX_DATAGRAM;
			if (sock->sendMessageLength > 0)
			{
				Q_memcpy(sock->sendMessage, sock->sendMessage+MAX_DATAGRAM, sock->sendMessageLength);
				sock->sendNext = true;
			}
			else
			{
				sock->sendMessageLength = 0;
				sock->canSend = true;
			}
			continue;
		}

		if (flags & NETFLAG_DATA)
		{
			packetBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK);
			packetBuffer.sequence = BigLong(sequence);
			sfunc.Write (sock->socket, (byte *)&packetBuffer, NET_HEADERSIZE, &readaddr);

			if (sequence != sock->receiveSequence)
			{
				receivedDuplicateCount++;
				continue;
			}
			sock->receiveSequence++;

			length -= NET_HEADERSIZE;

			if (flags & NETFLAG_EOM)
			{
				SZ_Clear(&net_message);
				SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength);
				SZ_Write(&net_message, packetBuffer.data, length);
				sock->receiveMessageLength = 0;

				ret = 1;
				break;
			}

			Q_memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length);
			sock->receiveMessageLength += length;
			continue;
		}
	}

	if (sock->sendNext)
		SendMessageNext (sock);

	return ret;
}
Пример #3
0
static qsocket_t *_Datagram_CheckNewConnections (void)
{
	struct qsockaddr clientaddr;
	struct qsockaddr newaddr;
	int			newsock;
	int			acceptsock;
	qsocket_t	*sock;
	qsocket_t	*s;
	int			len;
	int			command;
	int			control;
	int			ret;

	acceptsock = dfunc.CheckNewConnections();
	if (acceptsock == -1)
		return NULL;

	SZ_Clear(&net_message);

	len = dfunc.Read (acceptsock, net_message.data, net_message.maxsize, &clientaddr);
	if (len < sizeof(int))
		return NULL;
	net_message.cursize = len;

	MSG_BeginReading ();
	control = BigLong(*((int *)net_message.data));
	MSG_ReadLong();
	if (control == -1)
		return NULL;
	if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)
		return NULL;
	if ((control & NETFLAG_LENGTH_MASK) != len)
		return NULL;

	command = MSG_ReadByte();
	if (command == CCREQ_SERVER_INFO)
	{
		if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0)
			return NULL;

		SZ_Clear(&net_message);
		// save space for the header, filled in later
		MSG_WriteLong(&net_message, 0);
		MSG_WriteByte(&net_message, CCREP_SERVER_INFO);
		dfunc.GetSocketAddr(acceptsock, &newaddr);
		MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));
		MSG_WriteString(&net_message, hostname.string);
		MSG_WriteString(&net_message, sv.name);
		MSG_WriteByte(&net_message, net_activeconnections);
		MSG_WriteByte(&net_message, svs.maxclients);
		MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
		SZ_Clear(&net_message);
		return NULL;
	}

	if (command == CCREQ_PLAYER_INFO)
	{
		int			playerNumber;
		int			activeNumber;
		int			clientNumber;
		client_t	*client;
		
		playerNumber = MSG_ReadByte();
		activeNumber = -1;
		for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++)
		{
			if (client->active)
			{
				activeNumber++;
				if (activeNumber == playerNumber)
					break;
			}
		}
		if (clientNumber == svs.maxclients)
			return NULL;

		SZ_Clear(&net_message);
		// save space for the header, filled in later
		MSG_WriteLong(&net_message, 0);
		MSG_WriteByte(&net_message, CCREP_PLAYER_INFO);
		MSG_WriteByte(&net_message, playerNumber);
		MSG_WriteString(&net_message, client->name);
		MSG_WriteLong(&net_message, client->colors);
		MSG_WriteLong(&net_message, (int)client->edict->v.frags);
		MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime));
		MSG_WriteString(&net_message, client->netconnection->address);
		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
		SZ_Clear(&net_message);

		return NULL;
	}

	if (command == CCREQ_RULE_INFO)
	{
		char	*prevCvarName;
		cvar_t	*var;

		// find the search start location
		prevCvarName = MSG_ReadString();
		if (*prevCvarName)
		{
			var = Cvar_FindVar (prevCvarName);
			if (!var)
				return NULL;
			var = var->next;
		}
		else
			var = cvar_vars;

		// search for the next server cvar
		while (var)
		{
			if (var->server)
				break;
			var = var->next;
		}

		// send the response

		SZ_Clear(&net_message);
		// save space for the header, filled in later
		MSG_WriteLong(&net_message, 0);
		MSG_WriteByte(&net_message, CCREP_RULE_INFO);
		if (var)
		{
			MSG_WriteString(&net_message, var->name);
			MSG_WriteString(&net_message, var->string);
		}
		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
		SZ_Clear(&net_message);

		return NULL;
	}

	if (command != CCREQ_CONNECT)
		return NULL;

	if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0)
		return NULL;

	if (MSG_ReadByte() != NET_PROTOCOL_VERSION)
	{
		SZ_Clear(&net_message);
		// save space for the header, filled in later
		MSG_WriteLong(&net_message, 0);
		MSG_WriteByte(&net_message, CCREP_REJECT);
		MSG_WriteString(&net_message, "Incompatible version.\n");
		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
		SZ_Clear(&net_message);
		return NULL;
	}

#ifdef BAN_TEST
	// check for a ban
	if (clientaddr.sa_family == AF_INET)
	{
		unsigned long testAddr;
		testAddr = ((struct sockaddr_in *)&clientaddr)->sin_addr.s_addr;
		if ((testAddr & banMask) == banAddr)
		{
			SZ_Clear(&net_message);
			// save space for the header, filled in later
			MSG_WriteLong(&net_message, 0);
			MSG_WriteByte(&net_message, CCREP_REJECT);
			MSG_WriteString(&net_message, "You have been banned.\n");
			*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
			dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
			SZ_Clear(&net_message);
			return NULL;
		}
	}
#endif

	// see if this guy is already connected
	for (s = net_activeSockets; s; s = s->next)
	{
		if (s->driver != net_driverlevel)
			continue;
		ret = dfunc.AddrCompare(&clientaddr, &s->addr);
		if (ret >= 0)
		{
			// is this a duplicate connection reqeust?
			if (ret == 0 && net_time - s->connecttime < 2.0)
			{
				// yes, so send a duplicate reply
				SZ_Clear(&net_message);
				// save space for the header, filled in later
				MSG_WriteLong(&net_message, 0);
				MSG_WriteByte(&net_message, CCREP_ACCEPT);
				dfunc.GetSocketAddr(s->socket, &newaddr);
				MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
				*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
				dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
				SZ_Clear(&net_message);
				return NULL;
			}
			// it's somebody coming back in from a crash/disconnect
			// so close the old qsocket and let their retry get them back in
			NET_Close(s);
			return NULL;
		}
	}

	// allocate a QSocket
	sock = NET_NewQSocket ();
	if (sock == NULL)
	{
		// no room; try to let him know
		SZ_Clear(&net_message);
		// save space for the header, filled in later
		MSG_WriteLong(&net_message, 0);
		MSG_WriteByte(&net_message, CCREP_REJECT);
		MSG_WriteString(&net_message, "Server is full.\n");
		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
		SZ_Clear(&net_message);
		return NULL;
	}

	// allocate a network socket
	newsock = dfunc.OpenSocket(0);
	if (newsock == -1)
	{
		NET_FreeQSocket(sock);
		return NULL;
	}

	// connect to the client
	if (dfunc.Connect (newsock, &clientaddr) == -1)
	{
		dfunc.CloseSocket(newsock);
		NET_FreeQSocket(sock);
		return NULL;
	}

	// everything is allocated, just fill in the details	
	sock->socket = newsock;
	sock->landriver = net_landriverlevel;
	sock->addr = clientaddr;
	Q_strcpy(sock->address, dfunc.AddrToString(&clientaddr));

	// send him back the info about the server connection he has been allocated
	SZ_Clear(&net_message);
	// save space for the header, filled in later
	MSG_WriteLong(&net_message, 0);
	MSG_WriteByte(&net_message, CCREP_ACCEPT);
	dfunc.GetSocketAddr(newsock, &newaddr);
	MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
//	MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));
	*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
	dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
	SZ_Clear(&net_message);

	return sock;
}
Пример #4
0
int	Datagram_GetMessage (qsocket_t *sock)
{
	unsigned int	length;
	unsigned int	flags;
	int				ret = 0;
	struct qsockaddr readaddr;
	unsigned int	sequence;
	unsigned int	count;

	if (!sock->canSend)
		if ((net_time - sock->lastSendTime) > 1.0)
			ReSendMessage (sock);

	while(1)
	{	
		length = sock->landriver->Read(sock->socket, (byte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr);
/*
		// for testing packet loss effects
		if ((rand() & 255) > 220)
			continue;
*/
		if (length == 0)
			break;

		if ((int)length == -1)
		{
			Con_Printf("Read error\n");
			return -1;
		}

		// added !sock->net_wait (NAT fix)
		if (!sock->net_wait && sock->landriver->AddrCompare(&readaddr, &sock->addr) != 0)
		{
#ifdef DEBUG
			Con_DPrintf("Forged packet received\n");
			Con_DPrintf("Expected: %s\n", StrAddr (&sock->addr));
			Con_DPrintf("Received: %s\n", StrAddr (&readaddr));
#endif
			continue;
		}

		if (length < NET_HEADERSIZE)
		{
			shortPacketCount++;
			continue;
		}

		length = BigLong(packetBuffer.length);
		flags = length & (~NETFLAG_LENGTH_MASK);
		length &= NETFLAG_LENGTH_MASK;

		// ProQuake extra protection
		if (length > NET_DATAGRAMSIZE)
		{
			Con_Warning ("Datagram_GetMessage: excessive datagram length (%d, max = %d)\n", length, NET_DATAGRAMSIZE);
			return -1;
		}

		if (flags & NETFLAG_CTL)
			continue;

		sequence = BigLong(packetBuffer.sequence);
		packetsReceived++;

		// NAT fix
		if (sock->net_wait)
		{
			sock->addr = readaddr;
			strcpy(sock->address, sock->landriver->AddrToString(&readaddr));
			sock->net_wait = false;
		}

		if (flags & NETFLAG_UNRELIABLE)
		{
			if (sequence < sock->unreliableReceiveSequence)
			{
				Con_DPrintf("Got a stale datagram\n");
				ret = 0;
				break;
			}
			if (sequence != sock->unreliableReceiveSequence)
			{
				count = sequence - sock->unreliableReceiveSequence;
				droppedDatagrams += count;
				Con_DPrintf("Dropped %u datagram(s)\n", count);
			}
			sock->unreliableReceiveSequence = sequence + 1;

			length -= NET_HEADERSIZE;

			SZ_Clear (net_message->message);
			SZ_Write (net_message->message, packetBuffer.data, length);

			ret = 2;
			break;
		}

		if (flags & NETFLAG_ACK)
		{
			if (sequence != (sock->sendSequence - 1))
			{
				Con_DPrintf("Stale ACK received\n");
				continue;
			}
			if (sequence == sock->ackSequence)
			{
				sock->ackSequence++;
				if (sock->ackSequence != sock->sendSequence)
					Con_DPrintf("ack sequencing error\n");
			}
			else
			{
				Con_DPrintf("Duplicate ACK received\n");
				continue;
			}
			sock->sendMessageLength -= MAX_DATAGRAM;
			if (sock->sendMessageLength > 0)
			{
				// FIXME: was memcpy
				memmove(sock->sendMessage, sock->sendMessage + MAX_DATAGRAM, sock->sendMessageLength);
				sock->sendNext = true;
			}
			else
			{
				sock->sendMessageLength = 0;
				sock->canSend = true;
			}
			continue;
		}

		if (flags & NETFLAG_DATA)
		{
			packetBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK);
			packetBuffer.sequence = BigLong(sequence);
			sock->landriver->Write(sock->socket, (byte *)&packetBuffer, NET_HEADERSIZE, &readaddr);

			if (sequence != sock->receiveSequence)
			{
				receivedDuplicateCount++;
				continue;
			}
			sock->receiveSequence++;

			length -= NET_HEADERSIZE;

			if (flags & NETFLAG_EOM)
			{
				SZ_Clear(net_message->message);
				SZ_Write(net_message->message, sock->receiveMessage, sock->receiveMessageLength);
				SZ_Write(net_message->message, packetBuffer.data, length);
				sock->receiveMessageLength = 0;

				ret = 1;
				break;
			}

			memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length);
			sock->receiveMessageLength += length;
			continue;
		}
	}

	if (sock->sendNext)
		SendMessageNext (sock);

	return ret;
}
Пример #5
0
static void _Datagram_SearchForHosts (qboolean xmit)
{
	int		ret;
	int		n;
	int		i;
	struct qsockaddr readaddr;
	struct qsockaddr myaddr;
	int		control;

	dfunc.GetSocketAddr (dfunc.controlSock, &myaddr);
	if (xmit)
	{
		SZ_Clear(&net_message);
		// save space for the header, filled in later
		MSG_WriteLong(&net_message, 0);
		MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);
		MSG_WriteString(&net_message, "QUAKE");
		MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
		dfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize);
		SZ_Clear(&net_message);
	}

	while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)
	{
		if (ret < sizeof(int))
			continue;
		net_message.cursize = ret;

		// don't answer our own query
		if (dfunc.AddrCompare(&readaddr, &myaddr) >= 0)
			continue;

		// is the cache full?
		if (hostCacheCount == HOSTCACHESIZE)
			continue;

		MSG_BeginReading ();
		control = BigLong(*((int *)net_message.data));
		MSG_ReadLong();
		if (control == -1)
			continue;
		if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)
			continue;
		if ((control & NETFLAG_LENGTH_MASK) != ret)
			continue;

		if (MSG_ReadByte() != CCREP_SERVER_INFO)
			continue;

		dfunc.GetAddrFromName(MSG_ReadString(), &readaddr);
		// search the cache for this server
		for (n = 0; n < hostCacheCount; n++)
			if (dfunc.AddrCompare(&readaddr, &hostcache[n].addr) == 0)
				break;

		// is it already there?
		if (n < hostCacheCount)
			continue;

		// add it
		hostCacheCount++;
		Q_strcpy(hostcache[n].name, MSG_ReadString());
		Q_strcpy(hostcache[n].map, MSG_ReadString());
		hostcache[n].users = MSG_ReadByte();
		hostcache[n].maxusers = MSG_ReadByte();
		if (MSG_ReadByte() != NET_PROTOCOL_VERSION)
		{
			Q_strcpy(hostcache[n].cname, hostcache[n].name);
			hostcache[n].cname[14] = 0;
			Q_strcpy(hostcache[n].name, "*");
			Q_strcat(hostcache[n].name, hostcache[n].cname);
		}
		Q_memcpy(&hostcache[n].addr, &readaddr, sizeof(struct qsockaddr));
		hostcache[n].driver = net_driverlevel;
		hostcache[n].ldriver = net_landriverlevel;
		Q_strcpy(hostcache[n].cname, dfunc.AddrToString(&readaddr));

		// check for a name conflict
		for (i = 0; i < hostCacheCount; i++)
		{
			if (i == n)
				continue;
			if (Q_strcasecmp (hostcache[n].name, hostcache[i].name) == 0)
			{
				i = Q_strlen(hostcache[n].name);
				if (i < 15 && hostcache[n].name[i-1] > '8')
				{
					hostcache[n].name[i] = '0';
					hostcache[n].name[i+1] = 0;
				}
				else
					hostcache[n].name[i-1]++;
				i = -1;
			}
		}
	}
}
Пример #6
0
void EXT_FUNC SZ_Clear_api(sizebuf_t *buf) {
	SZ_Clear(buf);
}
Пример #7
0
static qbool SV_MVD_Record (mvddest_t *dest)
{
	sizebuf_t	buf;
	byte buf_data[MAX_MSGLEN];
	int n, i;
	char *s, info[MAX_INFO_STRING];
	client_t *player;
	char *gamedir;

	if (!dest)
		return false;

	DestFlush(true);

	if (!sv.mvdrecording)
	{
		memset(&demo, 0, sizeof(demo));
		for (i = 0; i < UPDATE_BACKUP; i++)
		{
			demo.recorder.frames[i] = demo_frames[i];
			demo.recorder.frames[i].entities.entities = demo_entities[i];
		}

		MVDBuffer_Init(&demo.dbuffer, demo.buffer, sizeof(demo.buffer));
		MVDSetMsgBuf(NULL, &demo.frames[0].buf);

		demo.datagram.maxsize = sizeof(demo.datagram_data);
		demo.datagram.data = demo.datagram_data;

		sv.mvdrecording = true;
	}
//	else
//		SV_WriteRecordMVDMessage(&buf);

	demo.pingtime = demo.time = sv.time;

	dest->nextdest = demo.dest;
	demo.dest = dest;

	singledest = dest;

/*-------------------------------------------------*/

// serverdata
	// send the info about the new client to all connected clients
	SZ_Init (&buf, buf_data, sizeof(buf_data));

// send the serverdata

	gamedir = Info_ValueForKey (svs.info, "*gamedir");
	if (!gamedir[0])
		gamedir = "qw";

	MSG_WriteByte (&buf, svc_serverdata);

	MSG_WriteLong (&buf, PROTOCOL_VERSION);
	MSG_WriteLong (&buf, svs.spawncount);
	MSG_WriteString (&buf, gamedir);

	MSG_WriteFloat (&buf, sv.time);

	// send full levelname
	MSG_WriteString (&buf, sv.mapname);

	// send the movevars
	MSG_WriteFloat(&buf, sv.movevars.gravity);
	MSG_WriteFloat(&buf, sv.movevars.stopspeed);
	MSG_WriteFloat(&buf, sv.movevars.maxspeed);
	MSG_WriteFloat(&buf, sv.movevars.spectatormaxspeed);
	MSG_WriteFloat(&buf, sv.movevars.accelerate);
	MSG_WriteFloat(&buf, sv.movevars.airaccelerate);
	MSG_WriteFloat(&buf, sv.movevars.wateraccelerate);
	MSG_WriteFloat(&buf, sv.movevars.friction);
	MSG_WriteFloat(&buf, sv.movevars.waterfriction);
	MSG_WriteFloat(&buf, sv.movevars.entgravity);

	// send music
	MSG_WriteByte (&buf, svc_cdtrack);
	MSG_WriteByte (&buf, 0); // none in demos

	// send server info string
	MSG_WriteByte (&buf, svc_stufftext);
	MSG_WriteString (&buf, va("fullserverinfo \"%s\"\n", svs.info) );

	// flush packet
	SV_WriteRecordMVDMessage (&buf);
	SZ_Clear (&buf);

// soundlist
	MSG_WriteByte (&buf, svc_soundlist);
	MSG_WriteByte (&buf, 0);

	n = 0;
	s = sv.sound_name[n+1];
	while (s)
	{
		MSG_WriteString (&buf, s);
		if (buf.cursize > MAX_MSGLEN/2)
		{
			MSG_WriteByte (&buf, 0);
			MSG_WriteByte (&buf, n);
			SV_WriteRecordMVDMessage (&buf);
			SZ_Clear (&buf);
			MSG_WriteByte (&buf, svc_soundlist);
			MSG_WriteByte (&buf, n + 1);
		}
		n++;
		s = sv.sound_name[n+1];
	}

	if (buf.cursize)
	{
		MSG_WriteByte (&buf, 0);
		MSG_WriteByte (&buf, 0);
		SV_WriteRecordMVDMessage (&buf);
		SZ_Clear (&buf);
	}

// modellist
	MSG_WriteByte (&buf, svc_modellist);
	MSG_WriteByte (&buf, 0);

	n = 0;
	s = sv.model_name[n+1];
	while (s)
	{
		MSG_WriteString (&buf, s);
		if (buf.cursize > MAX_MSGLEN/2)
		{
			MSG_WriteByte (&buf, 0);
			MSG_WriteByte (&buf, n);
			SV_WriteRecordMVDMessage (&buf);
			SZ_Clear (&buf);
			MSG_WriteByte (&buf, svc_modellist);
			MSG_WriteByte (&buf, n + 1);
		}
		n++;
		s = sv.model_name[n+1];
	}
	if (buf.cursize)
	{
		MSG_WriteByte (&buf, 0);
		MSG_WriteByte (&buf, 0);
		SV_WriteRecordMVDMessage (&buf);
		SZ_Clear (&buf);
	}

// baselines
	{
		entity_state_t from;
		edict_t *ent;
		entity_state_t *state;

		memset(&from, 0, sizeof(from));

		for (n = 0; n < sv.num_edicts; n++)
		{
			ent = EDICT_NUM(n);
			state = &ent->baseline;

			if (!state->number || !state->modelindex)
			{	//ent doesn't have a baseline
				continue;
			}

			if (!ent)
			{
				MSG_WriteByte(&buf, svc_spawnbaseline);

				MSG_WriteShort (&buf, n);

				MSG_WriteByte (&buf, 0);

				MSG_WriteByte (&buf, 0);
				MSG_WriteByte (&buf, 0);
				MSG_WriteByte (&buf, 0);
				for (i=0 ; i<3 ; i++)
				{
					MSG_WriteCoord(&buf, 0);
					MSG_WriteAngle(&buf, 0);
				}
			}
			else
			{
				MSG_WriteByte(&buf, svc_spawnbaseline);

				MSG_WriteShort (&buf, n);

				MSG_WriteByte (&buf, state->modelindex&255);

				MSG_WriteByte (&buf, state->frame);
				MSG_WriteByte (&buf, (int)state->colormap);
				MSG_WriteByte (&buf, (int)state->skinnum);
				for (i=0 ; i<3 ; i++)
				{
					MSG_WriteCoord(&buf, state->s_origin[i]);
					MSG_WriteAngle(&buf, state->s_angles[i]);
				}
			}
			if (buf.cursize > MAX_MSGLEN/2)
			{
				SV_WriteRecordMVDMessage (&buf);
				SZ_Clear (&buf);
			}
		}
	}

	//prespawn

	for (n = 0; n < sv.num_signon_buffers; n++)
	{
		if (buf.cursize+sv.signon_buffer_size[n] > MAX_MSGLEN/2)
		{
			SV_WriteRecordMVDMessage (&buf);
			SZ_Clear (&buf);
		}
		SZ_Write (&buf, sv.signon_buffers[n], sv.signon_buffer_size[n]);
	}

	if (buf.cursize > MAX_MSGLEN/2)
	{
		SV_WriteRecordMVDMessage (&buf);
		SZ_Clear (&buf);
	}

	MSG_WriteByte (&buf, svc_stufftext);
	MSG_WriteString (&buf, va("cmd spawn %i\n",svs.spawncount) );

	if (buf.cursize)
	{
		SV_WriteRecordMVDMessage (&buf);
		SZ_Clear (&buf);
	}

// send current status of all other players

	for (i = 0; i < MAX_CLIENTS; i++)
	{
		player = svs.clients + i;

		MSG_WriteByte (&buf, svc_updatefrags);
		MSG_WriteByte (&buf, i);
		MSG_WriteShort (&buf, player->old_frags);

		MSG_WriteByte (&buf, svc_updateping);
		MSG_WriteByte (&buf, i);
		MSG_WriteShort (&buf, SV_CalcPing(player));

		MSG_WriteByte (&buf, svc_updatepl);
		MSG_WriteByte (&buf, i);
		MSG_WriteByte (&buf, player->lossage);

		MSG_WriteByte (&buf, svc_updateentertime);
		MSG_WriteByte (&buf, i);
		MSG_WriteFloat (&buf, svs.realtime - player->connection_started);

		Q_strncpyz (info, player->userinfo, MAX_INFO_STRING);
		Info_RemovePrefixedKeys (info, '_');	// server passwords, etc

		MSG_WriteByte (&buf, svc_updateuserinfo);
		MSG_WriteByte (&buf, i);
		MSG_WriteLong (&buf, player->userid);
		MSG_WriteString (&buf, info);

		if (buf.cursize > MAX_MSGLEN/2)
		{
			SV_WriteRecordMVDMessage (&buf);
			SZ_Clear (&buf);
		}
	}

// send all current light styles
	for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
	{
		MSG_WriteByte (&buf, svc_lightstyle);
		MSG_WriteByte (&buf, (char)i);
		MSG_WriteString (&buf, sv.lightstyles[i]);
	}

	// get the client to check and download skins
	// when that is completed, a begin command will be issued
	MSG_WriteByte (&buf, svc_stufftext);
	MSG_WriteString (&buf, "skins\n");

	SV_WriteRecordMVDMessage (&buf);

	SV_WriteSetMVDMessage();

	singledest = NULL;

	// done
	return true;
}
Пример #8
0
/*
====================
CL_Record

Called by CL_Record_f and CL_EasyRecord_f
====================
*/
static void CL_Record (void)
{
	sizebuf_t	buf;
	byte	buf_data[MAX_MSGLEN];
	int n, i, j;
	char *s;
	entity_t *ent;
	entity_state_t *es, blankes;
	player_info_t *player;
	int seq = 1;

#ifdef MVDPLAY
	if (cls.mvdplayback) {
		Com_Printf ("Can't record while playing MVD demo.\n");
		return;
	}
#endif
	cls.demorecording = true;

/*-------------------------------------------------*/

// serverdata
	// send the info about the new client to all connected clients
	SZ_Init (&buf, buf_data, sizeof(buf_data));

// send the serverdata
	MSG_WriteByte (&buf, svc_serverdata);
	MSG_WriteLong (&buf, PROTOCOL_VERSION);
	MSG_WriteLong (&buf, cl.servercount);
	MSG_WriteString (&buf, cls.gamedirfile);

	if (cl.spectator)
		MSG_WriteByte (&buf, cl.playernum | 128);
	else
		MSG_WriteByte (&buf, cl.playernum);

	// send full levelname
	MSG_WriteString (&buf, cl.levelname);

	// send the movevars
	MSG_WriteFloat(&buf, movevars.gravity);
	MSG_WriteFloat(&buf, movevars.stopspeed);
	MSG_WriteFloat(&buf, cl.maxspeed);
	MSG_WriteFloat(&buf, movevars.spectatormaxspeed);
	MSG_WriteFloat(&buf, movevars.accelerate);
	MSG_WriteFloat(&buf, movevars.airaccelerate);
	MSG_WriteFloat(&buf, movevars.wateraccelerate);
	MSG_WriteFloat(&buf, movevars.friction);
	MSG_WriteFloat(&buf, movevars.waterfriction);
	MSG_WriteFloat(&buf, cl.entgravity);

	// send music
	MSG_WriteByte (&buf, svc_cdtrack);
	MSG_WriteByte (&buf, 0); // none in demos

	// send server info string
	MSG_WriteByte (&buf, svc_stufftext);
	MSG_WriteString (&buf, va("fullserverinfo \"%s\"\n", cl.serverinfo) );

	// flush packet
	CL_WriteRecordDemoMessage (&buf, seq++);
	SZ_Clear (&buf); 

// soundlist
	MSG_WriteByte (&buf, svc_soundlist);
	MSG_WriteByte (&buf, 0);

	n = 0;
	s = cl.sound_name[n+1];
	while (*s) {
		MSG_WriteString (&buf, s);
		if (buf.cursize > MAX_MSGLEN/2) {
			MSG_WriteByte (&buf, 0);
			MSG_WriteByte (&buf, n);
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
			MSG_WriteByte (&buf, svc_soundlist);
			MSG_WriteByte (&buf, n + 1);
		}
		n++;
		s = cl.sound_name[n+1];
	}
	if (buf.cursize) {
		MSG_WriteByte (&buf, 0);
		MSG_WriteByte (&buf, 0);
		CL_WriteRecordDemoMessage (&buf, seq++);
		SZ_Clear (&buf); 
	}

#ifdef VWEP_TEST
// vwep modellist
	if ((cl.z_ext & Z_EXT_VWEP) && cl.vw_model_name[0][0]) {
		// send VWep precaches
		// pray we don't overflow
		for (i = 0; i < MAX_VWEP_MODELS; i++) {
			s = cl.vw_model_name[i];
			if (!*s)
				continue;
			MSG_WriteByte (&buf, svc_serverinfo);
			MSG_WriteString (&buf, "#vw");
			MSG_WriteString (&buf, va("%i %s", i, TrimModelName(s)));
		}
		// send end-of-list messsage
		MSG_WriteByte (&buf, svc_serverinfo);
		MSG_WriteString (&buf, "#vw");
		MSG_WriteString (&buf, "");
	}
	// don't bother flushing, the vwep list is not that large (I hope)
#endif

// modellist
	MSG_WriteByte (&buf, svc_modellist);
	MSG_WriteByte (&buf, 0);

	n = 0;
	s = cl.model_name[n+1];
	while (*s) {
		MSG_WriteString (&buf, s);
		if (buf.cursize > MAX_MSGLEN/2) {
			MSG_WriteByte (&buf, 0);
			MSG_WriteByte (&buf, n);
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
			MSG_WriteByte (&buf, svc_modellist);
			MSG_WriteByte (&buf, n + 1);
		}
		n++;
		s = cl.model_name[n+1];
	}
	if (buf.cursize) {
		MSG_WriteByte (&buf, 0);
		MSG_WriteByte (&buf, 0);
		CL_WriteRecordDemoMessage (&buf, seq++);
		SZ_Clear (&buf); 
	}

// spawnstatic

	for (i = 0; i < cl.num_statics; i++) {
		ent = cl_static_entities + i;

		MSG_WriteByte (&buf, svc_spawnstatic);

		for (j = 1; j < MAX_MODELS; j++)
			if (ent->model == cl.model_precache[j])
				break;
		if (j == MAX_MODELS)
			MSG_WriteByte (&buf, 0);
		else
			MSG_WriteByte (&buf, j);

		MSG_WriteByte (&buf, ent->frame);
		MSG_WriteByte (&buf, 0);
		MSG_WriteByte (&buf, ent->skinnum);
		for (j=0 ; j<3 ; j++)
		{
			MSG_WriteCoord (&buf, ent->origin[j]);
			MSG_WriteAngle (&buf, ent->angles[j]);
		}

		if (buf.cursize > MAX_MSGLEN/2) {
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
		}
	}

// spawnstaticsound

	for (i = 0; i < cl.num_static_sounds; i++) {
		static_sound_t *ss = &cl.static_sounds[i];
		MSG_WriteByte (&buf, svc_spawnstaticsound);
		for (j = 0; j < 3; j++)
			MSG_WriteCoord (&buf, ss->org[j]);
		MSG_WriteByte (&buf, ss->sound_num);
		MSG_WriteByte (&buf, ss->vol);
		MSG_WriteByte (&buf, ss->atten);

		if (buf.cursize > MAX_MSGLEN/2) {
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
		}
	}

// baselines

	memset(&blankes, 0, sizeof(blankes));
	for (i = 0; i < MAX_CL_EDICTS; i++) {
		es = &cl_entities[i].baseline;

		if (memcmp(es, &blankes, sizeof(blankes))) {
			MSG_WriteByte (&buf,svc_spawnbaseline);		
			MSG_WriteShort (&buf, i);

			MSG_WriteByte (&buf, es->modelindex);
			MSG_WriteByte (&buf, es->frame);
			MSG_WriteByte (&buf, es->colormap);
			MSG_WriteByte (&buf, es->skinnum);
			for (j=0 ; j<3 ; j++)
			{
				MSG_WriteShort (&buf, es->s_origin[j]);
				MSG_WriteByte (&buf, es->s_angles[j]);
			}

			if (buf.cursize > MAX_MSGLEN/2) {
				CL_WriteRecordDemoMessage (&buf, seq++);
				SZ_Clear (&buf); 
			}
		}
	}

	MSG_WriteByte (&buf, svc_stufftext);
	MSG_WriteString (&buf, va("cmd spawn %i 0\n", cl.servercount) );

	if (buf.cursize) {
		CL_WriteRecordDemoMessage (&buf, seq++);
		SZ_Clear (&buf); 
	}

// send current status of all other players

	for (i = 0; i < MAX_CLIENTS; i++) {
		player = cl.players + i;

		MSG_WriteByte (&buf, svc_updatefrags);
		MSG_WriteByte (&buf, i);
		MSG_WriteShort (&buf, player->frags);
		
		MSG_WriteByte (&buf, svc_updateping);
		MSG_WriteByte (&buf, i);
		MSG_WriteShort (&buf, player->ping);
		
		MSG_WriteByte (&buf, svc_updatepl);
		MSG_WriteByte (&buf, i);
		MSG_WriteByte (&buf, player->pl);
		
		MSG_WriteByte (&buf, svc_updateentertime);
		MSG_WriteByte (&buf, i);
		MSG_WriteFloat (&buf, cls.realtime - player->entertime);

		MSG_WriteByte (&buf, svc_updateuserinfo);
		MSG_WriteByte (&buf, i);
		MSG_WriteLong (&buf, player->userid);
		MSG_WriteString (&buf, player->userinfo);

		if (buf.cursize > MAX_MSGLEN/2) {
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
		}
	}
	
// send all current light styles
	for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
	{
		if (!cl_lightstyle[i].length)
			continue;		// don't send empty lightstyle strings
		MSG_WriteByte (&buf, svc_lightstyle);
		MSG_WriteByte (&buf, (char)i);
		MSG_WriteString (&buf, cl_lightstyle[i].map);
	}

	for (i = 0; i < MAX_CL_STATS; i++) {
		if (!cl.stats[i])
			continue;		// no need to send zero values
		if (cl.stats[i] >= 0 && cl.stats[i] <= 255) {
			MSG_WriteByte (&buf, svc_updatestat);
			MSG_WriteByte (&buf, i);
			MSG_WriteByte (&buf, cl.stats[i]);
		} else {
			MSG_WriteByte (&buf, svc_updatestatlong);
			MSG_WriteByte (&buf, i);
			MSG_WriteLong (&buf, cl.stats[i]);
		}
		if (buf.cursize > MAX_MSGLEN/2) {
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
		}
	}

	// get the client to check and download skins
	// when that is completed, a begin command will be issued
	MSG_WriteByte (&buf, svc_stufftext);
	MSG_WriteString (&buf, va("skins\n") );

	CL_WriteRecordDemoMessage (&buf, seq++);

	CL_WriteSetDemoMessage();

	// done
}
Пример #9
0
// clears both cl->netchan.message and backbuf
void SV_ClearReliable (client_t *cl)
{
	SZ_Clear (&cl->netchan.message);
	SV_ClearBackbuf (cl);
}
Пример #10
0
bool NetDemo::startRecording(const std::string &filename)
{
    this->filename = filename;

    if (isPlaying() || isPaused())
    {
        error("Cannot record a netdemo while not connected to a server.");
        return false;
    }

    // Already recording so just ignore the command
    if (isRecording())
        return true;

    if (demofp != NULL)		// file is already open for some reason
    {
        fclose(demofp);
        demofp = NULL;
    }

    demofp = fopen(filename.c_str(), "wb");
    if (!demofp)
    {
        error("Unable to create netdemo file " + filename + ".");
        return false;
    }

    memset(&header, 0, sizeof(header));
    // Note: The header is not finalized at this point.  Write it anyway to
    // reserve space in the output file for it and overwrite it later.
    if (!writeHeader())
    {
        error("Unable to write netdemo header.");
        return false;
    }

    state = NetDemo::st_recording;
    header.starting_gametic = gametic;
    Printf(PRINT_HIGH, "Recording netdemo %s.\n", filename.c_str());

    if (connected)
    {
        // write a simulation of the connection sequence since the server
        // has already sent it to the client and it wasn't captured
        static buf_t tempbuf(MAX_UDP_PACKET);

        // Fake the launcher query response
        SZ_Clear(&tempbuf);
        writeLauncherSequence(&tempbuf);
        capture(&tempbuf);
        writeMessages();

        // Fake the server's side of the connection sequence
        SZ_Clear(&tempbuf);
        writeConnectionSequence(&tempbuf);
        capture(&tempbuf);
        writeMessages();

        // Record any additional messages (usually a full update if auto-recording))
        capture(&net_message);
        writeMessages();

        SZ_Clear(&tempbuf);
        MSG_WriteMarker(&tempbuf, svc_netdemoloadsnap);
        capture(&tempbuf);
        writeMessages();
    }

    return true;
}
Пример #11
0
/*
====================
CL_GetDemoMessage

  FIXME...
====================
*/
qbool CL_GetDemoMessage (void)
{
	int		r, i, j;
	float	demotime;
	byte	c;
	usercmd_t *pcmd;
#ifdef MVDPLAY
	byte	msec;
#endif

	if (qwz_unpacking)
		return false;

	if (cl.paused & PAUSED_DEMO)
		return false;

readnext:
	// read the time from the packet
#ifdef MVDPLAY
	if (cls.mvdplayback) {
		fread(&msec, sizeof(msec), 1, cls.demofile);
		demotime = cls.mvd_newtime + msec * 0.001;
	}
	else
#endif
	{
		fread(&demotime, sizeof(demotime), 1, cls.demofile);
		demotime = LittleFloat(demotime);
    }

// decide if it is time to grab the next message		
	if (cls.timedemo) {
		if (cls.td_lastframe < 0)
			cls.td_lastframe = demotime;
		else if (demotime > cls.td_lastframe) {
			cls.td_lastframe = demotime;
			// rewind back to time
#ifdef MVDPLAY
			if (cls.mvdplayback) {
				fseek(cls.demofile, ftell(cls.demofile) - sizeof(msec),
					SEEK_SET);
			} else 
#endif
				fseek(cls.demofile, ftell(cls.demofile) - sizeof(demotime),
					SEEK_SET);
			return false;	// already read this frame's message
		}
		if (!cls.td_starttime && cls.state == ca_active) {
			cls.td_starttime = Sys_DoubleTime();
			cls.td_startframe = cls.framecount;
		}
		cls.demotime = demotime; // warp
	} else if (!(cl.paused & PAUSED_SERVER) && cls.state >= ca_active) {	// always grab until active
#ifdef MVDPLAY
		if (cls.mvdplayback)
		{
			if (msec/* a hack! */ && cls.demotime < cls.mvd_newtime) {
				fseek(cls.demofile, ftell(cls.demofile) - sizeof(msec),
						SEEK_SET);
				return false;
			}
		}
        else
#endif
		if (cls.demotime < demotime) {
            if (cls.demotime + 1.0 < demotime)
                cls.demotime = demotime - 1.0; // too far back
			// rewind back to time
			fseek(cls.demofile, ftell(cls.demofile) - sizeof(demotime),
					SEEK_SET);
			return false;		// don't need another message yet
		}
	} else
		cls.demotime = demotime; // we're warping


#ifdef MVDPLAY
	if (cls.mvdplayback)
	{
		if (msec)
		{
			extern void CL_ParseClientdata ();

			cls.mvd_oldtime = cls.mvd_newtime;
			cls.mvd_newtime = demotime;
			cls.netchan.incoming_sequence++;
			cls.netchan.incoming_acknowledged++;

			CL_ParseClientdata();
		}
	}
#endif

	if (cls.state < ca_demostart)
		Host_Error ("CL_GetDemoMessage: cls.state < ca_demostart");
	
	// get the msg type
	r = fread (&c, sizeof(c), 1, cls.demofile);
	if (r != 1)
		Host_Error ("Unexpected end of demo");
	
#ifdef MVDPLAY
    switch (cls.mvdplayback ? c&7 : c) {
#else
	switch (c) {
#endif
	case dem_cmd :
		// user sent input
		i = cls.netchan.outgoing_sequence & UPDATE_MASK;
		pcmd = &cl.frames[i].cmd;
		r = fread (pcmd, sizeof(*pcmd), 1, cls.demofile);
		if (r != 1)
			Host_Error ("Unexpected end of demo");
		// byte order stuff
		for (j = 0; j < 3; j++)
			pcmd->angles[j] = LittleFloat(pcmd->angles[j]);
		pcmd->forwardmove = LittleShort(pcmd->forwardmove);
		pcmd->sidemove    = LittleShort(pcmd->sidemove);
		pcmd->upmove      = LittleShort(pcmd->upmove);
		cl.frames[i].senttime = demotime + (cls.realtime - cls.demotime);
		cl.frames[i].receivedtime = -1;		// we haven't gotten a reply yet
		cls.netchan.outgoing_sequence++;

		fread (cl.viewangles, 12, 1, cls.demofile);
		for (i = 0; i < 3; i++)
			cl.viewangles[i] = LittleFloat (cl.viewangles[i]);
		if (cl.spectator)
			Cam_TryLock();
		goto readnext;

	case dem_read:
#ifdef MVDPLAY
readit:
#endif
		// get the next message
		fread (&net_message.cursize, 4, 1, cls.demofile);
		net_message.cursize = LittleLong (net_message.cursize);
		if (net_message.cursize > MAX_BIG_MSGLEN)
			Host_Error ("Demo message > MAX_BIG_MSGLEN");
		r = fread (net_message.data, net_message.cursize, 1, cls.demofile);
		if (r != 1)
			Host_Error ("Unexpected end of demo");

#ifdef MVDPLAY
		if (cls.mvdplayback) {
			switch(cls.mvd_lasttype) {
			case dem_multiple:
				if (!cam_locked || !(cls.mvd_lastto & (1 << cam_curtarget)))
					goto readnext;	
				break;
			case dem_single:
				if (!cam_locked || cls.mvd_lastto != cam_curtarget)
					goto readnext;
				break;
			}
		}
#endif

		return true;

	case dem_set:
		fread (&i, 4, 1, cls.demofile);
		cls.netchan.outgoing_sequence = LittleLong(i);
		fread (&i, 4, 1, cls.demofile);
		cls.netchan.incoming_sequence = LittleLong(i);
#ifdef MVDPLAY
		if (cls.mvdplayback)
			cls.netchan.incoming_acknowledged = cls.netchan.incoming_sequence;
#endif
		goto readnext;

#ifdef MVDPLAY
	case dem_multiple:
		r = fread (&i, 4, 1, cls.demofile);
		if (r != 1)
			Host_Error ("Unexpected end of demo");
		cls.mvd_lastto = LittleLong(i);
		cls.mvd_lasttype = dem_multiple;
		goto readit;

	case dem_single:
		cls.mvd_lastto = c>>3;
		cls.mvd_lasttype = dem_single;
		goto readit;

	case dem_stats:
		cls.mvd_lastto = c>>3;
		cls.mvd_lasttype = dem_stats;
		goto readit;

	case dem_all:
		cls.mvd_lastto = 0;
		cls.mvd_lasttype = dem_all;
		goto readit;
#endif

	default:
		Host_Error ("Corrupted demo 3 -> c='%d'", c);
		return false;
	}
}

/*
====================
CL_Stop_f

stop recording a demo
====================
*/
void CL_Stop_f (void)
{
	if (!cls.demorecording)
	{
		Com_Printf ("Not recording a demo.\n");
		return;
	}

// write a disconnect message to the demo file
	SZ_Clear (&net_message);
	MSG_WriteLong (&net_message, -1);	// -1 sequence means out of band
	MSG_WriteByte (&net_message, svc_disconnect);
	MSG_WriteString (&net_message, "EndOfDemo");
	CL_WriteDemoMessage (&net_message);

// finish up
	fclose (cls.demofile);
	cls.demofile = NULL;
	cls.demorecording = false;
	Com_Printf ("Completed demo\n");
}


/*
====================
CL_WriteRecordDemoMessage
====================
*/
void CL_WriteRecordDemoMessage (sizebuf_t *msg, int seq)
{
	int		len;
	int		i;
	float	fl;
	byte	c;

//Com_Printf ("write: %ld bytes, %4.4f\n", msg->cursize, cls.realtime);

	if (!cls.demorecording)
		return;

	fl = LittleFloat((float)cls.realtime);
	fwrite (&fl, sizeof(fl), 1, cls.demofile);

	c = dem_read;
	fwrite (&c, sizeof(c), 1, cls.demofile);

	len = LittleLong (msg->cursize + 8);
	fwrite (&len, 4, 1, cls.demofile);

	i = LittleLong(seq);
	fwrite (&i, 4, 1, cls.demofile);
	fwrite (&i, 4, 1, cls.demofile);

	fwrite (msg->data, msg->cursize, 1, cls.demofile);

	fflush (cls.demofile);
}
Пример #12
0
//
// IntQrySendResponse()
// 
// Sends information regarding the type of information we received (ie: it will
// send data that is wanted by the enquirer program)
static DWORD IntQrySendResponse(const WORD &TagId, 
                                const BYTE &TagApplication,
                                const BYTE &TagQRId,
                                const WORD &TagPacketType)
{
    // It isn't a query, throw it away
    if (TagQRId != 1)
    {
        //Printf("Query/Response Id is not valid");
        
        return 0;
    }

    // Decipher the program that sent the query
    switch (TagApplication)
    {
        case 1:
        {
            //Printf(PRINT_HIGH, "Application is Enquirer");
        }
        break;
        
        case 2:
        {
            //Printf(PRINT_HIGH, "Application is Client");
        }
        break;

        case 3:
        {
            //Printf(PRINT_HIGH, "Application is Server");
        }
        break;

        case 4:
        {
            //Printf(PRINT_HIGH, "Application is Master Server");
        }
        break;
        
        default:
        {
            //Printf("Application is Unknown");
        }
        break;
    }
       
    DWORD ReTag = 0;
    WORD ReId = TAG_ID;
    BYTE ReApplication = 3;
    BYTE ReQRId = 2;
    WORD RePacketType = 0;    
    
    switch (TagPacketType)
    {
        // Request version
        case 1:
        {
            RePacketType = 1;
        }
        break;

        // Information request
        case 2:
        {
            RePacketType = 3;
        }
        break;
    }

    // Begin enquirer version translation
    DWORD EqVersion = MSG_ReadLong();
    DWORD EqProtocolVersion = MSG_ReadLong();
    DWORD EqTime = 0;

    EqTime = MSG_ReadLong();

    // Override other packet types for older enquirer version response
    if (VERSIONMAJOR(EqVersion) < VERSIONMAJOR(GAMEVER) || 
        (VERSIONMAJOR(EqVersion) <= VERSIONMAJOR(GAMEVER) && VERSIONMINOR(EqVersion) < VERSIONMINOR(GAMEVER)))
    {
        RePacketType = 2;
    }
    
    // Encode our tag
    ReTag = (((ReId << 20) & 0xFFF00000) | 
             ((ReApplication << 16) & 0x000F0000) | 
             ((ReQRId << 12) & 0x0000F000) | (RePacketType & 0x00000FFF));   
           
    // Clear our message buffer for a response
    SZ_Clear(&ml_message);

    MSG_WriteLong(&ml_message, ReTag);
    MSG_WriteLong(&ml_message, GAMEVER);
    
    // Enquirer requested the version info of the server or the server
    // determined it is an old version
    if (RePacketType == 1 || RePacketType == 2)
    {       
        // bond - real protocol
        MSG_WriteLong(&ml_message, PROTOCOL_VERSION);

        MSG_WriteLong(&ml_message, EqTime);

        NET_SendPacket(ml_message, net_from);
        
        //Printf(PRINT_HIGH, "Application is old version\n");
        
        return 0;
    }
    
    // If the enquirer protocol is newer, send the latest information the
    // server supports, otherwise send information built to the their version
    if (EqProtocolVersion > PROTOCOL_VERSION)
    {
        EqProtocolVersion = PROTOCOL_VERSION;
        
        MSG_WriteLong(&ml_message, PROTOCOL_VERSION);
    }
    else
        MSG_WriteLong(&ml_message, EqProtocolVersion);
    
    IntQryBuildInformation(EqProtocolVersion, EqTime);
    
    NET_SendPacket(ml_message, net_from);

    //Printf(PRINT_HIGH, "Success, data sent\n");

    return 0;
}
Пример #13
0
//
// SV_SendServerInfo
// 
// Sends server info to a launcher
// TODO: Clean up and reinvent.
void SV_SendServerInfo()
{
	size_t i;

	SZ_Clear(&ml_message);
	
	MSG_WriteLong(&ml_message, CHALLENGE);
	MSG_WriteLong(&ml_message, SV_NewToken());

	// if master wants a key to be presented, present it we will
	if(MSG_BytesLeft() == 4)
		MSG_WriteLong(&ml_message, MSG_ReadLong());

	MSG_WriteString(&ml_message, (char *)sv_hostname.cstring());

	byte playersingame = 0;
	for (Players::iterator it = players.begin();it != players.end();++it)
	{
		if (it->ingame())
			playersingame++;
	}

	MSG_WriteByte(&ml_message, playersingame);
	MSG_WriteByte(&ml_message, sv_maxclients.asInt());

	MSG_WriteString(&ml_message, level.mapname);

	size_t numwads = wadfiles.size();
	if(numwads > 0xff)numwads = 0xff;

	MSG_WriteByte(&ml_message, numwads - 1);

	for (i = 1; i < numwads; ++i)
		MSG_WriteString(&ml_message, D_CleanseFileName(wadfiles[i], "wad").c_str());

	MSG_WriteBool(&ml_message, (sv_gametype == GM_DM || sv_gametype == GM_TEAMDM));
	MSG_WriteByte(&ml_message, sv_skill.asInt());
	MSG_WriteBool(&ml_message, (sv_gametype == GM_TEAMDM));
	MSG_WriteBool(&ml_message, (sv_gametype == GM_CTF));

	for (Players::iterator it = players.begin();it != players.end();++it)
	{
		if (it->ingame())
		{
			MSG_WriteString(&ml_message, it->userinfo.netname.c_str());
			MSG_WriteShort(&ml_message, it->fragcount);
			MSG_WriteLong(&ml_message, it->ping);

			if (sv_gametype == GM_TEAMDM || sv_gametype == GM_CTF)
				MSG_WriteByte(&ml_message, it->userinfo.team);
			else
				MSG_WriteByte(&ml_message, TEAM_NONE);
		}
	}

	for (i = 1; i < numwads; ++i)
		MSG_WriteString(&ml_message, wadhashes[i].c_str());

	MSG_WriteString(&ml_message, sv_website.cstring());

	if (sv_gametype == GM_TEAMDM || sv_gametype == GM_CTF)
	{
		MSG_WriteLong(&ml_message, sv_scorelimit.asInt());
		
		for(size_t i = 0; i < NUMTEAMS; i++)
		{
			if ((sv_gametype == GM_CTF && i < 2) || (sv_gametype != GM_CTF && i < sv_teamsinplay)) {
				MSG_WriteByte(&ml_message, 1);
				MSG_WriteLong(&ml_message, TEAMpoints[i]);
			} else {
				MSG_WriteByte(&ml_message, 0);
			}
		}
	}
	
	MSG_WriteShort(&ml_message, VERSION);

//bond===========================
	MSG_WriteString(&ml_message, (char *)sv_email.cstring());

	int timeleft = (int)(sv_timelimit - level.time/(TICRATE*60));
	if (timeleft<0) timeleft=0;

	MSG_WriteShort(&ml_message,sv_timelimit.asInt());
	MSG_WriteShort(&ml_message,timeleft);
	MSG_WriteShort(&ml_message,sv_fraglimit.asInt());

	MSG_WriteBool(&ml_message, (sv_itemsrespawn ? true : false));
	MSG_WriteBool(&ml_message, (sv_weaponstay ? true : false));
	MSG_WriteBool(&ml_message, (sv_friendlyfire ? true : false));
	MSG_WriteBool(&ml_message, (sv_allowexit ? true : false));
	MSG_WriteBool(&ml_message, (sv_infiniteammo ? true : false));
	MSG_WriteBool(&ml_message, (sv_nomonsters ? true : false));
	MSG_WriteBool(&ml_message, (sv_monstersrespawn ? true : false));
	MSG_WriteBool(&ml_message, (sv_fastmonsters ? true : false));
	MSG_WriteBool(&ml_message, (sv_allowjump ? true : false));
	MSG_WriteBool(&ml_message, (sv_freelook ? true : false));
	MSG_WriteBool(&ml_message, (sv_waddownload ? true : false));
	MSG_WriteBool(&ml_message, (sv_emptyreset ? true : false));
	MSG_WriteBool(&ml_message, false);		// used to be sv_cleanmaps
	MSG_WriteBool(&ml_message, (sv_fragexitswitch ? true : false));

	for (Players::iterator it = players.begin();it != players.end();++it)
	{
		if (it->ingame())
		{
			MSG_WriteShort(&ml_message, it->killcount);
			MSG_WriteShort(&ml_message, it->deathcount);
			
			int timeingame = (time(NULL) - it->JoinTime)/60;
			if (timeingame<0) timeingame=0;
				MSG_WriteShort(&ml_message, timeingame);
		}
	}
	
//bond===========================

    MSG_WriteLong(&ml_message, (DWORD)0x01020304);
    MSG_WriteShort(&ml_message, sv_maxplayers.asInt());
    
    for (Players::iterator it = players.begin();it != players.end();++it)
    {
        if (it->ingame())
        {
            MSG_WriteBool(&ml_message, (it->spectator ? true : false));
        }
    }

    MSG_WriteLong(&ml_message, (DWORD)0x01020305);
    MSG_WriteShort(&ml_message, strlen(join_password.cstring()) ? 1 : 0);
    
    // GhostlyDeath -- Send Game Version info
    MSG_WriteLong(&ml_message, GAMEVER);

    MSG_WriteByte(&ml_message, patchfiles.size());
    
    for (size_t i = 0; i < patchfiles.size(); ++i)
        MSG_WriteString(&ml_message, D_CleanseFileName(patchfiles[i]).c_str());

	NET_SendPacket(ml_message, net_from);
}
Пример #14
0
/*
=================
CL_SendBatchedCmd
=================
*/
static void CL_SendBatchedCmd( void ) {
    int i, j, seq, bits;
    int numCmds, numDups;
    int totalCmds, totalMsec;
    size_t cursize;
    usercmd_t *cmd, *oldcmd;
    client_history_t *history, *oldest;
    byte *patch;

    // see if we are ready to send this packet
    if( !ready_to_send() ) {
        return;
    }

    // archive this packet
    seq = cls.netchan->outgoing_sequence;
    history = &cl.history[seq & CMD_MASK];
    history->cmdNumber = cl.cmdNumber;
    history->sent = cls.realtime;    // for ping calculation
    history->rcvd = 0;

    cl.lastTransmitTime = cls.realtime;
    cl.lastTransmitCmdNumber = cl.cmdNumber;
    cl.lastTransmitCmdNumberReal = cl.cmdNumber;

    // begin a client move command
    patch = SZ_GetSpace( &msg_write, 1 );

    // let the server know what the last frame we
    // got was, so the next message can be delta compressed
    if( cl_nodelta->integer || !cl.frame.valid /*|| cls.demowaiting*/ ) {
        *patch = clc_move_nodelta; // no compression
    } else {
        *patch = clc_move_batched;
        MSG_WriteLong( cl.frame.number );
    }

    Cvar_ClampInteger( cl_packetdup, 0, MAX_PACKET_FRAMES - 1 );
    numDups = cl_packetdup->integer;

    *patch |= numDups << SVCMD_BITS;

    // send lightlevel
    MSG_WriteByte( cl.lightlevel );

    // send this and the previous cmds in the message, so
    // if the last packet was dropped, it can be recovered
    oldcmd = NULL;
    totalCmds = 0;
    totalMsec = 0;
    for( i = seq - numDups; i <= seq; i++ ) {
        oldest = &cl.history[( i - 1 ) & CMD_MASK];
        history = &cl.history[i & CMD_MASK];

        numCmds = history->cmdNumber - oldest->cmdNumber;
        if( numCmds >= MAX_PACKET_USERCMDS ) {
            Com_WPrintf( "%s: MAX_PACKET_USERCMDS exceeded\n", __func__ );
            SZ_Clear( &msg_write );
            break;
        }
        totalCmds += numCmds;
        MSG_WriteBits( numCmds, 5 );
        for( j = oldest->cmdNumber + 1; j <= history->cmdNumber; j++ ) {
            cmd = &cl.cmds[j & CMD_MASK];
            totalMsec += cmd->msec;
            bits = MSG_WriteDeltaUsercmd_Enhanced( oldcmd, cmd, cls.protocolVersion );
#ifdef _DEBUG
            if( cl_showpackets->integer == 3 ) {
                MSG_ShowDeltaUsercmdBits_Enhanced( bits );
            }
#endif
            oldcmd = cmd;
        }
    }

    P_FRAMES++;

    //
    // deliver the message
    //
    cursize = cls.netchan->Transmit( cls.netchan, msg_write.cursize, msg_write.data, 1 );
#ifdef _DEBUG
    if( cl_showpackets->integer == 1 ) {
        Com_Printf( "%"PRIz"(%i) ", cursize, totalCmds );
    } else if( cl_showpackets->integer == 2 ) {
        Com_Printf( "%"PRIz"(%i) ", cursize, totalMsec );
    } else if( cl_showpackets->integer == 3 ) {
        Com_Printf( " | " );
    }
#endif

    SZ_Clear( &msg_write );
}
Пример #15
0
//
// SV_SendPacket
//
bool SV_SendPacket(player_t &pl)
{
	int				bps = 0; // bytes per second, not bits per second

	client_t *cl = &pl.client;

	if (cl->reliablebuf.overflowed)
	{ 
		SZ_Clear(&cl->netbuf);
		SZ_Clear(&cl->reliablebuf);
	    SV_DropClient(pl);
		return false;
	}
	else
		if (cl->netbuf.overflowed)
			SZ_Clear(&cl->netbuf);

	sendd.clear();

	// save the reliable message 
	// it will be retransmited, if it's missed

	// the end of the buffer is reached
	if (cl->relpackets.cursize + cl->reliablebuf.cursize >= cl->relpackets.maxsize())
		cl->relpackets.cursize = 0;

	// copy the beginning and the size of a packet to the buffer
	cl->packetbegin[cl->packetnum] = cl->relpackets.cursize;
	cl->packetsize[cl->packetnum] = cl->reliablebuf.cursize;
	cl->packetseq[cl->packetnum] = cl->sequence;

	if (cl->reliablebuf.cursize)
		SZ_Write (&cl->relpackets, cl->reliablebuf.data, cl->reliablebuf.cursize);


	cl->packetnum++; // packetnum will never be more than 255
	                 // because sizeof(packetnum) == 1. Don't need
	                 // to use &0xff. Cool, eh? ;-)
	// copy sequence
	MSG_WriteLong(&sendd, cl->sequence++);
    
	// copy the reliable message to the packet first
    if (cl->reliablebuf.cursize)
    {
		SZ_Write (&sendd, cl->reliablebuf.data, cl->reliablebuf.cursize);
		cl->reliable_bps += cl->reliablebuf.cursize;
    }

	// add the unreliable part if space is available and rate value
	// allows it
	if (gametic % 35)
	    bps = (int)((double)( (cl->unreliable_bps + cl->reliable_bps) * TICRATE)/(double)(gametic%35));

    if (bps < cl->rate*1000)
	  if (cl->netbuf.cursize && (sendd.maxsize() - sendd.cursize > cl->netbuf.cursize) )
	  {
         SZ_Write (&sendd, cl->netbuf.data, cl->netbuf.cursize);
	     cl->unreliable_bps += cl->netbuf.cursize;
	  }
    
	SZ_Clear(&cl->netbuf);
	SZ_Clear(&cl->reliablebuf);
	
	// compress the packet, but not the sequence id
	if(sv_networkcompression && sendd.size() > sizeof(int))
		SV_CompressPacket(sendd, sizeof(int), cl);

	NET_SendPacket(sendd, cl->address);

	return true;
}
Пример #16
0
void Netchan_CreateFragments_(qboolean server, netchan_t *chan, sizebuf_t *msg)
{
	fragbuf_t *buf;
	int chunksize;
	int send;
	int remaining;
	int pos;
	int bufferid = 1;
	fragbufwaiting_t *wait, *p;

	if (msg->cursize == 0)
	{
		return;
	}

	// Compress if not done already
	if (*(uint32 *)msg->data != MAKEID('B', 'Z', '2', '\0'))
	{
		unsigned char compressed[65536];
		char hdr[4] = "BZ2";
		unsigned int compressedSize = msg->cursize - sizeof(hdr);	// we should fit in same data buffer minus 4 bytes for a header
		if (!BZ2_bzBuffToBuffCompress((char *)compressed, &compressedSize, (char *)msg->data, msg->cursize, 9, 0, 30))
		{
			Con_DPrintf("Compressing split packet (%d -> %d bytes)\n", msg->cursize, compressedSize);
			Q_memcpy(msg->data, hdr, sizeof(hdr));
			Q_memcpy(msg->data + sizeof(hdr), compressed, compressedSize);
			msg->cursize = compressedSize + sizeof(hdr);
		}
	}

	chunksize = chan->pfnNetchan_Blocksize(chan->connection_status);

	wait = (fragbufwaiting_t *)Mem_ZeroMalloc(sizeof(fragbufwaiting_t));

	remaining = msg->cursize;
	pos = 0;
	while (remaining > 0)
	{
		send = min(remaining, chunksize);
		remaining -= send;

		buf = Netchan_AllocFragbuf();
		if (!buf)
		{
			return;
		}

		buf->bufferid = bufferid++;

		// Copy in data
		SZ_Clear(&buf->frag_message);
		SZ_Write(&buf->frag_message, &msg->data[pos], send);
		pos += send;

		Netchan_AddFragbufToTail(wait, buf);
	}

	// Now add waiting list item to the end of buffer queue
	if (!chan->waitlist[FRAG_NORMAL_STREAM])
	{
		chan->waitlist[FRAG_NORMAL_STREAM] = wait;
	}
	else
	{
		p = chan->waitlist[FRAG_NORMAL_STREAM];
		while (p->next)
		{
			p = p->next;
		}
		p->next = wait;
	}
}
Пример #17
0
static void Test2_Poll(void)
{
    struct qsockaddr clientaddr;
    int control;
    int len;
    char name[32];
    char value[32];

    net_landriverlevel = test2Driver;
    name[0] = 0;

    len =
	dfunc.Read(test2Socket, net_message.data, net_message.maxsize,
		   &clientaddr);
    if (len < sizeof(int))
	goto Reschedule;

    net_message.cursize = len;

    MSG_BeginReading();
    control = BigLong(*((int *) net_message.data));
    MSG_ReadLong();
    if (control == -1)
	goto Error;
    if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL)
	goto Error;
    if ((control & NETFLAG_LENGTH_MASK) != len)
	goto Error;

    if (MSG_ReadByte() != CCREP_RULE_INFO)
	goto Error;

    Q_strcpy(name, MSG_ReadString());
    if (name[0] == 0)
	goto Done;
    Q_strcpy(value, MSG_ReadString());

    Con_Printf("%-16.16s  %-16.16s\n", name, value);

    SZ_Clear(&net_message);
    // save space for the header, filled in later
    MSG_WriteLong(&net_message, 0);
    MSG_WriteByte(&net_message, CCREQ_RULE_INFO);
    MSG_WriteString(&net_message, name);
    *((int *) net_message.data) =
	BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
    dfunc.Write(test2Socket, net_message.data, net_message.cursize,
		&clientaddr);
    SZ_Clear(&net_message);

  Reschedule:
    SchedulePollProcedure(&test2PollProcedure, 0.05);
    return;

  Error:
    Con_Printf("Unexpected repsonse to Rule Info request\n");
  Done:
    dfunc.CloseSocket(test2Socket);
    test2InProgress = false;
    return;
}
Пример #18
0
void Netchan_CreateFileFragmentsFromBuffer(qboolean server, netchan_t *chan, const char *filename, unsigned char *uncompressed_pbuf, int uncompressed_size)
{
	int chunksize;
	int send;
	fragbufwaiting_t *p;
	fragbuf_t *buf;
	unsigned char *pbuf;
	qboolean bCompressed;
	qboolean firstfragment;
	signed int bufferid;
	int remaining;
	int pos;
	unsigned int size;
	fragbufwaiting_t *wait;

	if (!uncompressed_size)
		return;

	bufferid = 1;
	firstfragment = TRUE;
	size = uncompressed_size;

	pbuf = (unsigned char *)Mem_Malloc(uncompressed_size);
	if (BZ2_bzBuffToBuffCompress((char*)pbuf, &size, (char*)uncompressed_pbuf, uncompressed_size, 9, 0, 30))
	{
		bCompressed = FALSE;
		Mem_Free(pbuf);
		pbuf = uncompressed_pbuf;
		size = uncompressed_size;
	}
	else
	{
		bCompressed = TRUE;
		Con_DPrintf("Compressed %s for transmission (%d -> %d)\n", filename, uncompressed_size, size);
	}

	chunksize = chan->pfnNetchan_Blocksize(chan->connection_status);
	send = chunksize;
	wait = (fragbufwaiting_t *)Mem_ZeroMalloc(0xCu);
	remaining = size;
	pos = 0;

	while (remaining > 0)
	{
		send = min(remaining, chunksize);
		buf = (fragbuf_t *)Netchan_AllocFragbuf();
		if (!buf)
		{
			Con_Printf("Couldn't allocate fragbuf_t\n");
			Mem_Free(wait);
			if (server)
				SV_DropClient(host_client, 0, "Malloc problem");
			else
				rehlds_syserror("%s:Reverse me: client-side code", __func__);

#ifdef REHLDS_FIXES
			if (bCompressed) {
				Mem_Free(pbuf);
			}
#endif
			return;
		}

		buf->bufferid = bufferid++;
		SZ_Clear(&buf->frag_message);
		if (firstfragment)
		{
			firstfragment = FALSE;
			MSG_WriteString(&buf->frag_message, filename);
			MSG_WriteString(&buf->frag_message, bCompressed ? "bz2" : "uncompressed");
			MSG_WriteLong(&buf->frag_message, uncompressed_size);
			send -= buf->frag_message.cursize;
		}

		buf->isbuffer = TRUE;
		buf->isfile = TRUE;
		buf->size = send;
		buf->foffset = pos;

		MSG_WriteBuf(&buf->frag_message, send, &pbuf[pos]);
		pos += send;
		remaining -= send;

		Netchan_AddFragbufToTail(wait, buf);
	}

	if (!chan->waitlist[FRAG_FILE_STREAM]) {
		chan->waitlist[FRAG_FILE_STREAM] = wait;
	}
	else
	{
		p = chan->waitlist[FRAG_FILE_STREAM];
		while (p->next)
			p = p->next;

		p->next = wait;
	}

#ifdef REHLDS_FIXES
	if (bCompressed) {
		Mem_Free(pbuf);
	}
#endif
}
Пример #19
0
//
// SV_SendServerInfo
// 
// Sends server info to a launcher
// TODO: Clean up and reinvent.
void SV_SendServerInfo()
{
	size_t i;

	SZ_Clear(&ml_message);
	
	MSG_WriteLong(&ml_message, CHALLENGE);
	MSG_WriteLong(&ml_message, SV_NewToken());

	// if master wants a key to be presented, present it we will
	if(MSG_BytesLeft() == 4)
		MSG_WriteLong(&ml_message, MSG_ReadLong());

	MSG_WriteString(&ml_message, (char *)hostname.cstring());

	byte playersingame = 0;
	for (i = 0; i < players.size(); ++i)
	{
		if (players[i].ingame())
			playersingame++;
	}

	MSG_WriteByte(&ml_message, playersingame);
	MSG_WriteByte(&ml_message, maxclients);

	MSG_WriteString(&ml_message, level.mapname);

	size_t numwads = wadnames.size();
	if(numwads > 0xff)numwads = 0xff;

	MSG_WriteByte(&ml_message, numwads - 1);

	for (i = 1; i < numwads; ++i)
		MSG_WriteString(&ml_message, wadnames[i].c_str());

	MSG_WriteByte(&ml_message, (int)deathmatch);
	MSG_WriteByte(&ml_message, (int)skill);
	MSG_WriteByte(&ml_message, (int)teamplay);
	MSG_WriteByte(&ml_message, (int)ctfmode);

	for (i = 0; i < players.size(); ++i)
	{
		if (players[i].ingame())
		{
			MSG_WriteString(&ml_message, players[i].userinfo.netname);
			MSG_WriteShort(&ml_message, players[i].fragcount);
			MSG_WriteLong(&ml_message, players[i].ping);

			if (teamplay || ctfmode)
				MSG_WriteByte(&ml_message, players[i].userinfo.team);
			else
				MSG_WriteByte(&ml_message, TEAM_NONE);
		}
	}

	for (i = 1; i < numwads; ++i)
		MSG_WriteString(&ml_message, wadhashes[i].c_str());

	MSG_WriteString(&ml_message, website.cstring());

	if (ctfmode || teamplay)
	{
		MSG_WriteLong(&ml_message, scorelimit);
		
		for(size_t i = 0; i < NUMTEAMS; i++)
		{
			MSG_WriteByte(&ml_message, TEAMenabled[i]);

			if (TEAMenabled[i])
				MSG_WriteLong(&ml_message, TEAMpoints[i]);
		}
	}
	
	MSG_WriteShort(&ml_message, VERSION);

//bond===========================
	MSG_WriteString(&ml_message, (char *)email.cstring());

	int timeleft = (int)(timelimit - level.time/(TICRATE*60));
	if (timeleft<0) timeleft=0;

	MSG_WriteShort(&ml_message,(int)timelimit);
	MSG_WriteShort(&ml_message,timeleft);
	MSG_WriteShort(&ml_message,(int)fraglimit);

	MSG_WriteByte(&ml_message,(BOOL)itemsrespawn);
	MSG_WriteByte(&ml_message,(BOOL)weaponstay);
	MSG_WriteByte(&ml_message,(BOOL)friendlyfire);
	MSG_WriteByte(&ml_message,(BOOL)allowexit);
	MSG_WriteByte(&ml_message,(BOOL)infiniteammo);
	MSG_WriteByte(&ml_message,(BOOL)nomonsters);
	MSG_WriteByte(&ml_message,(BOOL)monstersrespawn);
	MSG_WriteByte(&ml_message,(BOOL)fastmonsters);
	MSG_WriteByte(&ml_message,(BOOL)allowjump);
	MSG_WriteByte(&ml_message,(BOOL)allowfreelook);
	MSG_WriteByte(&ml_message,(BOOL)waddownload);
	MSG_WriteByte(&ml_message,(BOOL)emptyreset);
	MSG_WriteByte(&ml_message,(BOOL)cleanmaps);
	MSG_WriteByte(&ml_message,(BOOL)fragexitswitch);

	for (i = 0; i < players.size(); ++i)
	{
		if (players[i].ingame())
		{
			MSG_WriteShort(&ml_message, players[i].killcount);
			MSG_WriteShort(&ml_message, players[i].deathcount);
			
			int timeingame = (time(NULL) - players[i].JoinTime)/60;
			if (timeingame<0) timeingame=0;
			MSG_WriteShort(&ml_message, timeingame);
		}
	}
	
//bond===========================

    MSG_WriteLong(&ml_message, (DWORD)0x01020304);
    MSG_WriteShort(&ml_message, (WORD)maxplayers);
    
    for (i = 0; i < players.size(); ++i)
    {
        if (players[i].ingame())
        {
            MSG_WriteByte(&ml_message, (players[i].spectator ? true : false));
        }
    }

    MSG_WriteLong(&ml_message, (DWORD)0x01020305);
    MSG_WriteShort(&ml_message, strlen(password.cstring()) ? 1 : 0);

	NET_SendPacket(ml_message, net_from);
}
Пример #20
0
int Netchan_CreateFileFragments_(qboolean server, netchan_t *chan, const char *filename)
#endif // REHLDS_FIXES
{
	int chunksize;
	int compressedFileTime;
	FileHandle_t hfile;
	signed int filesize;
	int remaining;
	fragbufwaiting_t *p;
	int send;
	fragbuf_t *buf;
	char compressedfilename[MAX_PATH];
	qboolean firstfragment;
	int bufferid;
	qboolean bCompressed;
	int pos;
	fragbufwaiting_t *wait;
	int uncompressed_size;

	bufferid = 1;
	firstfragment = TRUE;
	bCompressed = FALSE;
	chunksize = chan->pfnNetchan_Blocksize(chan->connection_status);

	Q_snprintf(compressedfilename, sizeof compressedfilename, "%s.ztmp", filename);
	compressedFileTime = FS_GetFileTime(compressedfilename);
	if (compressedFileTime >= FS_GetFileTime(filename) && (hfile = FS_Open(compressedfilename, "rb")))
	{
		filesize = FS_Size(hfile);
		FS_Close(hfile);
		bCompressed = TRUE;
		hfile = FS_Open(filename, "rb");
		if (!hfile)
		{
			Con_Printf("Warning:  Unable to open %s for transfer\n", filename);
			return 0;
		}

		uncompressed_size = FS_Size(hfile);
		if (uncompressed_size > sv_filetransfermaxsize.value)
		{
			FS_Close(hfile);
			Con_Printf("Warning:  File %s is too big to transfer from host %s\n", filename, NET_AdrToString(chan->remote_address));
			return 0;
		}
	}
	else
	{
		hfile = FS_Open(filename, "rb");
		if (!hfile)
		{
			Con_Printf("Warning:  Unable to open %s for transfer\n", filename);
			return 0;
		}
		filesize = FS_Size(hfile);
		if (filesize > sv_filetransfermaxsize.value)
		{
			FS_Close(hfile);
			Con_Printf("Warning:  File %s is too big to transfer from host %s\n", filename, NET_AdrToString(chan->remote_address));
			return 0;
		}

		uncompressed_size = filesize;
		if (sv_filetransfercompression.value != 0.0)
		{
			unsigned char* uncompressed = (unsigned char*)Mem_Malloc(filesize);
			unsigned char* compressed = (unsigned char*)Mem_Malloc(filesize);
			unsigned int compressedSize = filesize;
			FS_Read(uncompressed, filesize, 1, hfile);
			if (BZ_OK == BZ2_bzBuffToBuffCompress((char*)compressed, &compressedSize, (char*)uncompressed, filesize, 9, 0, 30))
			{
				FileHandle_t destFile = FS_Open(compressedfilename, "wb");
				if (destFile)
				{
					Con_DPrintf("Creating compressed version of file %s (%d -> %d)\n", filename, filesize, compressedSize);
					FS_Write(compressed, compressedSize, 1, destFile);
					FS_Close(destFile);
					filesize = compressedSize;
					bCompressed = TRUE;
				}
			}
			Mem_Free(uncompressed);
			Mem_Free(compressed);
		}
	}
	FS_Close(hfile);

	wait = (fragbufwaiting_t *)Mem_ZeroMalloc(0xCu);
	remaining = filesize;
	pos = 0;

	while (remaining)
	{
		send = min(chunksize, remaining);
		buf = Netchan_AllocFragbuf();
		if (!buf)
		{
			Con_Printf("Couldn't allocate fragbuf_t\n");
			Mem_Free(wait);
			if (server)
			{
#ifdef REHLDS_FIXES
				SV_DropClient(&g_psvs.clients[chan->player_slot - 1], 0, "Malloc problem");
#else // REHLDS_FIXES
				SV_DropClient(host_client, 0, "Malloc problem");
#endif // REHLDS_FIXES
				return 0;
			}
			else
			{
				rehlds_syserror("%s: Reverse clientside code", __func__);
				//return 0;
			}
		}

		buf->bufferid = bufferid++;
		SZ_Clear(&buf->frag_message);
		if (firstfragment)
		{
			firstfragment = FALSE;
			MSG_WriteString(&buf->frag_message, filename);
			MSG_WriteString(&buf->frag_message, bCompressed ? "bz2" : "uncompressed");
			MSG_WriteLong(&buf->frag_message, uncompressed_size);
			send -= buf->frag_message.cursize;
		}
		buf->isfile = TRUE;
		buf->iscompressed = bCompressed;
		buf->size = send;
		buf->foffset = pos;

		Q_strncpy(buf->filename, filename, MAX_PATH - 1);
		buf->filename[MAX_PATH - 1] = 0;

		pos += send;
		remaining -= send;

		Netchan_AddFragbufToTail(wait, buf);
	}

	if (!chan->waitlist[FRAG_FILE_STREAM])
	{
		chan->waitlist[FRAG_FILE_STREAM] = wait;
	}
	else
	{
		p = chan->waitlist[FRAG_FILE_STREAM];
		while (p->next)
			p = p->next;

		p->next = wait;
	}

	return 1;
}
Пример #21
0
qbool SV_MVDWritePackets (int num)
{
	demo_frame_t	*frame, *nextframe;
	demo_client_t	*cl, *nextcl = NULL;
	int				i, j, flags;
	qbool			valid;
	double			time1, playertime, nexttime;
	vec3_t			origin, angles;
	sizebuf_t		msg;
	byte			msg_buf[MAX_MSGLEN];
	demoinfo_t		*demoinfo;

	if (!sv.mvdrecording)
		return false;

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

	if (num > demo.parsecount - demo.lastwritten + 1)
		num = demo.parsecount - demo.lastwritten + 1;

	// 'num' frames to write
	for ( ; num; num--, demo.lastwritten++)
	{
		SZ_Clear(&msg);

		frame = &demo.frames[demo.lastwritten&DEMO_FRAMES_MASK];
		time1 = frame->time;
		nextframe = frame;

		demo.dbuf = &frame->buf;

		// find two frames
		// one before the exact time (time - msec) and one after,
		// then we can interpolte exact position for current frame
		for (i = 0, cl = frame->clients, demoinfo = demo.info; i < MAX_CLIENTS; i++, cl++, demoinfo++)
		{
			if (cl->parsecount != demo.lastwritten)
				continue; // not valid

			nexttime = playertime = time1 - cl->sec;

			valid = false;

			for (j = demo.lastwritten+1; nexttime < time1 && j < demo.parsecount; j++)
			{
				nextframe = &demo.frames[j&DEMO_FRAMES_MASK];
				nextcl = &nextframe->clients[i];

				if (nextcl->parsecount != j)
					break; // disconnected?
				if (nextcl->fixangle)
					break; // respawned, or walked into teleport, do not interpolate!
				if (!(nextcl->flags & DF_DEAD) && (cl->flags & DF_DEAD))
					break; // respawned, do not interpolate

				nexttime = nextframe->time - nextcl->sec;

				if (nexttime >= time1)
				{
					// good, found what we were looking for
					valid = true;
					break;
				}
			}

			if (valid)
			{
				float f = 0;
				float z = nexttime - playertime;

				if ( z )
					f = (time1 - nexttime) / z;

				for (j = 0; j < 3; j++) {
					angles[j] = adjustangle(cl->info.angles[j], nextcl->info.angles[j], 1.0 + f);
					origin[j] = nextcl->info.origin[j] + f * (nextcl->info.origin[j] - cl->info.origin[j]);
				}
			} else {
				VectorCopy(cl->info.origin, origin);
				VectorCopy(cl->info.angles, angles);
			}

			// now write it to buf
			flags = cl->flags;

			for (j=0; j < 3; j++)
				if (origin[j] != demoinfo->origin[i])
					flags |= DF_ORIGIN << j;

			for (j=0; j < 3; j++)
				if (angles[j] != demoinfo->angles[j])
					flags |= DF_ANGLES << j;

			if (cl->info.model != demoinfo->model)
				flags |= DF_MODEL;
			if (cl->info.effects != demoinfo->effects)
				flags |= DF_EFFECTS;
			if (cl->info.skinnum != demoinfo->skinnum)
				flags |= DF_SKINNUM;
			if (cl->info.weaponframe != demoinfo->weaponframe)
				flags |= DF_WEAPONFRAME;

			MSG_WriteByte (&msg, svc_playerinfo);
			MSG_WriteByte (&msg, i);
			MSG_WriteShort (&msg, flags);

			MSG_WriteByte (&msg, cl->frame);

			for (j=0 ; j<3 ; j++)
				if (flags & (DF_ORIGIN << j))
					MSG_WriteCoord (&msg, origin[j]);

			for (j=0 ; j<3 ; j++)
				if (flags & (DF_ANGLES << j))
					MSG_WriteAngle16 (&msg, angles[j]);

			if (flags & DF_MODEL)
				MSG_WriteByte (&msg, cl->info.model);

			if (flags & DF_SKINNUM)
				MSG_WriteByte (&msg, cl->info.skinnum);

			if (flags & DF_EFFECTS)
				MSG_WriteByte (&msg, cl->info.effects);

			if (flags & DF_WEAPONFRAME)
				MSG_WriteByte (&msg, cl->info.weaponframe);

			VectorCopy(cl->info.origin, demoinfo->origin);
			VectorCopy(cl->info.angles, demoinfo->angles);
			demoinfo->skinnum = cl->info.skinnum;
			demoinfo->effects = cl->info.effects;
			demoinfo->weaponframe = cl->info.weaponframe;
			demoinfo->model = cl->info.model;
		}

		SV_MVDWriteToDisk(demo.lasttype,demo.lastto, (float)time1); // this goes first to reduce demo size a bit
		SV_MVDWriteToDisk(0,0, (float)time1); // now goes the rest
		if (msg.cursize)
			SV_WriteMVDMessage(&msg, dem_all, 0, (float)time1);

		if (!sv.mvdrecording)
		{
			Com_DPrintf("SV_MVDWritePackets: error: in sv.mvdrecording\n");
			return false; // ERROR
		}
	}

	if (!sv.mvdrecording)
		return false; // ERROR

	if (demo.lastwritten > demo.parsecount)
		demo.lastwritten = demo.parsecount;

	demo.dbuf = &demo.frames[demo.parsecount&DEMO_FRAMES_MASK].buf;
	demo.dbuf->maxsize = MAXSIZE + demo.dbuf->bufsize;

	return true;
}
Пример #22
0
qboolean Netchan_CopyNormalFragments(netchan_t *chan)
{
	fragbuf_t *p, *n;

	if (!chan->incomingready[FRAG_NORMAL_STREAM])
		return FALSE;

	if (!chan->incomingbufs[FRAG_NORMAL_STREAM])
	{
		Con_Printf("%s:  Called with no fragments readied\n", __func__);
		chan->incomingready[FRAG_NORMAL_STREAM] = FALSE;
		return FALSE;
	}

	p = chan->incomingbufs[FRAG_NORMAL_STREAM];

	SZ_Clear(&net_message);
	MSG_BeginReading();

#ifdef REHLDS_FIXES
	bool overflowed = false;
#endif // REHLDS_FIXES

	while (p)
	{
		n = p->next;

#ifdef REHLDS_FIXES
		if (net_message.cursize + p->frag_message.cursize <= net_message.maxsize)
			SZ_Write(&net_message, p->frag_message.data, p->frag_message.cursize);
		else
			overflowed = true;
#else // REHLDS_FIXES
		SZ_Write(&net_message, p->frag_message.data, p->frag_message.cursize);
#endif // REHLDS_FIXES

		Mem_Free(p);
		p = n;
	}

#ifdef REHLDS_FIXES
	if (overflowed)
	{
		if (chan->player_slot == 0)
		{
			Con_Printf("%s: Incoming overflowed\n", __func__);
		}
		else
		{
			Con_Printf("%s: Incoming overflowed from %s\n", __func__, g_psvs.clients[chan->player_slot - 1].name);
		}

		SZ_Clear(&net_message);

		chan->incomingbufs[FRAG_NORMAL_STREAM] = nullptr;
		chan->incomingready[FRAG_NORMAL_STREAM] = FALSE;

		return FALSE;
	}
#endif // REHLDS_FIXES

	if (*(uint32 *)net_message.data == MAKEID('B', 'Z', '2', '\0'))
	{
		char uncompressed[65536];
		unsigned int uncompressedSize = 65536;
		BZ2_bzBuffToBuffDecompress(uncompressed, &uncompressedSize, (char*)net_message.data + 4, net_message.cursize - 4, 1, 0);
		Q_memcpy(net_message.data, uncompressed, uncompressedSize);
		net_message.cursize = uncompressedSize;
	}

	chan->incomingbufs[FRAG_NORMAL_STREAM] = nullptr;
	chan->incomingready[FRAG_NORMAL_STREAM] = FALSE;

	return TRUE;
}
Пример #23
0
/*
==================
SV_ClearDatagram

==================
*/
void SV_ClearDatagram (void)
{
	SZ_Clear (&sv.datagram);
}
Пример #24
0
qboolean Netchan_CopyFileFragments(netchan_t *chan)
{
	fragbuf_t *p;
	int nsize;
	unsigned char *buffer;
	int pos;
	signed int cursize;
	char filename[MAX_PATH];
	char compressor[32];
	fragbuf_s *n;
	qboolean bCompressed;
	unsigned int uncompressedSize;


	if (!chan->incomingready[FRAG_FILE_STREAM])
		return FALSE;

	p = chan->incomingbufs[FRAG_FILE_STREAM];
	if (!p)
	{
		Con_Printf("%s:  Called with no fragments readied\n", __func__);
		chan->incomingready[FRAG_FILE_STREAM] = FALSE;
		return FALSE;
	}

	bCompressed = FALSE;
	SZ_Clear(&net_message);
	MSG_BeginReading();
	SZ_Write(&net_message, p->frag_message.data, p->frag_message.cursize);
	Q_strncpy(filename, MSG_ReadString(), sizeof(filename) - 1);
	filename[sizeof(filename) - 1] = 0;

	Q_strncpy(compressor, MSG_ReadString(), sizeof(compressor) - 1);
	compressor[sizeof(compressor) - 1] = 0;
	if (!Q_stricmp(compressor, "bz2"))
		bCompressed = TRUE;

	uncompressedSize = (unsigned int)MSG_ReadLong();

#ifdef REHLDS_FIXES
	// TODO: this condition is invalid for server->client
	// TODO: add console message for client
	// TODO: add client name to message
	if (uncompressedSize > 1024 * 64) {
		Con_Printf("Received too large file (size=%u)\nFlushing input queue\n", uncompressedSize);
		Netchan_FlushIncoming(chan, 1);
		return FALSE;
	}
#endif

	if (Q_strlen(filename) <= 0)
	{
		Con_Printf("File fragment received with no filename\nFlushing input queue\n");
		Netchan_FlushIncoming(chan, 1);
		return FALSE;
	}

	if (Q_strstr(filename, ".."))
	{
		Con_Printf("File fragment received with relative path, ignoring\n");
		Netchan_FlushIncoming(chan, 1);
		return FALSE;
	}

	if (filename[0] != '!' && !IsSafeFileToDownload(filename))
	{
		Con_Printf("File fragment received with bad path, ignoring\n");
		Netchan_FlushIncoming(chan, 1);
		return FALSE;
	}
	// This prohibits to write files to FS on server
	if (g_pcls.state == ca_dedicated && filename[0] != '!')
	{
		Con_Printf("File fragment received with bad path, ignoring (2)\n");
		Netchan_FlushIncoming(chan, 1);
		return FALSE;
	}

	Q_strncpy(chan->incomingfilename, filename, MAX_PATH - 1);
	chan->incomingfilename[MAX_PATH - 1] = 0;

	if (filename[0] != '!' && FS_FileExists(filename))
	{
		Con_Printf("Can't download %s, already exists\n", filename);
		Netchan_FlushIncoming(chan, 1);
		return TRUE;
	}

	nsize = 0;
	while (p)
	{
		nsize += p->frag_message.cursize;
		if (p == chan->incomingbufs[FRAG_FILE_STREAM])
			nsize -= msg_readcount;
		p = p->next;
	}

	buffer = (unsigned char*)Mem_ZeroMalloc(nsize + 1);
	if (!buffer)
	{
		Con_Printf("Buffer allocation failed on %i bytes\n", nsize + 1);
		Netchan_FlushIncoming(chan, 1);
		return FALSE;
	}

	p = chan->incomingbufs[FRAG_FILE_STREAM];
	pos = 0;
	while (p)
	{
		n = p->next;

		cursize = p->frag_message.cursize;
		// First message has the file name, don't write that into the data stream, just write the rest of the actual data
		if (p == chan->incomingbufs[FRAG_FILE_STREAM])
		{
			// Copy it in
			cursize -= msg_readcount;
			Q_memcpy(&buffer[pos], &p->frag_message.data[msg_readcount], cursize);
			p->frag_message.cursize = cursize;
		}
		else
		{
			Q_memcpy(&buffer[pos], p->frag_message.data, cursize);
		}
		pos += p->frag_message.cursize;
		Mem_Free(p);
		p = n;

	}

	if (bCompressed)
	{
		unsigned char* uncompressedBuffer = (unsigned char*)Mem_Malloc(uncompressedSize);
		Con_DPrintf("Decompressing file %s (%d -> %d)\n", filename, nsize, uncompressedSize);
		BZ2_bzBuffToBuffDecompress((char*)uncompressedBuffer, &uncompressedSize, (char*)buffer, nsize, 1, 0);
		Mem_Free(buffer);
		pos = uncompressedSize;
		buffer = uncompressedBuffer;
	}

	if (filename[0] == '!')
	{
		if (chan->tempbuffer)
		{
			Con_DPrintf("Netchan_CopyFragments:  Freeing holdover tempbuffer\n");
			Mem_Free(chan->tempbuffer);
		}
		chan->tempbuffer = buffer;
		chan->tempbuffersize = pos;
	}
	else
	{
		char filedir[MAX_PATH];
		char *pszFileName;
		FileHandle_t handle;

#ifdef REHLDS_CHECKS
		Q_strncpy(filedir, filename, sizeof(filedir) - 1);
		filedir[sizeof(filedir) - 1] = 0;
#else
		Q_strncpy(filedir, filename, sizeof(filedir));
#endif // REHLDS_CHECKS
		COM_FixSlashes(filedir);
		pszFileName = Q_strrchr(filedir, '\\');
		if (pszFileName)
		{
			*pszFileName = 0;

#ifdef REHLDS_FIXES
			FS_CreateDirHierarchy(filedir, "GAMEDOWNLOAD");
#endif
		}

#ifndef REHLDS_FIXES
		FS_CreateDirHierarchy(filedir, "GAMEDOWNLOAD");
#endif
		handle = FS_OpenPathID(filename, "wb", "GAMEDOWNLOAD");
		if (!handle)
		{
			Con_Printf("File open failed %s\n", filename);
			Netchan_FlushIncoming(chan, 1);

#ifdef REHLDS_FIXES
			Mem_Free(buffer);
#endif
			return FALSE;
		}

		Sys_Printf("COM_WriteFile: %s\n", filename);
		FS_Write(buffer, pos, 1, handle);
		FS_Close(handle);

		Mem_Free(buffer);
	}
	SZ_Clear(&net_message);
	chan->incomingbufs[FRAG_FILE_STREAM] = nullptr;
	chan->incomingready[FRAG_FILE_STREAM] = FALSE;
	msg_readcount = 0;
	return TRUE;
}
Пример #25
0
static qsocket_t *_Datagram_Connect (char *host)
{
	struct qsockaddr sendaddr;
	struct qsockaddr readaddr;
	qsocket_t	*sock;
	int			newsock;
	int			ret;
	int			reps;
	double		start_time;
	int			control;
	char		*reason;

	// see if we can resolve the host name
	if (dfunc.GetAddrFromName(host, &sendaddr) == -1)
		return NULL;

	newsock = dfunc.OpenSocket (0);
	if (newsock == -1)
		return NULL;

	sock = NET_NewQSocket ();
	if (sock == NULL)
		goto ErrorReturn2;
	sock->socket = newsock;
	sock->landriver = net_landriverlevel;

	// connect to the host
	if (dfunc.Connect (newsock, &sendaddr) == -1)
		goto ErrorReturn;

	// send the connection request
	Con_Printf("trying...\n"); SCR_UpdateScreen ();
	start_time = net_time;

	for (reps = 0; reps < 3; reps++)
	{
		SZ_Clear(&net_message);
		// save space for the header, filled in later
		MSG_WriteLong(&net_message, 0);
		MSG_WriteByte(&net_message, CCREQ_CONNECT);
		MSG_WriteString(&net_message, "QUAKE");
		MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
		dfunc.Write (newsock, net_message.data, net_message.cursize, &sendaddr);
		SZ_Clear(&net_message);
		do
		{
			ret = dfunc.Read (newsock, net_message.data, net_message.maxsize, &readaddr);
			// if we got something, validate it
			if (ret > 0)
			{
				// is it from the right place?
				if (sfunc.AddrCompare(&readaddr, &sendaddr) != 0)
				{
#ifdef DEBUG
					Con_Printf("wrong reply address\n");
					Con_Printf("Expected: %s\n", StrAddr (&sendaddr));
					Con_Printf("Received: %s\n", StrAddr (&readaddr));
					SCR_UpdateScreen ();
#endif
					ret = 0;
					continue;
				}

				if (ret < sizeof(int))
				{
					ret = 0;
					continue;
				}

				net_message.cursize = ret;
				MSG_BeginReading ();

				control = BigLong(*((int *)net_message.data));
				MSG_ReadLong();
				if (control == -1)
				{
					ret = 0;
					continue;
				}
				if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)
				{
					ret = 0;
					continue;
				}
				if ((control & NETFLAG_LENGTH_MASK) != ret)
				{
					ret = 0;
					continue;
				}
			}
		}
		while (ret == 0 && (SetNetTime() - start_time) < 2.5);
		if (ret)
			break;
		Con_Printf("still trying...\n"); SCR_UpdateScreen ();
		start_time = SetNetTime();
	}

	if (ret == 0)
	{
		reason = "No Response";
		Con_Printf("%s\n", reason);
		Q_strcpy(m_return_reason, reason);
		goto ErrorReturn;
	}

	if (ret == -1)
	{
		reason = "Network Error";
		Con_Printf("%s\n", reason);
		Q_strcpy(m_return_reason, reason);
		goto ErrorReturn;
	}

	ret = MSG_ReadByte();
	if (ret == CCREP_REJECT)
	{
		reason = MSG_ReadString();
		Con_Printf(reason);
		Q_strncpy(m_return_reason, reason, 31);
		goto ErrorReturn;
	}

	if (ret == CCREP_ACCEPT)
	{
		Q_memcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr));
		dfunc.SetSocketPort (&sock->addr, MSG_ReadLong());
	}
	else
	{
		reason = "Bad Response";
		Con_Printf("%s\n", reason);
		Q_strcpy(m_return_reason, reason);
		goto ErrorReturn;
	}

	dfunc.GetNameFromAddr (&sendaddr, sock->address);

	Con_Printf ("Connection accepted\n");
	sock->lastMessageTime = SetNetTime();

	// switch the connection to the specified address
	if (dfunc.Connect (newsock, &sock->addr) == -1)
	{
		reason = "Connect to Game failed";
		Con_Printf("%s\n", reason);
		Q_strcpy(m_return_reason, reason);
		goto ErrorReturn;
	}

	m_return_onerror = false;
	return sock;

ErrorReturn:
	NET_FreeQSocket(sock);
ErrorReturn2:
	dfunc.CloseSocket(newsock);
	if (m_return_onerror)
	{
		key_dest = key_menu;
		m_state = m_return_state;
		m_return_onerror = false;
	}
	return NULL;
}
Пример #26
0
void Netchan_Transmit(netchan_t *chan, int length, byte *data)
{
#ifdef REHLDS_FIXES
	byte send_buf[MAX_UDP_PACKET];
#else
	byte send_buf[NET_MAX_MESSAGE];
#endif
	qboolean send_reliable;
	qboolean send_reliable_fragment;
	qboolean send_resending = false;
	unsigned w1, w2;
	int i, j;

	float fRate;

	sizebuf_t sb_send;
	sb_send.data = send_buf;
	sb_send.buffername = "Netchan_Transmit";
	sb_send.maxsize = sizeof(send_buf);
	sb_send.flags = 0;
	sb_send.cursize = 0;

	// check for message overflow
	if (chan->message.flags & 2) {
		Con_Printf("%s:Outgoing message overflow\n", NET_AdrToString(chan->remote_address));
		return;
	}

	// if the remote side dropped the last reliable message, resend it
	send_reliable = false;

	if (chan->incoming_acknowledged > chan->last_reliable_sequence &&
		chan->incoming_reliable_acknowledged != chan->reliable_sequence)
	{
		send_reliable = true;
		send_resending = true;
	}

	//
	// A packet can have "reliable payload + frag payload + unreliable payload
	// frag payload can be a file chunk, if so, it needs to be parsed on the receiving end and reliable payload + unreliable payload need
	// to be passed on to the message queue.  The processing routine needs to be able to handle the case where a message comes in and a file
	// transfer completes
	//
	//
	// if the reliable transmit buffer is empty, copy the current message out
	if (!chan->reliable_length)
	{
		qboolean send_frag = false;
		fragbuf_t *pbuf;

		// Will be true if we are active and should let chan->message get some bandwidth
		int		 send_from_frag[MAX_STREAMS] = { 0, 0 };
		int		 send_from_regular = 0;

#ifdef REHLDS_FIXES
		if (chan->message.cursize > MAX_MSGLEN)
		{
			Netchan_CreateFragments_(chan == &g_pcls.netchan ? 1 : 0, chan, &chan->message);
			SZ_Clear(&chan->message);
		}
#endif

		// 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)
		Netchan_FragSend(chan);

		// Sending regular payload
		send_from_regular = (chan->message.cursize) ? 1 : 0;

		// Check to see if we are sending a frag payload
		//
		for (i = 0; i < MAX_STREAMS; i++)
		{
			if (chan->fragbufs[i])
			{
				send_from_frag[i] = 1;
			}
		}

		// Stall reliable payloads if sending from frag buffer
		if (send_from_regular && (send_from_frag[FRAG_NORMAL_STREAM]))
		{
			send_from_regular = false;

			// If the reliable buffer has gotten too big, queue it at the end of everything and clear out buffer
			//
			if (chan->message.cursize > MAX_RELIABLE_PAYLOAD)
			{
				Netchan_CreateFragments_(chan == &g_pcls.netchan ? 1 : 0, chan, &chan->message);
				SZ_Clear(&chan->message);
			}
		}

		// Startpos will be zero if there is no regular payload
		for (i = 0; i < MAX_STREAMS; i++)
		{
			chan->frag_startpos[i] = 0;

			// Assume no fragment is being sent
			chan->reliable_fragment[i] = 0;
			chan->reliable_fragid[i] = 0;
			chan->frag_length[i] = 0;

			if (send_from_frag[i])
			{
				send_frag = true;
			}
		}

		if (send_from_regular || send_frag)
		{
			chan->reliable_sequence ^= 1;
			send_reliable = true;
		}

		if (send_from_regular) {
#ifdef REHLDS_FIXES
			Q_memcpy(chan->reliable_buf, chan->message.data, chan->message.cursize);
#else
			Q_memcpy(chan->reliable_buf, chan->message_buf, chan->message.cursize);
#endif
			chan->reliable_length = chan->message.cursize;
			SZ_Clear(&chan->message);

			// If we send fragments, this is where they'll start
			for (i = 0; i < MAX_STREAMS; i++) {
				chan->frag_startpos[i] = chan->reliable_length;
			}
		}

		for (i = 0; i < MAX_STREAMS; i++) {
			int fragment_size;

			// Is there something in the fragbuf?
			pbuf = chan->fragbufs[i];

			fragment_size = 0; // Compiler warning.
			if (pbuf)
			{
				fragment_size = pbuf->frag_message.cursize;

				// Files set size a bit differently.
				if (pbuf->isfile && !pbuf->isbuffer)
				{
					fragment_size = pbuf->size;
				}
			}

			// Make sure we have enought space left
			if (send_from_frag[i] && pbuf && ((chan->reliable_length + fragment_size) < MAX_RELIABLE_PAYLOAD)) {

				chan->reliable_fragid[i] = MAKE_FRAGID(pbuf->bufferid, chan->fragbufcount[i]); // Which buffer are we sending?

				// If it's not in-memory, then we'll need to copy it in frame the file handle.
				if (pbuf->isfile && !pbuf->isbuffer)	{
					char compressedfilename[MAX_PATH];
					FileHandle_t hfile;
					if (pbuf->iscompressed)
					{
						Q_snprintf(compressedfilename, sizeof(compressedfilename), "%s.ztmp", pbuf->filename);
						hfile = FS_Open(compressedfilename, "rb");
					}
					else
					{
						hfile = FS_Open(pbuf->filename, "rb");
					}
					FS_Seek(hfile, pbuf->foffset, FILESYSTEM_SEEK_HEAD);
					FS_Read(&pbuf->frag_message.data[pbuf->frag_message.cursize], pbuf->size, 1, hfile);
					pbuf->frag_message.cursize += pbuf->size;
					FS_Close(hfile);
				}


				Q_memcpy(chan->reliable_buf + chan->reliable_length, pbuf->frag_message.data, pbuf->frag_message.cursize);
				chan->reliable_length += pbuf->frag_message.cursize;
				chan->frag_length[i] = pbuf->frag_message.cursize;


				// Unlink  pbuf
				Netchan_UnlinkFragment(pbuf, &chan->fragbufs[i]);

				chan->reliable_fragment[i] = 1;

				// Offset the rest of the starting positions
				for (j = i + 1; j < MAX_STREAMS; j++)
				{
					chan->frag_startpos[j] += chan->frag_length[i];
				}
			}
		}
	}

	// Prepare the packet header
	w1 = chan->outgoing_sequence | (send_reliable << 31);
	w2 = chan->incoming_sequence | (chan->incoming_reliable_sequence << 31);

	send_reliable_fragment = false;

	for (i = 0; i < MAX_STREAMS; i++)
	{
		if (chan->reliable_fragment[i])
		{
			send_reliable_fragment = true;
			break;
		}
	}

	if (send_reliable && send_reliable_fragment)
	{
		w1 |= (1 << 30);
	}

	chan->outgoing_sequence++;

	MSG_WriteLong(&sb_send, w1);
	MSG_WriteLong(&sb_send, w2);

	if (send_reliable && send_reliable_fragment)
	{
		for (i = 0; i < MAX_STREAMS; i++)
		{
			if (chan->reliable_fragment[i])
			{
				MSG_WriteByte(&sb_send, 1);
				MSG_WriteLong(&sb_send, chan->reliable_fragid[i]);
				MSG_WriteShort(&sb_send, chan->frag_startpos[i]);
				MSG_WriteShort(&sb_send, chan->frag_length[i]);
			}
			else
			{
				MSG_WriteByte(&sb_send, 0);
			}
		}
	}

	// Copy the reliable message to the packet first
	if (send_reliable) {
		SZ_Write(&sb_send, chan->reliable_buf, chan->reliable_length);
		chan->last_reliable_sequence = chan->outgoing_sequence - 1;
	}

	// Is there room for the unreliable payload?
	int max_send_size = MAX_ROUTEABLE_PACKET;
	if (!send_resending)
		max_send_size = sb_send.maxsize;

	if ((max_send_size - sb_send.cursize) >= length) {
		SZ_Write(&sb_send, data, length);
	}
	else {
		Con_DPrintf("Netchan_Transmit:  Unreliable would overfow, ignoring\n");
	}

	// Deal with packets that are too small for some networks
	if (sb_send.cursize < 16)	// Packet too small for some networks
	{
		// Go ahead and pad a full 16 extra bytes -- this only happens during authentication / signon
		for (int i = sb_send.cursize; i < 16; i++)
		{
			// Note that the server can parse svc_nop, too.
			MSG_WriteByte(&sb_send, svc_nop);
		}
	}

	int statId = chan->flow[FLOW_OUTGOING].current & 0x1F;
	chan->flow[FLOW_OUTGOING].stats[statId].size = sb_send.cursize + UDP_HEADER_SIZE;
	chan->flow[FLOW_OUTGOING].stats[statId].time = realtime;
	chan->flow[FLOW_OUTGOING].current++;
	Netchan_UpdateFlow(chan);

	if (!g_pcls.demoplayback)
	{
		COM_Munge2(sb_send.data + 8, sb_send.cursize - 8, (unsigned char)(chan->outgoing_sequence - 1));

		if (g_modfuncs.m_pfnProcessOutgoingNet)
			g_modfuncs.m_pfnProcessOutgoingNet(chan, &sb_send);

		NET_SendPacket(chan->sock, sb_send.cursize, sb_send.data, chan->remote_address);
	}

	if (g_psv.active && sv_lan.value != 0.0f && sv_lan_rate.value > MIN_RATE)
		fRate = 1.0 / sv_lan_rate.value;
	else
		fRate = 1.0 / chan->rate;

	if (chan->cleartime < realtime) {
		chan->cleartime = realtime;
	}

	chan->cleartime += (sb_send.cursize + UDP_HEADER_SIZE) * fRate;

	if (net_showpackets.value != 0.0f && net_showpackets.value != 2.0f) {
		char c = (chan == &g_pcls.netchan) ? 'c' : 's';

		Con_Printf(" %c --> sz=%i seq=%i ack=%i rel=%i tm=%f\n"
				   , c
				   , sb_send.cursize
				   , chan->outgoing_sequence - 1
				   , chan->incoming_sequence
				   , send_reliable ? 1 : 0
				   , (float)(chan == &g_pcls.netchan ? g_pcl.time : g_psv.time));
	}
}
Пример #27
0
static void Test_f (void)
{
	char	*host;
	int		n;
	int		max = MAX_SCOREBOARD;
	struct qsockaddr sendaddr;

	if (testInProgress)
		return;

	host = Cmd_Argv (1);

	if (host && hostCacheCount)
	{
		for (n = 0; n < hostCacheCount; n++)
			if (Q_strcasecmp (host, hostcache[n].name) == 0)
			{
				if (hostcache[n].driver != myDriverLevel)
					continue;
				net_landriverlevel = hostcache[n].ldriver;
				max = hostcache[n].maxusers;
				Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));
				break;
			}
		if (n < hostCacheCount)
			goto JustDoIt;
	}

	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
	{
		if (!net_landrivers[net_landriverlevel].initialized)
			continue;

		// see if we can resolve the host name
		if (dfunc.GetAddrFromName(host, &sendaddr) != -1)
			break;
	}
	if (net_landriverlevel == net_numlandrivers)
		return;

JustDoIt:
	testSocket = dfunc.OpenSocket(0);
	if (testSocket == -1)
		return;

	testInProgress = true;
	testPollCount = 20;
	testDriver = net_landriverlevel;

	for (n = 0; n < max; n++)
	{
		SZ_Clear(&net_message);
		// save space for the header, filled in later
		MSG_WriteLong(&net_message, 0);
		MSG_WriteByte(&net_message, CCREQ_PLAYER_INFO);
		MSG_WriteByte(&net_message, n);
		*((int *)net_message.data) = BigLong(NETFLAG_CTL | 	(net_message.cursize & NETFLAG_LENGTH_MASK));
		dfunc.Write (testSocket, net_message.data, net_message.cursize, &sendaddr);
	}
	SZ_Clear(&net_message);
	SchedulePollProcedure(&testPollProcedure, 0.1);
}
Пример #28
0
qboolean Netchan_Process(netchan_t *chan)
{
	int				i;
	unsigned int	sequence, sequence_ack;
	unsigned int	reliable_ack, reliable_message;
	unsigned int	fragid[MAX_STREAMS] = { 0, 0 };
	qboolean		frag_message[MAX_STREAMS] = { false, false };
	int				frag_offset[MAX_STREAMS] = { 0, 0 };
	int				frag_length[MAX_STREAMS] = { 0, 0 };
	qboolean		message_contains_fragments;


	if (!g_pcls.demoplayback && !g_pcls.passive)
	{
		if (!NET_CompareAdr(net_from, chan->remote_address))
			return FALSE;
	}

	chan->last_received = realtime;

	// get sequence numbers
	MSG_BeginReading();
	sequence = MSG_ReadLong();
	sequence_ack = MSG_ReadLong();

	if (sequence_ack & 0x40000000)
	{
		if (!g_modfuncs.m_pfnProcessIncomingNet)
			return FALSE;
	}

	if (g_modfuncs.m_pfnProcessIncomingNet)
	{
		if (!g_modfuncs.m_pfnProcessIncomingNet(chan, &net_message))
			return FALSE;
	}

	reliable_message = sequence >> 31;
	reliable_ack = sequence_ack >> 31;
	message_contains_fragments = sequence & (1 << 30) ? true : false;

	COM_UnMunge2(&net_message.data[8], net_message.cursize - 8, sequence & 0xFF);
	if (message_contains_fragments)
	{
		for (i = 0; i < MAX_STREAMS; i++)
		{
			if (MSG_ReadByte())
			{
				frag_message[i] = true;
				fragid[i] = MSG_ReadLong();
				frag_offset[i] = MSG_ReadShort();
				frag_length[i] = MSG_ReadShort();
			}
		}

		if (!Netchan_Validate(chan, frag_message, fragid, frag_offset, frag_length))
			return FALSE;
	}

	sequence &= ~(1 << 31);
	sequence &= ~(1 << 30);
	sequence_ack &= ~(1 << 31);
	sequence_ack &= ~(1 << 30);

	if (net_showpackets.value != 0.0 && net_showpackets.value != 3.0)
	{
		char c = (chan == &g_pcls.netchan) ? 'c' : 's';

		Con_Printf(
			" %c <-- sz=%i seq=%i ack=%i rel=%i tm=%f\n",
			c,
			net_message.cursize,
			sequence,
			sequence_ack,
			reliable_message,
			(chan == &g_pcls.netchan) ? g_pcl.time : g_psv.time);
	}

	if (sequence <= (unsigned)chan->incoming_sequence)
	{
		if (net_showdrop.value != 0.0) {
			if (sequence == (unsigned)chan->incoming_sequence)
				Con_Printf("%s:duplicate packet %i at %i\n", NET_AdrToString(chan->remote_address), sequence, chan->incoming_sequence);
			else
				Con_Printf("%s:out of order packet %i at %i\n", NET_AdrToString(chan->remote_address), sequence, chan->incoming_sequence);
		}
		return FALSE;
	}

	//
	// dropped packets don't keep the message from being used
	//
	net_drop = sequence - (chan->incoming_sequence + 1);
	if (net_drop > 0 && net_showdrop.value != 0.0)
	{
		Con_Printf("%s:Dropped %i packets at %i\n", NET_AdrToString(chan->remote_address), net_drop, sequence);
	}

	//
	// if the current outgoing reliable message has been acknowledged
	// clear the buffer to make way for the next
	//
	if (reliable_ack == (unsigned)chan->reliable_sequence)
	{
		// Make sure we actually could have ack'd this message
#ifdef REHLDS_FIXES
		if (sequence_ack >= (unsigned)chan->last_reliable_sequence)
#else // REHLDS_FIXES
		if (chan->incoming_acknowledged + 1 >= chan->last_reliable_sequence)
#endif // REHLDS_FIXES
		{
			chan->reliable_length = 0;	// it has been received
		}
	}

	//
	// if this message contains a reliable message, bump incoming_reliable_sequence
	//
	chan->incoming_sequence = sequence;
	chan->incoming_acknowledged = sequence_ack;
	chan->incoming_reliable_acknowledged = reliable_ack;
	if (reliable_message)
	{
		chan->incoming_reliable_sequence ^= 1;
	}

	int statId = chan->flow[FLOW_INCOMING].current & 0x1F;
	chan->flow[FLOW_INCOMING].stats[statId].size = net_message.cursize + UDP_HEADER_SIZE;
	chan->flow[FLOW_INCOMING].stats[statId].time = realtime;
	chan->flow[FLOW_INCOMING].current++;
	Netchan_UpdateFlow(chan);

	if (message_contains_fragments)
	{
		for (i = 0; i < MAX_STREAMS; i++)
		{
			int j;
			fragbuf_t *pbuf;
			int inbufferid;
			int intotalbuffers;

			if (!frag_message[i])
				continue;

			inbufferid = FRAG_GETID(fragid[i]);
			intotalbuffers = FRAG_GETCOUNT(fragid[i]);

			if (fragid[i] != 0)
			{
				pbuf = Netchan_FindBufferById(&chan->incomingbufs[i], fragid[i], true);
				if (pbuf) {
					int len = frag_length[i];
					SZ_Clear(&pbuf->frag_message);
					SZ_Write(&pbuf->frag_message, &net_message.data[msg_readcount + frag_offset[i]], len);
				}
				else {
					Con_Printf("Netchan_Process:  Couldn't allocate or find buffer %i\n", inbufferid);
				}
				// Count # of incoming bufs we've queued? are we done?
				Netchan_CheckForCompletion(chan, i, intotalbuffers);
			}

			// Rearrange incoming data to not have the frag stuff in the middle of it
			int wpos = msg_readcount + frag_offset[i];
			int rpos = wpos + frag_length[i];

			Q_memmove(net_message.data + wpos, net_message.data + rpos, net_message.cursize - rpos);
			net_message.cursize -= frag_length[i];

			for (j = i + 1; j < MAX_STREAMS; j++)
			{
				frag_offset[j] -= frag_length[i]; // fragments order already validated
			}
		}

		// Is there anything left to process?
		if (net_message.cursize <= 16)
			return FALSE;
	}

	return TRUE;
}
Пример #29
0
/*
==================
Host_ShutdownServer

This only happens at the end of a game, not between levels
==================
*/
void Host_ShutdownServer(qboolean crash)
{
	int		i;
	int		count;
	sizebuf_t	buf;
	char		message[4];
	double	start;

	if (!sv.active)
		return;

	sv.active = false;

// stop all client sounds immediately
	if (cls.state == ca_connected)
		CL_Disconnect ();

// flush any pending messages - like the score!!!
	start = Sys_FloatTime();
	do
	{
		count = 0;
		for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
		{
			if (host_client->active && host_client->message.cursize)
			{
				if (NET_CanSendMessage (host_client->netconnection))
				{
					NET_SendMessage(host_client->netconnection, &host_client->message);
					SZ_Clear (&host_client->message);
				}
				else
				{
					NET_GetMessage(host_client->netconnection);
					count++;
				}
			}
		}
		if ((Sys_FloatTime() - start) > 3.0)
			break;
	}
	while (count);

// make sure all the clients know we're disconnecting
	buf.data = message;
	buf.maxsize = 4;
	buf.cursize = 0;
	MSG_WriteByte(&buf, svc_disconnect);
	count = NET_SendToAll(&buf, 5);
	if (count)
		Con_Printf("Host_ShutdownServer: NET_SendToAll failed for %u clients\n", count);

	for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
		if (host_client->active)
			SV_DropClient(crash);

//
// clear structures
//
	memset (&sv, 0, sizeof(sv));
	memset (svs.clients, 0, svs.maxclientslimit*sizeof(client_t));
}
Пример #30
0
// All changes need to be in SV_SendEffect(), SV_ParseEffect(),
// SV_SaveEffects(), SV_LoadEffects(), CL_ParseEffect()
void SV_SendEffect (sizebuf_t *sb, int idx)
{
	qboolean	DoTest;
	vec3_t		TestO1;
	int		TestDistance;
	int		i;

	if (sv_ce_scale.value > 0)
		DoTest = true;
	else
		DoTest = false;

	VectorClear(TestO1);

	switch (sv.Effects[idx].type)
	{
		case CE_HWSHEEPINATOR:
		case CE_HWXBOWSHOOT:
			VectorCopy(sv.Effects[idx].ef.Xbow.origin[5], TestO1);
			TestDistance = 900;
			break;

		case CE_SCARABCHAIN:
			VectorCopy(sv.Effects[idx].ef.Chain.origin, TestO1);
			TestDistance = 900;
			break;

		case CE_TRIPMINE:
			VectorCopy(sv.Effects[idx].ef.Chain.origin, TestO1);
		//	DoTest = false;
			break;

		//ACHTUNG!!!!!!! setting DoTest to false here does not insure
		//		 that effect will be sent to everyone!
		case CE_TRIPMINESTILL:
			TestDistance = 10000;
			DoTest = false;
			break;

		case CE_RAIN:
			TestDistance = 10000;
			DoTest = false;
			break;

		case CE_FOUNTAIN:
			TestDistance = 10000;
			DoTest = false;
			break;

		case CE_QUAKE:
			VectorCopy(sv.Effects[idx].ef.Quake.origin, TestO1);
			TestDistance = 700;
			break;

		case CE_WHITE_SMOKE:
		case CE_GREEN_SMOKE:
		case CE_GREY_SMOKE:
		case CE_RED_SMOKE:
		case CE_SLOW_WHITE_SMOKE:
		case CE_TELESMK1:
		case CE_TELESMK2:
		case CE_GHOST:
		case CE_REDCLOUD:
		case CE_FLAMESTREAM:
		case CE_ACID_MUZZFL:
		case CE_FLAMEWALL:
		case CE_FLAMEWALL2:
		case CE_ONFIRE:
		case CE_RIPPLE:
			VectorCopy(sv.Effects[idx].ef.Smoke.origin, TestO1);
			TestDistance = 250;
			break;

		case CE_SM_WHITE_FLASH:
		case CE_YELLOWRED_FLASH:
		case CE_BLUESPARK:
		case CE_YELLOWSPARK:
		case CE_SM_CIRCLE_EXP:
		case CE_BG_CIRCLE_EXP:
		case CE_SM_EXPLOSION:
		case CE_SM_EXPLOSION2:
		case CE_LG_EXPLOSION:
		case CE_FLOOR_EXPLOSION:
		case CE_BLUE_EXPLOSION:
		case CE_REDSPARK:
		case CE_GREENSPARK:
		case CE_ICEHIT:
		case CE_MEDUSA_HIT:
		case CE_MEZZO_REFLECT:
		case CE_FLOOR_EXPLOSION2:
		case CE_XBOW_EXPLOSION:
		case CE_NEW_EXPLOSION:
		case CE_MAGIC_MISSILE_EXPLOSION:
		case CE_BONE_EXPLOSION:
		case CE_BLDRN_EXPL:
		case CE_ACID_HIT:
		case CE_LBALL_EXPL:
		case CE_FIREWALL_SMALL:
		case CE_FIREWALL_MEDIUM:
		case CE_FIREWALL_LARGE:
		case CE_ACID_SPLAT:
		case CE_ACID_EXPL:
		case CE_FBOOM:
		case CE_BRN_BOUNCE:
		case CE_LSHOCK:
		case CE_BOMB:
		case CE_FLOOR_EXPLOSION3:
			VectorCopy(sv.Effects[idx].ef.Smoke.origin, TestO1);
			TestDistance = 250;
			break;

		case CE_WHITE_FLASH:
		case CE_BLUE_FLASH:
		case CE_SM_BLUE_FLASH:
		case CE_HWSPLITFLASH:
		case CE_RED_FLASH:
			VectorCopy(sv.Effects[idx].ef.Smoke.origin, TestO1);
			TestDistance = 250;
			break;

		case CE_RIDER_DEATH:
			DoTest = false;
			break;

		case CE_TELEPORTERPUFFS:
			VectorCopy(sv.Effects[idx].ef.Teleporter.origin, TestO1);
			TestDistance = 350;
			break;

		case CE_TELEPORTERBODY:
			VectorCopy(sv.Effects[idx].ef.Teleporter.origin, TestO1);
			TestDistance = 350;
			break;

		case CE_DEATHBUBBLES:
			if (sv.Effects[idx].ef.Bubble.owner < 0 || sv.Effects[idx].ef.Bubble.owner >= sv.num_edicts)
			{
				return;
			}
			VectorCopy(PROG_TO_EDICT(sv.Effects[idx].ef.Bubble.owner)->v.origin, TestO1);
			TestDistance = 400;
			break;

		case CE_HWDRILLA:
		case CE_BONESHARD:
		case CE_BONESHRAPNEL:
		case CE_HWBONEBALL:
		case CE_HWRAVENSTAFF:
		case CE_HWRAVENPOWER:
			VectorCopy(sv.Effects[idx].ef.Missile.origin, TestO1);
			TestDistance = 900;
			break;

		case CE_HWMISSILESTAR:
		case CE_HWEIDOLONSTAR:
			VectorCopy(sv.Effects[idx].ef.Missile.origin, TestO1);
			TestDistance = 600;
			break;

		default:
		//	Sys_Error ("%s: bad type", __thisfunc__);
			PR_RunError ("%s: bad type", __thisfunc__);
			break;
	}

	MSG_WriteByte (&sv.multicast, svc_start_effect);
	MSG_WriteByte (&sv.multicast, idx);
	MSG_WriteByte (&sv.multicast, sv.Effects[idx].type);

	switch (sv.Effects[idx].type)
	{
		case CE_RAIN:
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Rain.min_org[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Rain.min_org[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Rain.min_org[2]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Rain.max_org[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Rain.max_org[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Rain.max_org[2]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Rain.e_size[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Rain.e_size[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Rain.e_size[2]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Rain.dir[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Rain.dir[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Rain.dir[2]);
			MSG_WriteShort(&sv.multicast, sv.Effects[idx].ef.Rain.color);
			MSG_WriteShort(&sv.multicast, sv.Effects[idx].ef.Rain.count);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Rain.wait);
			break;

		case CE_FOUNTAIN:
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Fountain.pos[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Fountain.pos[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Fountain.pos[2]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[idx].ef.Fountain.angle[0]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[idx].ef.Fountain.angle[1]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[idx].ef.Fountain.angle[2]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Fountain.movedir[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Fountain.movedir[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Fountain.movedir[2]);
			MSG_WriteShort(&sv.multicast, sv.Effects[idx].ef.Fountain.color);
			MSG_WriteByte(&sv.multicast, sv.Effects[idx].ef.Fountain.cnt);
			break;

		case CE_QUAKE:
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Quake.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Quake.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Quake.origin[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Quake.radius);
			break;

		case CE_WHITE_SMOKE:
		case CE_GREEN_SMOKE:
		case CE_GREY_SMOKE:
		case CE_RED_SMOKE:
		case CE_SLOW_WHITE_SMOKE:
		case CE_TELESMK1:
		case CE_TELESMK2:
		case CE_GHOST:
		case CE_REDCLOUD:
		case CE_FLAMESTREAM:
		case CE_ACID_MUZZFL:
		case CE_FLAMEWALL:
		case CE_FLAMEWALL2:
		case CE_ONFIRE:
		case CE_RIPPLE:
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Smoke.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Smoke.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Smoke.origin[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Smoke.velocity[0]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Smoke.velocity[1]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Smoke.velocity[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Smoke.framelength);
			break;

		case CE_SM_WHITE_FLASH:
		case CE_YELLOWRED_FLASH:
		case CE_BLUESPARK:
		case CE_YELLOWSPARK:
		case CE_SM_CIRCLE_EXP:
		case CE_BG_CIRCLE_EXP:
		case CE_SM_EXPLOSION:
		case CE_SM_EXPLOSION2:
		case CE_LG_EXPLOSION:
		case CE_FLOOR_EXPLOSION:
		case CE_BLUE_EXPLOSION:
		case CE_REDSPARK:
		case CE_GREENSPARK:
		case CE_ICEHIT:
		case CE_MEDUSA_HIT:
		case CE_MEZZO_REFLECT:
		case CE_FLOOR_EXPLOSION2:
		case CE_XBOW_EXPLOSION:
		case CE_NEW_EXPLOSION:
		case CE_MAGIC_MISSILE_EXPLOSION:
		case CE_BONE_EXPLOSION:
		case CE_BLDRN_EXPL:
		case CE_ACID_HIT:
		case CE_ACID_SPLAT:
		case CE_ACID_EXPL:
		case CE_LBALL_EXPL:
		case CE_FIREWALL_SMALL:
		case CE_FIREWALL_MEDIUM:
		case CE_FIREWALL_LARGE:
		case CE_FBOOM:
		case CE_BOMB:
		case CE_BRN_BOUNCE:
		case CE_LSHOCK:
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Smoke.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Smoke.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Smoke.origin[2]);
			break;

		case CE_WHITE_FLASH:
		case CE_BLUE_FLASH:
		case CE_SM_BLUE_FLASH:
		case CE_HWSPLITFLASH:
		case CE_RED_FLASH:
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Smoke.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Smoke.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Smoke.origin[2]);
			break;

		case CE_RIDER_DEATH:
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.RD.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.RD.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.RD.origin[2]);
			break;

		case CE_TELEPORTERPUFFS:
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Teleporter.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Teleporter.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Teleporter.origin[2]);
			break;

		case CE_TELEPORTERBODY:
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Teleporter.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Teleporter.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Teleporter.origin[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Teleporter.velocity[0][0]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Teleporter.velocity[0][1]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Teleporter.velocity[0][2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Teleporter.skinnum);
			break;

		case CE_BONESHRAPNEL:
		case CE_HWBONEBALL:
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Missile.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Missile.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Missile.origin[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Missile.velocity[0]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Missile.velocity[1]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Missile.velocity[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Missile.angle[0]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Missile.angle[1]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Missile.angle[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Missile.avelocity[0]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Missile.avelocity[1]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Missile.avelocity[2]);
			break;

		case CE_BONESHARD:
		case CE_HWRAVENSTAFF:
		case CE_HWMISSILESTAR:
		case CE_HWEIDOLONSTAR:
		case CE_HWRAVENPOWER:
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Missile.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Missile.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Missile.origin[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Missile.velocity[0]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Missile.velocity[1]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Missile.velocity[2]);
			break;

		case CE_HWDRILLA:
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Missile.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Missile.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Missile.origin[2]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[idx].ef.Missile.angle[0]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[idx].ef.Missile.angle[1]);
			MSG_WriteShort(&sv.multicast, sv.Effects[idx].ef.Missile.speed);
			break;

		case CE_DEATHBUBBLES:
			MSG_WriteShort(&sv.multicast, sv.Effects[idx].ef.Bubble.owner);
			MSG_WriteByte(&sv.multicast, sv.Effects[idx].ef.Bubble.offset[0]);
			MSG_WriteByte(&sv.multicast, sv.Effects[idx].ef.Bubble.offset[1]);
			MSG_WriteByte(&sv.multicast, sv.Effects[idx].ef.Bubble.offset[2]);
			MSG_WriteByte(&sv.multicast, sv.Effects[idx].ef.Bubble.count);
			break;

		case CE_SCARABCHAIN:
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Chain.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Chain.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Chain.origin[2]);
			MSG_WriteShort(&sv.multicast, sv.Effects[idx].ef.Chain.owner + sv.Effects[idx].ef.Chain.material);
			MSG_WriteByte(&sv.multicast, sv.Effects[idx].ef.Chain.tag);
			break;

		case CE_TRIPMINESTILL:
		case CE_TRIPMINE:
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Chain.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Chain.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Chain.origin[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Chain.velocity[0]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Chain.velocity[1]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[idx].ef.Chain.velocity[2]);
			break;

		case CE_HWSHEEPINATOR:
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Xbow.origin[5][0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Xbow.origin[5][1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Xbow.origin[5][2]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[idx].ef.Xbow.angle[0]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[idx].ef.Xbow.angle[1]);
			//now send the guys that have turned
			MSG_WriteByte(&sv.multicast, sv.Effects[idx].ef.Xbow.turnedbolts);
			MSG_WriteByte(&sv.multicast, sv.Effects[idx].ef.Xbow.activebolts);
			for (i = 0 ; i < 5 ; i++)
			{
				if ((1<<i)&sv.Effects[idx].ef.Xbow.turnedbolts)
				{
					MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Xbow.origin[i][0]);
					MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Xbow.origin[i][1]);
					MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Xbow.origin[i][2]);
					MSG_WriteAngle(&sv.multicast, sv.Effects[idx].ef.Xbow.vel[i][0]);
					MSG_WriteAngle(&sv.multicast, sv.Effects[idx].ef.Xbow.vel[i][1]);
				}
			}
			break;

		case CE_HWXBOWSHOOT:
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Xbow.origin[5][0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Xbow.origin[5][1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Xbow.origin[5][2]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[idx].ef.Xbow.angle[0]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[idx].ef.Xbow.angle[1]);
		//	MSG_WriteFloat(&sv.multicast, sv.Effects[idx].Xbow.angle[2]);
			MSG_WriteByte(&sv.multicast, sv.Effects[idx].ef.Xbow.bolts);
			MSG_WriteByte(&sv.multicast, sv.Effects[idx].ef.Xbow.randseed);
			//now send the guys that have turned
			MSG_WriteByte(&sv.multicast, sv.Effects[idx].ef.Xbow.turnedbolts);
			MSG_WriteByte(&sv.multicast, sv.Effects[idx].ef.Xbow.activebolts);
			for (i = 0 ; i < 5 ; i++)
			{
				if ( (1<<i) & sv.Effects[idx].ef.Xbow.turnedbolts )
				{
					MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Xbow.origin[i][0]);
					MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Xbow.origin[i][1]);
					MSG_WriteCoord(&sv.multicast, sv.Effects[idx].ef.Xbow.origin[i][2]);
					MSG_WriteAngle(&sv.multicast, sv.Effects[idx].ef.Xbow.vel[i][0]);
					MSG_WriteAngle(&sv.multicast, sv.Effects[idx].ef.Xbow.vel[i][1]);
				}
			}
			break;

		default:
		//	Sys_Error ("%s: bad type", __thisfunc__);
			PR_RunError ("%s: bad type", __thisfunc__);
			break;
	}

	if (sb)
	{
		SZ_Write (sb, sv.multicast.data, sv.multicast.cursize);
		SZ_Clear (&sv.multicast);
	}
	else
	{
		if (DoTest)
		{
			SV_Multicast (TestO1, MULTICAST_PVS_R);
		}
		else
		{
			SV_Multicast (TestO1, MULTICAST_ALL_R);
		}
		sv.Effects[idx].client_list = clients_multicast;
	}
}