1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101 |
- /*
- 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++;
- }
- }
|