|  | @@ -0,0 +1,2101 @@
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | +GNU General Public License version 3 notice
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Copyright (C) 2012 Mihawk <luiz@netdome.biz>. All rights reserved.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +This program is free software: you can redistribute it and/or modify
 | 
	
		
			
				|  |  | +it under the terms of the GNU General Public License as published by
 | 
	
		
			
				|  |  | +the Free Software Foundation, either version 3 of the License, or
 | 
	
		
			
				|  |  | +(at your option) any later version.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +This program is distributed in the hope that it will be useful,
 | 
	
		
			
				|  |  | +but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
	
		
			
				|  |  | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
	
		
			
				|  |  | +GNU General Public License for more details.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +You should have received a copy of the GNU General Public License
 | 
	
		
			
				|  |  | +along with this program.  If not, see < http://www.gnu.org/licenses/ >.
 | 
	
		
			
				|  |  | +*/
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include "QWClient.h"
 | 
	
		
			
				|  |  | +#include "QWClientPrivate.h"
 | 
	
		
			
				|  |  | +#include "QWPack.h"
 | 
	
		
			
				|  |  | +#include "QWTables.h"
 | 
	
		
			
				|  |  | +#include <QUdpSocket>
 | 
	
		
			
				|  |  | +#include <QTime>
 | 
	
		
			
				|  |  | +#include <QBuffer>
 | 
	
		
			
				|  |  | +#include <QFile>
 | 
	
		
			
				|  |  | +#include <QDir>
 | 
	
		
			
				|  |  | +#include <QRegExp>
 | 
	
		
			
				|  |  | +#include <QStringList>
 | 
	
		
			
				|  |  | +#include <QFileInfoList>
 | 
	
		
			
				|  |  | +#include <QHostInfo>
 | 
	
		
			
				|  |  | +#include <QCryptographicHash>
 | 
	
		
			
				|  |  | +#include <QCoreApplication>
 | 
	
		
			
				|  |  | +#include <QtEndian>
 | 
	
		
			
				|  |  | +#include <QDebug>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const char* QWClientPrivate::ClientName		= "libqwclient";
 | 
	
		
			
				|  |  | +const char* QWClientPrivate::ClientVersion = "0.1";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +QWClientPrivate::QWClientPrivate(QWClient* client):
 | 
	
		
			
				|  |  | +  myClient(client),
 | 
	
		
			
				|  |  | +  mySocket(new QUdpSocket),
 | 
	
		
			
				|  |  | +  myTime(new QTime),
 | 
	
		
			
				|  |  | +  myLastServerReplyTime(new QTime),
 | 
	
		
			
				|  |  | +  myDownload(new QFile),
 | 
	
		
			
				|  |  | +  myClientName(ClientName),
 | 
	
		
			
				|  |  | +  myClientVersion(ClientVersion),
 | 
	
		
			
				|  |  | +  myState(QWClient::DisconnectedState),
 | 
	
		
			
				|  |  | +  myGameDir("qw"),
 | 
	
		
			
				|  |  | +  myQuakeDir(QCoreApplication::applicationDirPath()),
 | 
	
		
			
				|  |  | +  myPing(666),
 | 
	
		
			
				|  |  | +  myRate(3000),
 | 
	
		
			
				|  |  | +  myTopColor(0),
 | 
	
		
			
				|  |  | +  myBottomColor(0),
 | 
	
		
			
				|  |  | +  myName(ClientName),
 | 
	
		
			
				|  |  | +  mySpectatorFlag(true),
 | 
	
		
			
				|  |  | +  myTeam("lqwc")
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	/* Setup IO streams */
 | 
	
		
			
				|  |  | +	myInBuffer.setBuffer(&myInData);
 | 
	
		
			
				|  |  | +	myInStream.setDevice(&myInBuffer);
 | 
	
		
			
				|  |  | +	myInStream.setByteOrder(QDataStream::LittleEndian);
 | 
	
		
			
				|  |  | +	myInBuffer.open(QIODevice::ReadOnly);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myUnreliableOutBuffer.setBuffer(&myUnreliableOutData);
 | 
	
		
			
				|  |  | +	myUnreliableOutStream.setDevice(&myUnreliableOutBuffer);
 | 
	
		
			
				|  |  | +	myUnreliableOutBuffer.open(QIODevice::WriteOnly);
 | 
	
		
			
				|  |  | +	myUnreliableOutStream.setByteOrder(QDataStream::LittleEndian);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myReliableOutBuffer.setBuffer(&myReliableOutData);
 | 
	
		
			
				|  |  | +	myReliableOutStream.setDevice(&myReliableOutBuffer);
 | 
	
		
			
				|  |  | +	myReliableOutBuffer.open(QIODevice::WriteOnly);
 | 
	
		
			
				|  |  | +	myReliableOutStream.setByteOrder(QDataStream::LittleEndian);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myOutBuffer.setBuffer(&myOutData);
 | 
	
		
			
				|  |  | +	myOutStream.setDevice(&myOutBuffer);
 | 
	
		
			
				|  |  | +	myOutBuffer.open(QIODevice::ReadWrite);
 | 
	
		
			
				|  |  | +	myOutStream.setByteOrder(QDataStream::LittleEndian);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	reloadPackFiles();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::setPing(quint16 ping)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	myPing = qBound<quint16>(13, ping, 999);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::reconnect()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  disconnect();
 | 
	
		
			
				|  |  | +	connect(myHost.toString().toAscii().data(), myPort);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::setRate(quint16 rate)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	myRate = qBound<quint16>(2500, rate, 30000);
 | 
	
		
			
				|  |  | +  if(myState != QWClient::ConnectedState)
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	sendCmd("setinfo \"rate\" \"" + QString::number(rate) + "\"");
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::setSpectator(bool spectate)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  if(myState == QWClient::ConnectedState)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		if(spectate && !mySpectatorFlag)
 | 
	
		
			
				|  |  | +			observe();
 | 
	
		
			
				|  |  | +		else if(!spectate && mySpectatorFlag)
 | 
	
		
			
				|  |  | +			join();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	mySpectatorFlag = spectate;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::setPassword(const QString &password)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  myPassword = password;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::setQuakeFolder(const QString &path)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	myQuakeDir = path;
 | 
	
		
			
				|  |  | +	QDir dir(myQuakeDir);
 | 
	
		
			
				|  |  | +	dir.mkpath("id1");
 | 
	
		
			
				|  |  | +	dir.mkpath(myGameDir);
 | 
	
		
			
				|  |  | +	reloadPackFiles();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::join()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	mySpectatorFlag = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if(myState != QWClient::ConnectedState)
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +	writeString(&myReliableOutStream, "setinfo \"spectator\" \"\"");
 | 
	
		
			
				|  |  | +	writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +	writeString(&myReliableOutStream, "join");
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::observe()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	mySpectatorFlag = true;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if(myState != QWClient::ConnectedState)
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +	writeString(&myReliableOutStream, "setinfo \"spectator\" \"" + QString::number(mySpectatorFlag) + "\"");
 | 
	
		
			
				|  |  | +	writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +	writeString(&myReliableOutStream, "observe");
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const QString& QWClientPrivate::gameDir() const
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  return myGameDir;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const QString& QWClientPrivate::quakeDir() const
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  return myQuakeDir;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::setColor(quint8 bottom, quint8 top)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	myBottomColor = bottom;
 | 
	
		
			
				|  |  | +	myTopColor = top;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if(myState != QWClient::ConnectedState)
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +	writeString(&myReliableOutStream, "setinfo \"bottomcolor\" \"" + QString::number(myBottomColor) + "\"");
 | 
	
		
			
				|  |  | +	writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +	writeString(&myReliableOutStream, "setinfo \"topcolor\" \"" + QString::number(myTopColor) + "\"");
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::setName(const char *name)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	myName = QString(name);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if(myState == QWClient::ConnectedState)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +		writeString(&myReliableOutStream, "setinfo \"name\" \"" + myName + "\"");
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::setTeam(const char *team)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	myTeam = QString(team);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if(myState == QWClient::ConnectedState)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +		writeString(&myReliableOutStream, "setinfo \"name\" \"" + myTeam + "\"");
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::sendCmd(const QString &cmd)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  if(myState != QWClient::ConnectedState)
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +	writeString(&myReliableOutStream, cmd);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +QWClientPrivate::~QWClientPrivate()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	delete myTime;
 | 
	
		
			
				|  |  | +	delete myLastServerReplyTime;
 | 
	
		
			
				|  |  | +	delete mySocket;
 | 
	
		
			
				|  |  | +	delete myDownload;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::reloadPackFiles()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	for(int i = 0; i < myPacks.size(); ++i)
 | 
	
		
			
				|  |  | +		delete myPacks.at(i);
 | 
	
		
			
				|  |  | +	myPacks.clear();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	QDir quakeDir(myQuakeDir);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(!quakeDir.isReadable())
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	quakeDir.cd("id1");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	QFileInfoList files = quakeDir.entryInfoList(QStringList("*.pak"), QDir::Files);
 | 
	
		
			
				|  |  | +	QRegExp packRegex("pak[0-9]+\\.pak", Qt::CaseInsensitive);
 | 
	
		
			
				|  |  | +	for(int i = 0; i < files.size(); ++i)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		if(packRegex.indexIn(files.at(i).fileName()) != -1)
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			QWPack* pack = new QWPack();
 | 
	
		
			
				|  |  | +			if(!pack->load(files.at(i).absoluteFilePath()))
 | 
	
		
			
				|  |  | +			{
 | 
	
		
			
				|  |  | +				delete pack;
 | 
	
		
			
				|  |  | +				continue;
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +			myPacks.push_back(pack);
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	files.clear();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	QDir gameDir(myQuakeDir + "/" + myGameDir);
 | 
	
		
			
				|  |  | +	if(!gameDir.isReadable())
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	files = gameDir.entryInfoList(QStringList("*.pak"), QDir::Files);
 | 
	
		
			
				|  |  | +	for(int i = 0; i < files.size(); ++i)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		if(packRegex.indexIn(files.at(i).fileName()) != -1)
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			QWPack* pack = new QWPack();
 | 
	
		
			
				|  |  | +			if(!pack->load(files.at(i).absoluteFilePath()))
 | 
	
		
			
				|  |  | +			{
 | 
	
		
			
				|  |  | +				delete pack;
 | 
	
		
			
				|  |  | +				continue;
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +			myPacks.push_back(pack);
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::run()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	/* Read and parse packets sent by the server */
 | 
	
		
			
				|  |  | +	readPackets();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Send something to the server to keep the connection alive */
 | 
	
		
			
				|  |  | +	sendToServer();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::sendToServer(bool dontWait)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	/* Check for resend */
 | 
	
		
			
				|  |  | +  if(myState == QWClient::ConnectingState)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		if(myTime->elapsed() >= 5000)
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			sendConnectionless("getchallenge\n");
 | 
	
		
			
				|  |  | +			myClient->onChallenge();
 | 
	
		
			
				|  |  | +			myTime->restart();
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Go full speed when connecting or downloading a new map */
 | 
	
		
			
				|  |  | +  if(!dontWait && (myState != QWClient::ConnectedState || myDownload->isOpen() ? 12 : myPing) > myTime->elapsed())
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  sendMovement(); //send some movement every frame
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	bool sendReliable = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(myIncomingAck > myLastRealiableSeq && myIncomingAckReliableFlag != myOutgoingSeqReliableFlag)
 | 
	
		
			
				|  |  | +		sendReliable = true;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(!myReliableData.size() && myReliableOutData.size())
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		myReliableData = myReliableOutData;
 | 
	
		
			
				|  |  | +		myOutgoingSeqReliableFlag ^= 1;
 | 
	
		
			
				|  |  | +		sendReliable = true;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		myReliableOutData.clear();
 | 
	
		
			
				|  |  | +		myReliableOutStream.device()->seek(0);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Write packet header */
 | 
	
		
			
				|  |  | +	myOutData.clear();
 | 
	
		
			
				|  |  | +	myOutStream.device()->seek(0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myOutStream << (myOutgoingSeq | (sendReliable << 31));
 | 
	
		
			
				|  |  | +	myOutStream << (myIncomingSeq | (myIncomingSeqReliableFlag << 31));
 | 
	
		
			
				|  |  | +	myOutStream << myQPort;
 | 
	
		
			
				|  |  | +	myOutgoingSeq++;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Write reliable buffer first */
 | 
	
		
			
				|  |  | +	if(sendReliable)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		myOutData.append(myReliableData);
 | 
	
		
			
				|  |  | +		myLastRealiableSeq = myOutgoingSeq;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Unreliable part afterwards */
 | 
	
		
			
				|  |  | +	if(myOutData.size() + myUnreliableOutData.size() < MAX_MSGLEN && myUnreliableOutData.size())
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		myOutData.append(myUnreliableOutData);
 | 
	
		
			
				|  |  | +		myUnreliableOutData.clear();
 | 
	
		
			
				|  |  | +		myUnreliableOutStream.device()->seek(0);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Finally send the packet */
 | 
	
		
			
				|  |  | +  mySocket->write(myOutData);
 | 
	
		
			
				|  |  | +  mySocket->waitForBytesWritten();
 | 
	
		
			
				|  |  | +	myOutData.clear();
 | 
	
		
			
				|  |  | +	myOutStream.device()->seek(0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myTime->restart();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::readPackets()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if(!mySocket->isOpen())
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(!mySocket->hasPendingDatagrams())
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		if(myLastServerReplyTime->secsTo(QTime::currentTime()) >= 30)
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			myClient->onError("Client Timed Out.");
 | 
	
		
			
				|  |  | +      disconnect();
 | 
	
		
			
				|  |  | +			return;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	*myLastServerReplyTime = QTime::currentTime();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myInData.resize(mySocket->pendingDatagramSize());
 | 
	
		
			
				|  |  | +//	myInData = mySocket->readAll();
 | 
	
		
			
				|  |  | +	mySocket->readDatagram(myInData.data(), mySocket->pendingDatagramSize());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myInStream.device()->seek(0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	quint32 seq;
 | 
	
		
			
				|  |  | +	myInStream >> seq;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(seq == 0xffffffff)
 | 
	
		
			
				|  |  | +		parseConnectionless();
 | 
	
		
			
				|  |  | +	else
 | 
	
		
			
				|  |  | +		parseServerMessage();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseConnectionless()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	quint8 c;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	c = readByte();
 | 
	
		
			
				|  |  | +	switch(c)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		case S2C_CHALLENGE:
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			QString challenge;
 | 
	
		
			
				|  |  | +			QString connString;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			challenge = readString();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			connString.append("connect " + QString::number(PROTOCOL_VERSION) + " " + QString::number(myQPort) + " " + challenge);
 | 
	
		
			
				|  |  | +			connString.append(" \"\\rate\\" + QString::number(myRate));
 | 
	
		
			
				|  |  | +      if(!myPassword.isEmpty())
 | 
	
		
			
				|  |  | +        connString.append("\\password\\" + myPassword);
 | 
	
		
			
				|  |  | +			connString.append("\\msg\\1\\noaim\\1\\topcolor\\" + QString::number(myTopColor) + "\\bottomcolor\\" + QString::number(myBottomColor) + "\\w_switch\\2\\b_switch\\2\\*client\\" + myClientName);
 | 
	
		
			
				|  |  | +			connString.append(" " + myClientVersion + "\\name\\" + myName + "\\team\\" + myTeam + "\\spectator\\" + (mySpectatorFlag ? "1" : "0") + "\\pmodel\\33168\\emodel\\6967\\*z_ext\\383\"");
 | 
	
		
			
				|  |  | +			myInStream.device()->seek(0);
 | 
	
		
			
				|  |  | +			sendConnectionless(connString.toAscii());
 | 
	
		
			
				|  |  | +			myClient->onConnection();
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		case S2C_CONNECTION:
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +      myState = QWClient::ConnectedState;
 | 
	
		
			
				|  |  | +			writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +			writeString(&myReliableOutStream, "new");
 | 
	
		
			
				|  |  | +			myClient->onConnected();
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		case A2C_PRINT:
 | 
	
		
			
				|  |  | +			myClient->onOOBPrint(readString().toAscii().data());
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		case A2C_CLIENT_COMMAND:
 | 
	
		
			
				|  |  | +			myClient->onOOBCommand(readString().toAscii().data());
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		case A2A_PING:
 | 
	
		
			
				|  |  | +			sendConnectionless(QString(QChar(A2A_ACK)).toAscii());
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		case A2A_ACK:
 | 
	
		
			
				|  |  | +//			qDebug("Ack");
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		case A2A_NACK:
 | 
	
		
			
				|  |  | +//			qDebug("Nack");
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		case A2A_ECHO:
 | 
	
		
			
				|  |  | +			myClient->onOOBEcho(readString().toAscii().data());
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bool QWClientPrivate::fileExists(const QString &filename)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	/* Search on the gamedir first */
 | 
	
		
			
				|  |  | +	if(QFile::exists(myQuakeDir + "/" + myGameDir + "/" + filename))
 | 
	
		
			
				|  |  | +		return true;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Search quake pak files next */
 | 
	
		
			
				|  |  | +	for(int i = 0; i < myPacks.size(); ++i)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		if(myPacks[i]->exists(filename))
 | 
	
		
			
				|  |  | +			return true;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return false;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bool QWClientPrivate::readFile(const QString &filename, char **data, quint64 *len)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	/* Try disk */
 | 
	
		
			
				|  |  | +	QFile file(myQuakeDir + "/" + myGameDir + "/" + filename);
 | 
	
		
			
				|  |  | +  *len = 0;
 | 
	
		
			
				|  |  | +	if(file.open(QIODevice::ReadOnly))
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		*len = file.size();
 | 
	
		
			
				|  |  | +		*data = new char[*len];
 | 
	
		
			
				|  |  | +		file.read(*data, *len);
 | 
	
		
			
				|  |  | +		return true;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Try packs */
 | 
	
		
			
				|  |  | +	for(int i = 0; i < myPacks.size(); ++i)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		QWPack* pack = myPacks.at(i);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if(!pack->exists(filename))
 | 
	
		
			
				|  |  | +			continue;
 | 
	
		
			
				|  |  | +		pack->read(filename, data, len);
 | 
	
		
			
				|  |  | +		return true;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return false;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//int	bitCounts[32];	/// just for protocol profiling
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseDelta(entityState_t *from, entityState_t *to, int bits)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int			i;
 | 
	
		
			
				|  |  | +	int			morebits;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	// set everything to the state we are delta'ing from
 | 
	
		
			
				|  |  | +	*to = *from;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	to->number = bits & 511;
 | 
	
		
			
				|  |  | +	bits &= ~511;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(bits & U_MOREBITS)
 | 
	
		
			
				|  |  | +	{	// read in the low order bits
 | 
	
		
			
				|  |  | +		i = readByte();
 | 
	
		
			
				|  |  | +		bits |= i;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(bits & U_FTE_EVENMORE && myFTEProtocolExtensions) {
 | 
	
		
			
				|  |  | +		morebits = readByte();
 | 
	
		
			
				|  |  | +		if (morebits & U_FTE_YETMORE)
 | 
	
		
			
				|  |  | +			morebits |= readByte() << 8;
 | 
	
		
			
				|  |  | +	} else {
 | 
	
		
			
				|  |  | +		morebits = 0;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +//	// count the bits for net profiling
 | 
	
		
			
				|  |  | +//	for (i=0 ; i<16 ; i++)
 | 
	
		
			
				|  |  | +//		if (bits&(1<<i))
 | 
	
		
			
				|  |  | +//			bitCounts[i]++;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	to->flags = bits;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(bits & U_MODEL)
 | 
	
		
			
				|  |  | +		to->modelindex = readByte();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(bits & U_FRAME)
 | 
	
		
			
				|  |  | +		to->frame = readByte();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(bits & U_COLORMAP)
 | 
	
		
			
				|  |  | +		to->colormap = readByte();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(bits & U_SKIN)
 | 
	
		
			
				|  |  | +		to->skinnum = readByte();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(bits & U_EFFECTS)
 | 
	
		
			
				|  |  | +		to->effects = readByte();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(bits & U_ORIGIN1)
 | 
	
		
			
				|  |  | +		to->origin[0] = readCoord();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(bits & U_ANGLE1)
 | 
	
		
			
				|  |  | +		to->angles[0] = readAngle();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(bits & U_ORIGIN2)
 | 
	
		
			
				|  |  | +		to->origin[1] = readCoord();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(bits & U_ANGLE2)
 | 
	
		
			
				|  |  | +		to->angles[1] = readAngle();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(bits & U_ORIGIN3)
 | 
	
		
			
				|  |  | +		to->origin[2] = readCoord();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(bits & U_ANGLE3)
 | 
	
		
			
				|  |  | +		to->angles[2] = readAngle();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(bits & U_SOLID)
 | 
	
		
			
				|  |  | +	{}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(morebits & U_FTE_TRANS && myFTEProtocolExtensions & FTE_PEXT_TRANS)
 | 
	
		
			
				|  |  | +		readByte();
 | 
	
		
			
				|  |  | +	if(morebits & U_FTE_ENTITYDBL)
 | 
	
		
			
				|  |  | +	{}
 | 
	
		
			
				|  |  | +	if(morebits & U_FTE_ENTITYDBL2)
 | 
	
		
			
				|  |  | +	{}
 | 
	
		
			
				|  |  | +	if(morebits & U_FTE_MODELDBL)
 | 
	
		
			
				|  |  | +	{}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//========================================================================
 | 
	
		
			
				|  |  | +// Parser
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +quint32 QWClientPrivate::littleLong(quint32 l)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if(QSysInfo::ByteOrder == QSysInfo::LittleEndian)
 | 
	
		
			
				|  |  | +		return qToLittleEndian<quint32>(l);
 | 
	
		
			
				|  |  | +	else
 | 
	
		
			
				|  |  | +		return l;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +quint16 QWClientPrivate::littleShort(quint16 s)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if(QSysInfo::ByteOrder == QSysInfo::LittleEndian)
 | 
	
		
			
				|  |  | +		return qToLittleEndian<quint16>(s);
 | 
	
		
			
				|  |  | +	else
 | 
	
		
			
				|  |  | +		return s;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +float QWClientPrivate::littleFloat(float f)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if(QSysInfo::ByteOrder == QSysInfo::LittleEndian)
 | 
	
		
			
				|  |  | +		return qToLittleEndian<float>(f);
 | 
	
		
			
				|  |  | +	else
 | 
	
		
			
				|  |  | +		return f;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bool QWClientPrivate::checkForBadRead(quint8 typeSize)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if(myInStream.device()->pos()+typeSize > myInStream.device()->size())
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		myBadReadFlag = true;
 | 
	
		
			
				|  |  | +		return true;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	return false;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +float QWClientPrivate::readAngle()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if(checkForBadRead(1))
 | 
	
		
			
				|  |  | +		return -1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	quint8 angle;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myInStream >> angle;
 | 
	
		
			
				|  |  | +	return angle * (360.0f/256);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +float QWClientPrivate::readAngle16()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if(checkForBadRead(2))
 | 
	
		
			
				|  |  | +		return -1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	quint16 angle;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myInStream >> angle;
 | 
	
		
			
				|  |  | +	return angle * (360.0f/65536);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +float QWClientPrivate::readCoord()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if(checkForBadRead(2))
 | 
	
		
			
				|  |  | +		return -1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	quint16 coord;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myInStream >> coord;
 | 
	
		
			
				|  |  | +	return coord * (1.0f/8);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +quint8 QWClientPrivate::readByte()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if(checkForBadRead(1))
 | 
	
		
			
				|  |  | +		return 0xff;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	quint8 byte;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myInStream >> byte;
 | 
	
		
			
				|  |  | +	return byte;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +float QWClientPrivate::readFloat()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	union
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		quint8	b[4];
 | 
	
		
			
				|  |  | +		int			l;
 | 
	
		
			
				|  |  | +		float		f;
 | 
	
		
			
				|  |  | +	} d;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	d.b[0] = readByte();
 | 
	
		
			
				|  |  | +	d.b[1] = readByte();
 | 
	
		
			
				|  |  | +	d.b[2] = readByte();
 | 
	
		
			
				|  |  | +	d.b[3] = readByte();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return littleFloat(d.f);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const QString QWClientPrivate::readString()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	QString str;
 | 
	
		
			
				|  |  | +	quint8 c;
 | 
	
		
			
				|  |  | +	c = readByte();
 | 
	
		
			
				|  |  | +	while(c && c != 255) //bad read or null terminator
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		str.append(c);
 | 
	
		
			
				|  |  | +		c = readByte();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	return str;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +qint32 QWClientPrivate::readLong()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if(checkForBadRead(4))
 | 
	
		
			
				|  |  | +		return -1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	quint32 l;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myInStream >> l;
 | 
	
		
			
				|  |  | +	return l;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +qint16 QWClientPrivate::readShort()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if(checkForBadRead(2))
 | 
	
		
			
				|  |  | +		return -1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	qint16 s;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myInStream >> s;
 | 
	
		
			
				|  |  | +	return s;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//========================================================================
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcNoop()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcDisconnect()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	mySocket->close();
 | 
	
		
			
				|  |  | +  myState = QWClient::DisconnectedState;
 | 
	
		
			
				|  |  | +	myClient->onDisconnect();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcPrint()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	quint8	level = readByte();
 | 
	
		
			
				|  |  | +	QString msg		= readString();
 | 
	
		
			
				|  |  | +	myClient->onPrint(level, msg.toAscii().data());
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcCenterPrint()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	myClient->onCenterPrint(readString().toAscii().data());
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcStuffText()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	QStringList commands = readString().split("\n");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for(int i = 0; i < commands.size(); ++i)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		QString cmd = commands.at(i);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if(cmd == "reconnect" || cmd == "cmd new")
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +			writeString(&myReliableOutStream, "new");
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		else if(cmd == "cmd pext")
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +			writeString(&myReliableOutStream, "pext 0x00000000 0x00000000 0x00000000");
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		else if(cmd.startsWith("cmd spawn"))
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +			writeString(&myReliableOutStream, cmd.section(' ', 1));
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		else if(cmd.startsWith("cmd prespawn"))
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +			writeString(&myReliableOutStream, cmd.section(' ', 1));
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		else if(cmd == "skins")
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +			writeString(&myReliableOutStream, QString("begin " + QString::number(myServerCount)));
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		else if(cmd.startsWith("packet"))
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			QRegExp regex("\"(.+)\"");
 | 
	
		
			
				|  |  | +			int pos = regex.indexIn(cmd);
 | 
	
		
			
				|  |  | +			if(pos != -1)
 | 
	
		
			
				|  |  | +				sendConnectionless(regex.capturedTexts().at(1).toAscii());
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +    myClient->onStuffedCmd(cmd.toAscii().data());
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcDamage()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int armor = readByte();
 | 
	
		
			
				|  |  | +	int blood = readByte();
 | 
	
		
			
				|  |  | +	myClient->onDamage(armor, blood);
 | 
	
		
			
				|  |  | +	readCoord();
 | 
	
		
			
				|  |  | +	readCoord();
 | 
	
		
			
				|  |  | +	readCoord();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcServerData()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	while (1) {
 | 
	
		
			
				|  |  | +		myProtocolVersion = readLong();
 | 
	
		
			
				|  |  | +		if(myProtocolVersion == PROTOCOL_VERSION_FTE || myProtocolVersion == PROTOCOL_VERSION_FTE2)
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			myFTEProtocolExtensions = readLong();
 | 
	
		
			
				|  |  | +			continue;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		if(myProtocolVersion == PROTOCOL_VERSION)
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myServerCount = readLong();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myGameDir = readString();
 | 
	
		
			
				|  |  | +	QDir quakeDir(myQuakeDir);
 | 
	
		
			
				|  |  | +	if(!quakeDir.cd(myGameDir))
 | 
	
		
			
				|  |  | +		quakeDir.mkdir(myGameDir);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	quint8 playerNum = readByte();		//playernum
 | 
	
		
			
				|  |  | +	if(playerNum & 0x80)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		mySpectatorFlag = true;
 | 
	
		
			
				|  |  | +		playerNum &= ~0x80;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	else
 | 
	
		
			
				|  |  | +		mySpectatorFlag = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	QString lvlName = readString();
 | 
	
		
			
				|  |  | +	float a = readFloat();
 | 
	
		
			
				|  |  | +	float b = readFloat();
 | 
	
		
			
				|  |  | +	float c = readFloat();
 | 
	
		
			
				|  |  | +	float d = readFloat();
 | 
	
		
			
				|  |  | +	float e = readFloat();
 | 
	
		
			
				|  |  | +	float f = readFloat();
 | 
	
		
			
				|  |  | +	float g = readFloat();
 | 
	
		
			
				|  |  | +	float h = readFloat();
 | 
	
		
			
				|  |  | +	float i = readFloat();
 | 
	
		
			
				|  |  | +	float j = readFloat();
 | 
	
		
			
				|  |  | +	myClient->onLevelChanged(
 | 
	
		
			
				|  |  | +		playerNum,
 | 
	
		
			
				|  |  | +		lvlName.toAscii().data(),
 | 
	
		
			
				|  |  | +		a,b,c,d,e,f,g,h,i,j
 | 
	
		
			
				|  |  | +	);
 | 
	
		
			
				|  |  | +	writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +	writeString(&myReliableOutStream, QString("soundlist " + QString::number(myServerCount) + " 0"));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if(myDownload->isOpen())
 | 
	
		
			
				|  |  | +    myDownload->close();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcSetAngle()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	readAngle();
 | 
	
		
			
				|  |  | +	readAngle();
 | 
	
		
			
				|  |  | +	readAngle();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcLightStyle()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	readString();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcSound()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	quint16 channel;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	channel = readShort();
 | 
	
		
			
				|  |  | +	if (channel & SND_VOLUME)
 | 
	
		
			
				|  |  | +		readByte();
 | 
	
		
			
				|  |  | +	if (channel & SND_ATTENUATION)
 | 
	
		
			
				|  |  | +		readByte();
 | 
	
		
			
				|  |  | +	myClient->onPlaySound(readByte());
 | 
	
		
			
				|  |  | +	readCoord();
 | 
	
		
			
				|  |  | +	readCoord();
 | 
	
		
			
				|  |  | +	readCoord();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcStopSound()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	readShort();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcUpdateFrags()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	//printf("svc_updatefrags\n");
 | 
	
		
			
				|  |  | +	quint8 playerNum = readByte();
 | 
	
		
			
				|  |  | +	quint16 frags = readShort();
 | 
	
		
			
				|  |  | +	myClient->onUpdateFrags(playerNum, frags);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcUpdatePing()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	quint8 playerNum = readByte();
 | 
	
		
			
				|  |  | +	quint16 ping = readShort();
 | 
	
		
			
				|  |  | +	myClient->onUpdatePing(playerNum, ping);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcUpdatePL()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	quint8 playerNum = readByte();
 | 
	
		
			
				|  |  | +	quint8 pl = readByte();
 | 
	
		
			
				|  |  | +	myClient->onUpdatePL(playerNum, pl);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcUpdateEnterTime()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	readFloat();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcSpawnBaseLine()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	//printf("svc_spawnbaseline\n");
 | 
	
		
			
				|  |  | +	readShort();
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	for(int i = 0; i < 3; i++)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		readCoord();
 | 
	
		
			
				|  |  | +		readAngle();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcSpawnStatic()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	//printf("svc_spawnstatic\n");
 | 
	
		
			
				|  |  | +	//rawReadShort();
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	for(int i = 0; i < 3; i++)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		readCoord();
 | 
	
		
			
				|  |  | +		readAngle();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcTempEntity()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	//printf("svc_temp_entity\n");
 | 
	
		
			
				|  |  | +	quint8 c = readByte();
 | 
	
		
			
				|  |  | +	bool	 parsed = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	switch(c)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		case TE_LIGHTNING1:
 | 
	
		
			
				|  |  | +		case TE_LIGHTNING2:
 | 
	
		
			
				|  |  | +		case TE_LIGHTNING3:
 | 
	
		
			
				|  |  | +			readShort();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			readCoord();
 | 
	
		
			
				|  |  | +			readCoord();
 | 
	
		
			
				|  |  | +			readCoord();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			readCoord();
 | 
	
		
			
				|  |  | +			readCoord();
 | 
	
		
			
				|  |  | +			readCoord();
 | 
	
		
			
				|  |  | +			parsed = true;
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		case TE_GUNSHOT:
 | 
	
		
			
				|  |  | +			readByte();
 | 
	
		
			
				|  |  | +			readCoord();
 | 
	
		
			
				|  |  | +			readCoord();
 | 
	
		
			
				|  |  | +			readCoord();
 | 
	
		
			
				|  |  | +			parsed = true;
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		case TE_BLOOD:
 | 
	
		
			
				|  |  | +			readByte();
 | 
	
		
			
				|  |  | +			readCoord();
 | 
	
		
			
				|  |  | +			readCoord();
 | 
	
		
			
				|  |  | +			readCoord();
 | 
	
		
			
				|  |  | +			parsed = true;
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		case TE_LIGHTNINGBLOOD:
 | 
	
		
			
				|  |  | +			readCoord();
 | 
	
		
			
				|  |  | +			readCoord();
 | 
	
		
			
				|  |  | +			readCoord();
 | 
	
		
			
				|  |  | +			parsed = true;
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(!parsed)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		readCoord();
 | 
	
		
			
				|  |  | +		readCoord();
 | 
	
		
			
				|  |  | +		readCoord();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcUpdateStat()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcUpdateStatLong()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	//printf("svc_updatestatlong\n");
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	readLong();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcSpawnStaticSound()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	//printf("svc_spawnstaticsound\n");
 | 
	
		
			
				|  |  | +	readCoord();
 | 
	
		
			
				|  |  | +	readCoord();
 | 
	
		
			
				|  |  | +	readCoord();
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcCDTrack()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcIntermission()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	//printf("svc_intermission\n");
 | 
	
		
			
				|  |  | +	readCoord();
 | 
	
		
			
				|  |  | +	readCoord();
 | 
	
		
			
				|  |  | +	readCoord();
 | 
	
		
			
				|  |  | +	readAngle();
 | 
	
		
			
				|  |  | +	readAngle();
 | 
	
		
			
				|  |  | +	readAngle();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcFinale()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	//printf("svc_finale\n");
 | 
	
		
			
				|  |  | +	readString();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcSellScreen()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcSmallKick()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcBigKick()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcMuzzleFlash()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	//printf("svc_muzzleflash\n");
 | 
	
		
			
				|  |  | +	readShort();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcUpdateUserinfo()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	quint8 playerNum = readByte();
 | 
	
		
			
				|  |  | +	quint32 userID = readLong();
 | 
	
		
			
				|  |  | +	QString info = readString();
 | 
	
		
			
				|  |  | +	myClient->onUpdateUserInfo(playerNum, userID, info.toAscii().data());
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcSetinfo()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	//printf("svc_setinfo\n");
 | 
	
		
			
				|  |  | +	QString key, value;
 | 
	
		
			
				|  |  | +	int playerNum = readByte();
 | 
	
		
			
				|  |  | +	key = readString();
 | 
	
		
			
				|  |  | +	value = readString();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	//that must be done
 | 
	
		
			
				|  |  | +	if(key == "rate")
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		myRate = value.toUInt();
 | 
	
		
			
				|  |  | +		sendCmd("setinfo \"rate\" \"" + value + "\"");
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myClient->onSetInfo(playerNum, key.toAscii().data(), value.toAscii().data());
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcServerinfo()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	//printf("svc_serverinfo\n");
 | 
	
		
			
				|  |  | +	QString key, value;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	key = readString();
 | 
	
		
			
				|  |  | +	value = readString();
 | 
	
		
			
				|  |  | +	myClient->onServerInfo(key.toAscii().data(), value.toAscii().data());
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::startDownload(const QString &filename)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if(myDownload->isOpen())
 | 
	
		
			
				|  |  | +		myDownload->close();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +	writeString(&myReliableOutStream, QString("download " + filename));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(filename.contains('/'))
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		QString path = filename.mid(0, (filename.size() - filename.section('/', -1).size() - 1));
 | 
	
		
			
				|  |  | +		QDir quakeDir(myGameDir);
 | 
	
		
			
				|  |  | +		quakeDir.mkpath(myQuakeDir + "/" + myGameDir + "/" + path);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	//generate disk path
 | 
	
		
			
				|  |  | +	int tmpNo = 0;
 | 
	
		
			
				|  |  | +	QString tmpFileName = myQuakeDir + "/" + myGameDir + "/" + filename + QString::number(tmpNo) + ".tmp";
 | 
	
		
			
				|  |  | +	while(myDownload->exists(tmpFileName))
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		tmpNo++;
 | 
	
		
			
				|  |  | +		tmpFileName = myQuakeDir + "/" + myGameDir + "/" + filename + QString::number(tmpNo) + ".tmp";
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myDownload->setFileName(tmpFileName);
 | 
	
		
			
				|  |  | +	myDownload->open(QIODevice::WriteOnly);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myClient->onDownloadStarted(filename.toAscii().data());
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#if 0
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseChunkedDownload()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	QString	svname;
 | 
	
		
			
				|  |  | +	int			totalsize;
 | 
	
		
			
				|  |  | +	int			chunknum;
 | 
	
		
			
				|  |  | +	char		data[DLBLOCKSIZE];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	chunknum = readLong();
 | 
	
		
			
				|  |  | +	if(chunknum < 0)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		totalsize = readLong();
 | 
	
		
			
				|  |  | +		svname    = readString();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if(myDownload->isOpen())
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			// Ensure FILE is closed
 | 
	
		
			
				|  |  | +			if(totalsize != -3) // -3 = dl stopped, so this known issue, do not warn
 | 
	
		
			
				|  |  | +				qDebug("cls.download shouldn't have been set\n");
 | 
	
		
			
				|  |  | +			myDownload->close();
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if(totalsize < 0)
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			switch(totalsize)
 | 
	
		
			
				|  |  | +			{
 | 
	
		
			
				|  |  | +				case -3: qDebug("Server cancel downloading file %s\n", svname.toAscii().data());			break;
 | 
	
		
			
				|  |  | +				case -2: qDebug("Server permissions deny downloading file %s\n", svname.toAscii().data());	break;
 | 
	
		
			
				|  |  | +				default: qDebug("Couldn't find file %s on the server\n", svname.toAscii().data());			break;
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +			myDownload->close();
 | 
	
		
			
				|  |  | +			return;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if(cls.downloadmethod == DL_QWCHUNKS)
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			qDebug("Received second download - \"%s\"\n", svname.toAscii().data());
 | 
	
		
			
				|  |  | +			disconnect();
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if(!myDownload->isOpen())
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			qDebug("Failed to open %s", myDownload->fileName());
 | 
	
		
			
				|  |  | +			return;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		cls.downloadmethod  = DL_QWCHUNKS;
 | 
	
		
			
				|  |  | +		cls.downloadpercent = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		chunked_download_number++;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		downloadsize        = totalsize;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		firstblock    = 0;
 | 
	
		
			
				|  |  | +		receivedbytes = 0;
 | 
	
		
			
				|  |  | +		blockcycle    = -1;	//so it requests 0 first. :)
 | 
	
		
			
				|  |  | +		memset(recievedblock, 0, sizeof(recievedblock));
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	MSG_ReadData(data, DLBLOCKSIZE);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (myDownload->isOpen())
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (cls.downloadmethod != DL_QWCHUNKS)
 | 
	
		
			
				|  |  | +		Host_Error("cls.downloadmethod != DL_QWCHUNKS\n");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(chunknum < firstblock)
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(chunknum - firstblock >= MAXBLOCKS)
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(recievedblock[chunknum&(MAXBLOCKS-1)])
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	receivedbytes += DLBLOCKSIZE;
 | 
	
		
			
				|  |  | +	recievedblock[chunknum&(MAXBLOCKS-1)] = true;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	while(recievedblock[firstblock&(MAXBLOCKS-1)])
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		recievedblock[firstblock&(MAXBLOCKS-1)] = false;
 | 
	
		
			
				|  |  | +		firstblock++;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	fseek(cls.download, chunknum * DLBLOCKSIZE, SEEK_SET);
 | 
	
		
			
				|  |  | +	if (downloadsize - chunknum * DLBLOCKSIZE < DLBLOCKSIZE)	//final block is actually meant to be smaller than we recieve.
 | 
	
		
			
				|  |  | +		fwrite(data, 1, downloadsize - chunknum * DLBLOCKSIZE, cls.download);
 | 
	
		
			
				|  |  | +	else
 | 
	
		
			
				|  |  | +		fwrite(data, 1, DLBLOCKSIZE, cls.download);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	cls.downloadpercent = receivedbytes/(float)downloadsize*100;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	tm = Sys_DoubleTime() - cls.downloadstarttime; // how long we dl-ing
 | 
	
		
			
				|  |  | +	cls.downloadrate = (tm ? receivedbytes / 1024 / tm : 0); // some average dl speed in KB/s
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcDownload()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +//	if(myFTEProtocolExtensions & FTE_PEXT_CHUNKEDDOWNLOADS)
 | 
	
		
			
				|  |  | +//	{
 | 
	
		
			
				|  |  | +//		parseChunkedDownload();
 | 
	
		
			
				|  |  | +//		return;
 | 
	
		
			
				|  |  | +//	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	qint16 size;
 | 
	
		
			
				|  |  | +	quint8 percent;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	size = readShort();
 | 
	
		
			
				|  |  | +	percent = readByte();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(size == -1)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		//file not found
 | 
	
		
			
				|  |  | +		disconnect();
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(!myDownload->isOpen())
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		myInStream.device()->seek(myInStream.device()->pos() + size);
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	char*	temp = new char[size];
 | 
	
		
			
				|  |  | +	myInStream.readRawData(temp, size);
 | 
	
		
			
				|  |  | +	myDownload->write(temp, size);
 | 
	
		
			
				|  |  | +  myDownload->waitForBytesWritten(1000);
 | 
	
		
			
				|  |  | +  delete[] temp;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myClient->onDownloadProgress(percent);
 | 
	
		
			
				|  |  | +	if(percent != 100)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +		writeString(&myReliableOutStream, "nextdl");
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	else
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		myDownload->close();
 | 
	
		
			
				|  |  | +		QString normalFileName = myDownload->fileName().left(myDownload->fileName().length()-5); //strip #.tmp
 | 
	
		
			
				|  |  | +		if(!myDownload->rename(normalFileName))
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			QFile::remove(normalFileName);
 | 
	
		
			
				|  |  | +			myDownload->rename(normalFileName); //now it should succeed
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		myClient->onDownloadFinished();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		preSpawn(mapChecksum(myMapName));
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::readUserDeltaCmd(userCmd_t *from, userCmd_t *move)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	quint8 bits;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	memcpy(move, from, sizeof(*move));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	bits = readByte();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	// read current angles
 | 
	
		
			
				|  |  | +	if(bits & CM_ANGLE1)
 | 
	
		
			
				|  |  | +		move->angles[0] = readAngle16();
 | 
	
		
			
				|  |  | +	if(bits & CM_ANGLE2)
 | 
	
		
			
				|  |  | +		move->angles[1] = readAngle16();
 | 
	
		
			
				|  |  | +	if(bits & CM_ANGLE3)
 | 
	
		
			
				|  |  | +		move->angles[2] = readAngle16();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	// read movement
 | 
	
		
			
				|  |  | +	if(bits & CM_FORWARD)
 | 
	
		
			
				|  |  | +		move->forwardmove = readShort();
 | 
	
		
			
				|  |  | +	if(bits & CM_SIDE)
 | 
	
		
			
				|  |  | +		move->sidemove = readShort();
 | 
	
		
			
				|  |  | +	if(bits & CM_UP)
 | 
	
		
			
				|  |  | +		move->upmove = readShort();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	// read buttons
 | 
	
		
			
				|  |  | +	if(bits & CM_BUTTONS)
 | 
	
		
			
				|  |  | +		move->buttons = readByte();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(bits & CM_IMPULSE)
 | 
	
		
			
				|  |  | +		move->impulse = readByte();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	// read time to run command
 | 
	
		
			
				|  |  | +	move->msec = readByte();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcPlayerinfo()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	quint16		flags;
 | 
	
		
			
				|  |  | +	userCmd_t from, move;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	memset(&from, 0, sizeof(userCmd_t));
 | 
	
		
			
				|  |  | +	memset(&move, 0, sizeof(userCmd_t));
 | 
	
		
			
				|  |  | +	int playerNum = readByte();
 | 
	
		
			
				|  |  | +	flags = readShort();
 | 
	
		
			
				|  |  | +	float x = readCoord();
 | 
	
		
			
				|  |  | +	float y = readCoord();
 | 
	
		
			
				|  |  | +	float z = readCoord();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myClient->onPlayerInfo(playerNum, x, y, z);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(flags & PF_MSEC)
 | 
	
		
			
				|  |  | +		readByte();
 | 
	
		
			
				|  |  | +	if(flags & PF_COMMAND)
 | 
	
		
			
				|  |  | +		readUserDeltaCmd(&from, &move);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for(int i = 0; i < 3; i++)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		if(flags & (PF_VELOCITY1<<i))
 | 
	
		
			
				|  |  | +			readShort();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	if(flags & PF_MODEL)
 | 
	
		
			
				|  |  | +		readByte();
 | 
	
		
			
				|  |  | +	if(flags & PF_SKINNUM)
 | 
	
		
			
				|  |  | +		readByte();
 | 
	
		
			
				|  |  | +	if(flags & PF_EFFECTS)
 | 
	
		
			
				|  |  | +		readByte();
 | 
	
		
			
				|  |  | +	if(flags & PF_WEAPONFRAME)
 | 
	
		
			
				|  |  | +		readByte();
 | 
	
		
			
				|  |  | +	if(flags & PF_TRANS_Z && myFTEProtocolExtensions & FTE_PEXT_TRANS)
 | 
	
		
			
				|  |  | +		readByte();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcNails()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	//printf("svc_nails\n");
 | 
	
		
			
				|  |  | +	quint8 c = readByte();
 | 
	
		
			
				|  |  | +  for(int i = 0; i < c; i++)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		for(int j = 0; j < 6; j++)
 | 
	
		
			
				|  |  | +			readByte();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcChokeCount()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcModellist()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	quint8 i = readByte();
 | 
	
		
			
				|  |  | +	bool	 firstLoop = true;
 | 
	
		
			
				|  |  | +	for(;;)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		QString s = readString();
 | 
	
		
			
				|  |  | +		if(s.isEmpty())
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +		if(!i && firstLoop)
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			myMapName = s;
 | 
	
		
			
				|  |  | +			firstLoop = false;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		myClient->onModelListFile(s.toAscii().data());
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	i = readByte();
 | 
	
		
			
				|  |  | +	if(i)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +		writeString(&myReliableOutStream, QString("modellist " + QString::number(myServerCount) + " " + QString::number(i)));
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if(!fileExists(myMapName) && !QWTables::getOriginalMapChecksum(myMapName))
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		startDownload(myMapName);
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	preSpawn(mapChecksum(myMapName));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcSoundlist()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	quint8 i;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	i = readByte();
 | 
	
		
			
				|  |  | +	for(;;)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		QString s = readString();
 | 
	
		
			
				|  |  | +		if(s.isEmpty())
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +		myClient->onSoundListFile(s.toAscii().data());
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	i = readByte();
 | 
	
		
			
				|  |  | +	if(i)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +		writeString(&myReliableOutStream, QString("soundlist " + QString::number(myServerCount) + " " + QString::number(i)));
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	//continue login
 | 
	
		
			
				|  |  | +	writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +	writeString(&myReliableOutStream, QString("modellist " + QString::number(myServerCount) + " 0"));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcPacketEntities()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int	word;
 | 
	
		
			
				|  |  | +	entityState_t	olde, newe;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	memset(&olde, 0, sizeof(olde));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	while (1)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		word = (unsigned short)readShort();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if (!word)
 | 
	
		
			
				|  |  | +			break;	// done
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		parseDelta(&olde, &newe, word);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcDeltaPacketEntities()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	parseSvcPacketEntities();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcMaxSpeed()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	myClient->onMaxSpeedChange(readFloat());
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcEntGravity()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	myClient->onEntGravityChange(readFloat());
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcSetPause()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	myClient->onSetPause(readByte());
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcNails2()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	quint8 c = readByte();
 | 
	
		
			
				|  |  | +  for(int i = 0; i < c; i++)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		readByte();
 | 
	
		
			
				|  |  | +		for(int j = 0; j < 6; j++)
 | 
	
		
			
				|  |  | +			readByte();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcFTEModellistShort()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	quint16 i = readShort();
 | 
	
		
			
				|  |  | +	bool	  firstLoop = true;
 | 
	
		
			
				|  |  | +	for(;;)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		QString s;
 | 
	
		
			
				|  |  | +		s = readString();
 | 
	
		
			
				|  |  | +		if(s.isEmpty())
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +		if(!i && firstLoop)
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			myMapName = s;
 | 
	
		
			
				|  |  | +			firstLoop = false;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		myClient->onModelListFile(s.toAscii().data());
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	i = readByte();
 | 
	
		
			
				|  |  | +	if(i)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +		writeString(&myReliableOutStream, QString("modellist " + QString::number(myServerCount) + " " + QString::number(i)));
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if(!fileExists(myMapName) && !QWTables::getOriginalMapChecksum(myMapName))
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		startDownload(myMapName);
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	preSpawn(mapChecksum(myMapName));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcFTESpawnBaseline2()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	entityState_t nullst, es;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(!(myFTEProtocolExtensions & FTE_PEXT_SPAWNSTATIC2))
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		myClient->onError("illegible server message\nsvc_fte_spawnbaseline2 without FTE_PEXT_SPAWNSTATIC2\n");
 | 
	
		
			
				|  |  | +		disconnect();
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	memset(&nullst, 0, sizeof (entityState_t));
 | 
	
		
			
				|  |  | +	memset(&es, 0, sizeof (entityState_t));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	parseDelta(&nullst, &es, readShort());
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcQizmoVoice()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	// Read the two-byte header.
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	// 32 bytes of voice data follow
 | 
	
		
			
				|  |  | +	for(int i = 0; i < 32; i++)
 | 
	
		
			
				|  |  | +		readByte();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcFTEVoiceChat()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	readByte();
 | 
	
		
			
				|  |  | +	quint16 i = readShort();
 | 
	
		
			
				|  |  | +	myInStream.device()->seek(myInStream.device()->pos() + i);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcFTESpawnStatic2()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if(myFTEProtocolExtensions & FTE_PEXT_SPAWNSTATIC2)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		entityState_t from, to;
 | 
	
		
			
				|  |  | +		memset(&from, 0, sizeof(entityState_t));
 | 
	
		
			
				|  |  | +		memset(&to, 0, sizeof(entityState_t));
 | 
	
		
			
				|  |  | +    parseDelta(&from, &to, readShort());
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcKilledMonster()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcFoundSecret()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcUpdateName()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  readByte();
 | 
	
		
			
				|  |  | +  readString();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcUpdateColors()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  readByte();
 | 
	
		
			
				|  |  | +  readByte();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcTime()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  readFloat();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcSignonNum()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  readByte();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcParticle()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  for(int i = 0; i < 3; ++i)
 | 
	
		
			
				|  |  | +    readCoord();
 | 
	
		
			
				|  |  | +  for(int i = 0; i < 3; ++i)
 | 
	
		
			
				|  |  | +    readByte();
 | 
	
		
			
				|  |  | +  readByte();
 | 
	
		
			
				|  |  | +  readByte();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcClientData()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  qDebug() << "WHY?!?!?!?!?!?! WHY ME BEING CALLED!";
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseSvcVersion()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::preSpawn(int mapChecksum)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +	writeString(&myReliableOutStream, "setinfo pmodel 33168");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +	writeString(&myReliableOutStream, "setinfo emodel 6967");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	writeByte(&myReliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +	writeString(&myReliableOutStream, QString("prespawn " + QString::number(myServerCount) + " 0 " + QString::number(mapChecksum)));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::parseServerMessage()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	quint32 incomingSeq, incomingAck;
 | 
	
		
			
				|  |  | +	bool		incomingSeqReliable, incomingAckReliable;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myBadReadFlag = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myInStream.device()->seek(0);
 | 
	
		
			
				|  |  | +	myInStream >> incomingSeq;
 | 
	
		
			
				|  |  | +	myInStream >> incomingAck;
 | 
	
		
			
				|  |  | +	incomingSeqReliable = incomingSeq >> 31;
 | 
	
		
			
				|  |  | +	incomingAckReliable = incomingAck >> 31;
 | 
	
		
			
				|  |  | +	incomingSeq &= ~0x80000000;
 | 
	
		
			
				|  |  | +	incomingAck &= ~0x80000000;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(incomingSeq <= myIncomingSeq)
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myPacketLoss = incomingSeq - (myIncomingSeq + 1);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(incomingAckReliable == myOutgoingSeqReliableFlag)
 | 
	
		
			
				|  |  | +		myReliableData.clear();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(incomingSeqReliable)
 | 
	
		
			
				|  |  | +		myIncomingSeqReliableFlag ^= 1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myIncomingSeq = incomingSeq;
 | 
	
		
			
				|  |  | +	myIncomingAck = incomingAck;
 | 
	
		
			
				|  |  | +	myIncomingAckReliableFlag = incomingAckReliable;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	while(!myInStream.atEnd())
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		if(myBadReadFlag)
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			myClient->onError("Bad read from server.");
 | 
	
		
			
				|  |  | +			disconnect();
 | 
	
		
			
				|  |  | +			return;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		quint8 c;
 | 
	
		
			
				|  |  | +		quint8 last = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		myInStream >> c;
 | 
	
		
			
				|  |  | +		if(c == 0xff)
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		switch(c)
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			case svc_bad:
 | 
	
		
			
				|  |  | +				myClient->onError("Bad read from server.");
 | 
	
		
			
				|  |  | +        disconnect();
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_nop:
 | 
	
		
			
				|  |  | +				parseSvcNoop();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_disconnect:
 | 
	
		
			
				|  |  | +				parseSvcDisconnect();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_print:
 | 
	
		
			
				|  |  | +				parseSvcPrint();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_centerprint:
 | 
	
		
			
				|  |  | +				parseSvcCenterPrint();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_stufftext:
 | 
	
		
			
				|  |  | +				parseSvcStuffText();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_damage:
 | 
	
		
			
				|  |  | +				parseSvcDamage();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_serverdata:
 | 
	
		
			
				|  |  | +				parseSvcServerData();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_setangle:
 | 
	
		
			
				|  |  | +				parseSvcSetAngle();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_lightstyle:
 | 
	
		
			
				|  |  | +				parseSvcLightStyle();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_sound:
 | 
	
		
			
				|  |  | +				parseSvcSound();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_stopsound:
 | 
	
		
			
				|  |  | +				parseSvcStopSound();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_updatefrags:
 | 
	
		
			
				|  |  | +				parseSvcUpdateFrags();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_updateping:
 | 
	
		
			
				|  |  | +				parseSvcUpdatePing();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_updatepl:
 | 
	
		
			
				|  |  | +				parseSvcUpdatePL();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_updateentertime:
 | 
	
		
			
				|  |  | +				parseSvcUpdateEnterTime();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_spawnbaseline:
 | 
	
		
			
				|  |  | +				parseSvcSpawnBaseLine();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_spawnstatic:
 | 
	
		
			
				|  |  | +				parseSvcSpawnStatic();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_temp_entity:
 | 
	
		
			
				|  |  | +				parseSvcTempEntity();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_killedmonster:
 | 
	
		
			
				|  |  | +				parseSvcKilledMonster();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_foundsecret:
 | 
	
		
			
				|  |  | +				parseSvcFoundSecret();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_updatestat:
 | 
	
		
			
				|  |  | +				parseSvcUpdateStat();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_updatestatlong:
 | 
	
		
			
				|  |  | +				parseSvcUpdateStatLong();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_spawnstaticsound:
 | 
	
		
			
				|  |  | +				parseSvcSpawnStaticSound();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_cdtrack:
 | 
	
		
			
				|  |  | +				parseSvcCDTrack();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_intermission:
 | 
	
		
			
				|  |  | +				parseSvcIntermission();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_finale:
 | 
	
		
			
				|  |  | +				parseSvcFinale();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_sellscreen:
 | 
	
		
			
				|  |  | +				parseSvcSellScreen();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_smallkick:
 | 
	
		
			
				|  |  | +				parseSvcSmallKick();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_bigkick:
 | 
	
		
			
				|  |  | +				parseSvcBigKick();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_muzzleflash:
 | 
	
		
			
				|  |  | +				parseSvcMuzzleFlash();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_updateuserinfo:
 | 
	
		
			
				|  |  | +				parseSvcUpdateUserinfo();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_setinfo:
 | 
	
		
			
				|  |  | +				parseSvcSetinfo();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_serverinfo:
 | 
	
		
			
				|  |  | +				parseSvcServerinfo();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_download:
 | 
	
		
			
				|  |  | +				parseSvcDownload();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_playerinfo:
 | 
	
		
			
				|  |  | +				parseSvcPlayerinfo();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_nails:
 | 
	
		
			
				|  |  | +				parseSvcNails();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_chokecount:
 | 
	
		
			
				|  |  | +				parseSvcChokeCount();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_modellist:
 | 
	
		
			
				|  |  | +				parseSvcModellist();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_soundlist:
 | 
	
		
			
				|  |  | +				parseSvcSoundlist();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_packetentities:
 | 
	
		
			
				|  |  | +				parseSvcPacketEntities();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_deltapacketentities:
 | 
	
		
			
				|  |  | +				parseSvcDeltaPacketEntities();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_maxspeed:
 | 
	
		
			
				|  |  | +				parseSvcMaxSpeed();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_entgravity:
 | 
	
		
			
				|  |  | +				parseSvcEntGravity();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    case svc_setpause:
 | 
	
		
			
				|  |  | +				parseSvcSetPause();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_nails2:
 | 
	
		
			
				|  |  | +				parseSvcNails2();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_fte_modellistshort:
 | 
	
		
			
				|  |  | +				parseSvcFTEModellistShort();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_fte_spawnbaseline2:
 | 
	
		
			
				|  |  | +				parseSvcFTESpawnBaseline2();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_qizmovoice:
 | 
	
		
			
				|  |  | +				parseSvcQizmoVoice();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_fte_voicechat:
 | 
	
		
			
				|  |  | +				parseSvcFTEVoiceChat();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			case svc_fte_spawnstatic2:
 | 
	
		
			
				|  |  | +				parseSvcFTESpawnStatic2();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +			case nq_svc_time:
 | 
	
		
			
				|  |  | +        parseSvcTime();
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +			case nq_svc_clientdata:
 | 
	
		
			
				|  |  | +        parseSvcClientData();
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +			case nq_svc_version:
 | 
	
		
			
				|  |  | +        parseSvcVersion();
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +			case nq_svc_particle:
 | 
	
		
			
				|  |  | +        parseSvcParticle();
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +			case nq_svc_signonnum:
 | 
	
		
			
				|  |  | +        parseSvcSignonNum();
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +			case nq_svc_updatecolors:
 | 
	
		
			
				|  |  | +        parseSvcUpdateColors();
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +			case nq_svc_updatename:
 | 
	
		
			
				|  |  | +        parseSvcUpdateName();
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +			default:
 | 
	
		
			
				|  |  | +				myClient->onError(QString("Unknown message from server. Last Cmd: [" + QString::number(last) + "] Current Cmd: [" + QString::number(c) + "]").toAscii().data());
 | 
	
		
			
				|  |  | +        disconnect();
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		last = c;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::connect(const char *host, quint16 port)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  if(myState != QWClient::DisconnectedState)
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /* Disabled this, blocking too much, now user is supposed to send the string already resolved. */
 | 
	
		
			
				|  |  | +  //	QHostInfo hi = QHostInfo::fromName(host);
 | 
	
		
			
				|  |  | +  //	if(hi.error() != QHostInfo::NoError)
 | 
	
		
			
				|  |  | +  //	{
 | 
	
		
			
				|  |  | +  //		myClient->onError(hi.errorString().toAscii().data());
 | 
	
		
			
				|  |  | +  //		return;
 | 
	
		
			
				|  |  | +  //	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  myHost.setAddress(host);
 | 
	
		
			
				|  |  | +	myPort = port;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	myIncomingSeq = 0;
 | 
	
		
			
				|  |  | +	myIncomingAck = 0;
 | 
	
		
			
				|  |  | +	myOutgoingSeq = 0;
 | 
	
		
			
				|  |  | +	myLastRealiableSeq = 0;
 | 
	
		
			
				|  |  | +	myIncomingSeqReliableFlag = false;
 | 
	
		
			
				|  |  | +	myIncomingAckReliableFlag = false;
 | 
	
		
			
				|  |  | +	myOutgoingSeqReliableFlag = false;
 | 
	
		
			
				|  |  | +	myPacketLoss = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	mySocket->connectToHost(myHost, myPort);
 | 
	
		
			
				|  |  | +	mySocket->waitForConnected();
 | 
	
		
			
				|  |  | +	sendConnectionless("getchallenge\n");
 | 
	
		
			
				|  |  | +	myClient->onChallenge();
 | 
	
		
			
				|  |  | +	myQPort = qrand() & 0xffff;
 | 
	
		
			
				|  |  | +	myTime->start();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  myState = QWClient::ConnectingState;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	*myLastServerReplyTime = QTime::currentTime();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::setBindHost(const QString &host)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  QHostAddress address(host);
 | 
	
		
			
				|  |  | +  mySocket->bind(address, 0);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::disconnect()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  if(myState == QWClient::ConnectedState)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +    writeByte(&myUnreliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +    writeString(&myUnreliableOutStream, "drop");
 | 
	
		
			
				|  |  | +    sendToServer(true);
 | 
	
		
			
				|  |  | +    writeByte(&myUnreliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +    writeString(&myUnreliableOutStream, "drop");
 | 
	
		
			
				|  |  | +    sendToServer(true);
 | 
	
		
			
				|  |  | +    writeByte(&myUnreliableOutStream, clc_stringcmd);
 | 
	
		
			
				|  |  | +    writeString(&myUnreliableOutStream, "drop");
 | 
	
		
			
				|  |  | +    sendToServer(true);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +  mySocket->close();
 | 
	
		
			
				|  |  | +  myState = QWClient::DisconnectedState;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::sendConnectionless(const QByteArray &data)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	QByteArray d;
 | 
	
		
			
				|  |  | +	d.append("\xff\xff\xff\xff");
 | 
	
		
			
				|  |  | +	d.append(data);
 | 
	
		
			
				|  |  | +	mySocket->write(d);
 | 
	
		
			
				|  |  | +  mySocket->waitForBytesWritten();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::sendMovement()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  myUnreliableOutStream << (quint8)clc_move << (quint8)0x10 << (quint8)myPacketLoss << (quint8)0x00 << (quint8)0x00 << (quint8)0x00 << (quint8)0x22 << (quint8)0x00 << (quint8)0x21;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//=====================================================================
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// "GPL map" support.  If we encounter a map with a known "GPL" CRC,
 | 
	
		
			
				|  |  | +// we fake the CRC so that, on the client side, the CRC of the original
 | 
	
		
			
				|  |  | +// map is transferred to the server, and on the server side, comparison
 | 
	
		
			
				|  |  | +// of clients' CRC is done against the orignal one
 | 
	
		
			
				|  |  | +typedef struct {
 | 
	
		
			
				|  |  | +	const char *mapname;
 | 
	
		
			
				|  |  | +	int original;
 | 
	
		
			
				|  |  | +	int gpl;
 | 
	
		
			
				|  |  | +} csentry_t;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static csentry_t table[] = {
 | 
	
		
			
				|  |  | +	// CRCs for AquaShark's "simpletextures" maps
 | 
	
		
			
				|  |  | +  { "dm1", 0xc5c7dab3, 0x7d37618e },
 | 
	
		
			
				|  |  | +	{ "dm2", 0x65f63634, 0x7b337440 },
 | 
	
		
			
				|  |  | +	{ "dm3", 0x15e20df8, 0x912781ae },
 | 
	
		
			
				|  |  | +	{ "dm4", 0x9c6fe4bf, 0xc374df89 },
 | 
	
		
			
				|  |  | +	{ "dm5", 0xb02d48fd, 0x77ca7ce5 },
 | 
	
		
			
				|  |  | +	{ "dm6", 0x5208da2b, 0x200c8b5d },
 | 
	
		
			
				|  |  | +	{ "end", 0xbbd4b4a5, 0xf89b12ae }, // this is the version with the extra room
 | 
	
		
			
				|  |  | +	{ NULL, 0, 0 },
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +int Com_TranslateMapChecksum (const char *mapname, int checksum)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	csentry_t *p;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//	Com_Printf ("Map checksum (%s): 0x%x\n", mapname, checksum);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for (p = table; p->mapname; p++)
 | 
	
		
			
				|  |  | +		if (!strcmp(p->mapname, mapname)) {
 | 
	
		
			
				|  |  | +			if (checksum == p->gpl)
 | 
	
		
			
				|  |  | +				return p->original;
 | 
	
		
			
				|  |  | +			else
 | 
	
		
			
				|  |  | +				return checksum;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return checksum;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +quint32 QWClientPrivate::mapChecksum(const QString &mapName)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  // Check if this is an original map, if it is we have the checksum table ready
 | 
	
		
			
				|  |  | +  quint32     checksum = 0;
 | 
	
		
			
				|  |  | +  checksum = QWTables::getOriginalMapChecksum(mapName);
 | 
	
		
			
				|  |  | +  if(checksum)
 | 
	
		
			
				|  |  | +    return checksum;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	char*		mapdata;
 | 
	
		
			
				|  |  | +	quint64 maplen;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(!readFile(mapName, &mapdata, &maplen))
 | 
	
		
			
				|  |  | +		return 0;
 | 
	
		
			
				|  |  | +  if(!maplen || !mapdata)
 | 
	
		
			
				|  |  | +    return 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	dheader_t* header;
 | 
	
		
			
				|  |  | +	uchar*		 mod_base;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	header = (dheader_t*)mapdata;
 | 
	
		
			
				|  |  | +	mod_base = (uchar*)mapdata;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for(int i = 0; i < HEADER_LUMPS; ++i)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		if(i == LUMP_ENTITIES || i == LUMP_VISIBILITY || i == LUMP_LEAFS || i == LUMP_NODES)
 | 
	
		
			
				|  |  | +			continue;
 | 
	
		
			
				|  |  | +		checksum ^= blockCheckSum(mod_base + header->lumps[i].fileofs, header->lumps[i].filelen);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	delete[] mapdata;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  QString	cleanMapName;
 | 
	
		
			
				|  |  | +  cleanMapName = mapName.section('/', -1);
 | 
	
		
			
				|  |  | +  cleanMapName.chop(4); //strip .bsp
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return Com_TranslateMapChecksum(cleanMapName.toAscii().data(), checksum);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +unsigned QWClientPrivate::blockCheckSum(void* buffer, int len)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	QByteArray digest = QCryptographicHash::hash(QByteArray((const char*)buffer, len), QCryptographicHash::Md4);
 | 
	
		
			
				|  |  | +	int *d = (int*)digest.data();
 | 
	
		
			
				|  |  | +	return (d[0] ^ d[1] ^ d[2] ^ d[3]);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::writeByte(QDataStream *stream, const quint8 b)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	*stream << b;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::writeLong(QDataStream *stream, const quint32 l)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	*stream << l;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::writeShort(QDataStream *stream, const quint16 s)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	*stream << s;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::writeString(QDataStream *stream, const QString &str)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	stream->writeRawData(str.toAscii().data(), str.size()+1);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//========================================================================
 | 
	
		
			
				|  |  | +// NAME FUN
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +char QWClientPrivate::ourReadableCharsTable[256] = {	'.', '_' , '_' , '_' , '_' , '.' , '_' , '_' , '_' , '_' , '\n' , '_' , '\n' , '>' , '.' , '.',
 | 
	
		
			
				|  |  | +																			 '[', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '_', '_', '_'
 | 
	
		
			
				|  |  | +																			 };
 | 
	
		
			
				|  |  | +bool QWClientPrivate::ourReadableCharsTableInitialized = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::fillReadableCharsTable()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int i;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for(i = 32; i < 127; i++)
 | 
	
		
			
				|  |  | +		ourReadableCharsTable[i] = ourReadableCharsTable[128 + i] = i;
 | 
	
		
			
				|  |  | +	ourReadableCharsTable[127] = ourReadableCharsTable[128 + 127] = '_';
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for(i = 0; i < 32; i++)
 | 
	
		
			
				|  |  | +		ourReadableCharsTable[128 + i] = ourReadableCharsTable[i];
 | 
	
		
			
				|  |  | +	ourReadableCharsTable[128] = '_';
 | 
	
		
			
				|  |  | +	ourReadableCharsTable[10 + 128] = '_';
 | 
	
		
			
				|  |  | +	ourReadableCharsTable[12 + 128] = '_';
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ourReadableCharsTableInitialized = true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void QWClientPrivate::stripColor(char* string)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if(!ourReadableCharsTableInitialized)
 | 
	
		
			
				|  |  | +		fillReadableCharsTable();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	while(*string)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		*string = ourReadableCharsTable[(unsigned char)*string] & 127;
 | 
	
		
			
				|  |  | +		string++;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 |