# HG changeset patch # User displacer # Date 1168471495 0 # Node ID 73003488240b28ae5b7c72b3f72d5fc3dcdbb31b # Parent 83773ccf4f095ea192373d550e0facc6a22c4296 client/server net pre-alpha diff -r 83773ccf4f09 -r 73003488240b QTfrontend/netserver.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/netserver.cpp Wed Jan 10 23:24:55 2007 +0000 @@ -0,0 +1,244 @@ +/* + * Hedgewars, a worms-like game + * Copyright (c) 2006 Ulyanov Igor + * + * 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; version 2 of the License + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "netserver.h" + +#include +#include +#include + +#include + +#include + +const quint16 HWNetServer::ds_port=46631; + +extern char delimeter; + +void HWNetServer::StartServer() +{ + IPCServer = new QTcpServer(this); + if (!IPCServer->listen(QHostAddress::LocalHost, ds_port)) { + QMessageBox::critical(0, tr("Error"), + tr("Unable to start the server: %1.") + .arg(IPCServer->errorString())); + } + + connect(IPCServer, SIGNAL(newConnection()), this, SLOT(NewConnection())); +} + +void HWNetServer::StopServer() +{ + IPCServer->close(); +} + +void HWNetServer::NewConnection() +{ + QTcpSocket* client = IPCServer->nextPendingConnection(); + if(!client) return; + connclients.push_back(new HWConnectedClient(this, client)); + connect(connclients.back(), SIGNAL(HWClientDisconnected(HWConnectedClient*)), + this, SLOT(ClientDisconnect(HWConnectedClient*))); +} + +void HWNetServer::ClientDisconnect(HWConnectedClient* client) +{ + QList::iterator it=std::find(connclients.begin(), connclients.end(), client); + connclients.erase(it); + teamChanged(); +} + +QString HWNetServer::getRunningHostName() const +{ + return IPCServer->serverAddress().toString(); +} + +quint16 HWNetServer::getRunningPort() const +{ + return ds_port; +} + +bool HWNetServer::haveNick(const QString& nick) const +{ + for(QList::const_iterator it=connclients.begin(); it!=connclients.end(); ++it) { + if((*it)->getClientNick()==nick) { + return true; + } + } + return false; +} + +QStringList HWNetServer::getTeams() const +{ + QStringList lst; + for(QList::const_iterator it=connclients.begin(); it!=connclients.end(); ++it) { + try { + lst.push_back((*it)->getTeamName()); + } catch(HWConnectedClient::NoTeamNameException& e) { + } + } + return lst; +} + +void HWNetServer::teamChanged() +{ + for(QList::const_iterator it=connclients.begin(); it!=connclients.end(); ++it) { + (*it)->teamChangedNotify(); + } +} + +bool HWNetServer::shouldStart(HWConnectedClient* client) +{ + QList::iterator it=std::find(connclients.begin(), connclients.end(), client); + if(it==connclients.end() || *it!=client) return false; + for(it=connclients.begin(); it!=connclients.end(); ++it) { + if(!(*it)->isReady()) return false; + } + return true; +} + +QString HWNetServer::prepareConfig(QStringList lst) +{ + QString msg=lst.join((QString)delimeter)+delimeter; + for(QList::iterator it=connclients.begin(); it!=connclients.end(); ++it) { + if(!(*it)->isReady()) continue; + msg+=(*it)->getHedgehogsDescription()+delimeter; + } + qDebug() << msg; + return msg; +} + +HWConnectedClient::HWConnectedClient(HWNetServer* hwserver, QTcpSocket* client) : + readyToStart(false), + m_hwserver(hwserver), + m_client(client), + pclent_team(0) +{ + connect(client, SIGNAL(disconnected()), this, SLOT(ClientDisconnect())); + connect(client, SIGNAL(readyRead()), this, SLOT(ClientRead())); +} + +HWConnectedClient::~HWConnectedClient() +{ + if(pclent_team) delete pclent_team; +} + +void HWConnectedClient::ClientDisconnect() +{ + emit(HWClientDisconnected(this)); +} + +void HWConnectedClient::ClientRead() +{ + try { + while (m_client->canReadLine()) { + ParseLine(m_client->readLine().trimmed()); + } + } catch(ShouldDisconnectException& e) { + m_client->close(); + } +} + +void HWConnectedClient::ParseLine(const QByteArray & line) +{ + QString msg = QString::fromUtf8 (line.data(), line.size()); + + qDebug() << "line " << msg << " received"; + + QStringList lst = msg.split(delimeter); + if(lst.size()<2) return; + if (lst[0] == "NICK") { + if(m_hwserver->haveNick(lst[1])) { + RawSendNet(QString("ERRONEUSNICKNAME")); + throw ShouldDisconnectException(); + } + + client_nick=lst[1]; + qDebug() << "send connected"; + RawSendNet(QString("CONNECTED")); + m_hwserver->teamChanged(); + return; + } + if(client_nick=="") return; + + if (lst[0]=="START:") { + readyToStart=true; + if(m_hwserver->shouldStart(this)) { + // start + RawSendNet(QString("CONFIGASKED")); + } + return; + } + + if(lst[0]=="CONFIGANSWER") { + lst.pop_front(); + RawSendNet(QString("CONFIGURED")+QString(delimeter)+m_hwserver->prepareConfig(lst)+delimeter+"!"+delimeter); + return; + } + + if(lst.size()<10) return; + if(lst[0]=="ADDTEAM:") { + lst.pop_front(); + if(pclent_team) delete pclent_team; + pclent_team=new HWTeam(lst); + m_hwserver->teamChanged(); + return; + } +} + +void HWConnectedClient::teamChangedNotify() +{ + QString teams; + QStringList lst=m_hwserver->getTeams(); + for(int i=0; iwrite(buf); + m_client->write("\n", 1); +} + +QString HWConnectedClient::getClientNick() const +{ + return client_nick; +} + +QString HWConnectedClient::getTeamName() const +{ + if(!pclent_team) throw NoTeamNameException(); + return pclent_team->TeamName; +} + +bool HWConnectedClient::isReady() const +{ + return readyToStart; +} + +QString HWConnectedClient::getHedgehogsDescription() const +{ + return pclent_team->TeamGameConfig(65535, 4, 100).join((QString)delimeter); +} diff -r 83773ccf4f09 -r 73003488240b QTfrontend/netserver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/netserver.h Wed Jan 10 23:24:55 2007 +0000 @@ -0,0 +1,96 @@ +/* + * Hedgewars, a worms-like game + * Copyright (c) 2006 Igor Ulyanov + * + * 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; version 2 of the License + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef _NETSERVER_INCLUDED +#define _NETSERVER_INCLUDED + +#include +#include + +#include "team.h" + +class HWNetServer; +class QTcpSocket; +class QTcpServer; + +class HWConnectedClient : public QObject +{ + Q_OBJECT + + public: + HWConnectedClient(HWNetServer* hwserver, QTcpSocket* client); + ~HWConnectedClient(); + QString getClientNick() const; + + class NoTeamNameException{}; + QString getTeamName() const; + void teamChangedNotify(); + bool isReady() const; + + QString getHedgehogsDescription() const; + + private: + bool readyToStart; + class ShouldDisconnectException {}; + + QString client_nick; + void ParseLine(const QByteArray & line); + + HWNetServer* m_hwserver; + QTcpSocket* m_client; + HWTeam* pclent_team; + + void RawSendNet(const QString & buf); + void RawSendNet(const QByteArray & buf); + + //QByteArray readbuffer; + + signals: + void HWClientDisconnected(HWConnectedClient* client); + + private slots: + void ClientRead(); + void ClientDisconnect(); +}; + +class HWNetServer : public QObject +{ + Q_OBJECT + + public: + void StartServer(); + void StopServer(); + bool haveNick(const QString& nick) const; + QString getRunningHostName() const; + quint16 getRunningPort() const; + QStringList getTeams() const; + void teamChanged(); + bool shouldStart(HWConnectedClient* client); + QString prepareConfig(QStringList lst); + + private: + static const quint16 ds_port; + QTcpServer* IPCServer; + QList connclients; + + private slots: + void NewConnection(); + void ClientDisconnect(HWConnectedClient* client); +}; + +#endif // _NETSERVER_INCLUDED diff -r 83773ccf4f09 -r 73003488240b QTfrontend/newnetclient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/newnetclient.cpp Wed Jan 10 23:24:55 2007 +0000 @@ -0,0 +1,193 @@ +/* + * Hedgewars, a worms-like game + * Copyright (c) 2006 Ulyanov Igor + * + * 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; version 2 of the License + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +#include + +#include "newnetclient.h" +#include "proto.h" +#include "gameuiconfig.h" +#include "game.h" + +char delimeter='\t'; + +HWNewNet::HWNewNet(GameUIConfig * config) : + config(config) +{ + connect(&NetSocket, SIGNAL(readyRead()), this, SLOT(ClientRead())); + connect(&NetSocket, SIGNAL(connected()), this, SLOT(OnConnect())); + connect(&NetSocket, SIGNAL(disconnected()), this, SLOT(OnDisconnect())); + connect(&NetSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, + SLOT(displayError(QAbstractSocket::SocketError))); +} + +void HWNewNet::Connect(const QString & hostName, quint16 port, const QString & nick) +{ + qDebug() << hostName << ":" << port; + NetSocket.connectToHost(hostName, port); + mynick = nick; +} + +void HWNewNet::Disconnect() +{ + NetSocket.disconnect(); +} + +void HWNewNet::JoinGame(const QString & game) +{ + RawSendNet(QString("JOIN %1").arg(game)); +} + +void HWNewNet::AddTeam(const HWTeam & team) +{ + RawSendNet(QString("ADDTEAM:") + delimeter + + team.TeamName + delimeter + team.HHName[0] + delimeter + team.HHName[1] + delimeter + + team.HHName[2] + delimeter + team.HHName[3] + delimeter + team.HHName[4] + delimeter + + team.HHName[5] + delimeter + team.HHName[6] + delimeter + team.HHName[7]); +} + +void HWNewNet::StartGame() +{ + seed = QUuid::createUuid().toString(); + RawSendNet(QString("START:") + delimeter + seed); +} + +void HWNewNet::SendNet(const QByteArray & buf) +{ + QString msg = QString(buf.toBase64()); + + //NetBuffer += buf; + //RawSendNet(QString("PRIVMSG %1 :"MAGIC_CHAR MAGIC_CHAR"%2").arg(channel, msg)); +} + +void HWNewNet::RawSendNet(const QString & str) +{ + RawSendNet(str.toUtf8()); +} + +void HWNewNet::RawSendNet(const QByteArray & buf) +{ + if (buf.size() > 510) return; + NetSocket.write(buf); + NetSocket.write("\n", 1); +} + +void HWNewNet::ClientRead() +{ + while (NetSocket.canReadLine()) { + ParseLine(NetSocket.readLine().trimmed()); + } +} + +void HWNewNet::OnConnect() +{ + RawSendNet(QString("USER") + delimeter + "hwgame 1 2 Hedgewars game"); + RawSendNet(QString("NICK%1%2").arg(delimeter).arg(mynick)); +} + +void HWNewNet::OnDisconnect() +{ + emit ChangeInTeams(QStringList()); + emit Disconnected(); +} + +void HWNewNet::displayError(QAbstractSocket::SocketError socketError) +{ + switch (socketError) { + case QAbstractSocket::RemoteHostClosedError: + break; + case QAbstractSocket::HostNotFoundError: + QMessageBox::information(0, tr("Error"), + tr("The host was not found. Please check the host name and port settings.")); + break; + case QAbstractSocket::ConnectionRefusedError: + QMessageBox::information(0, tr("Error"), + tr("Connection refused")); + break; + default: + QMessageBox::information(0, tr("Error"), + NetSocket.errorString()); + } +} + +void HWNewNet::ParseLine(const QByteArray & line) +{ + QString msg = QString::fromUtf8 (line.data(), line.size()); + + qDebug() << "line " << msg << " received"; + + QStringList lst = msg.split(delimeter); + if (lst[0] == "ERRONEUSNICKNAME") { + QMessageBox::information(0, 0, "Your net nickname is in use or cannot be used"); + return; + } + + if (lst[0] == "CONNECTED") { + emit Connected(); + emit EnteredGame(); + return; + } + + if (lst[0] == "TEAMCHANGED") { + lst.pop_front(); + emit ChangeInTeams(lst); + return; + } + + if (lst[0] == "CONFIGASKED") { + ConfigAsked(); + return; + } + + if (lst[0] == "CONFIGURED") { + lst.pop_front(); + RunGame(); + qDebug() << lst[0]; + QByteArray ar=QByteArray::fromBase64(lst[0].toAscii()); + emit FromNet(ar); + + lst.pop_front(); + QByteArray cache; + emit FromNet(HWProto::addStringListToBuffer(cache, lst)); + return; + } + + QByteArray em = QByteArray::fromBase64(msg.toAscii()); + emit FromNet(em); +} + + +void HWNewNet::ConfigAsked() +{ + QByteArray cache; + HWProto::addStringToBuffer(cache, "eseed " + seed); + HWProto::addStringToBuffer(cache, "e$gmflags 0"); + HWProto::addStringToBuffer(cache, QString("etheme %1").arg(config->GetRandomTheme())); + QString _msg = QString("CONFIGANSWER") + delimeter + QString(cache.toBase64()); + RawSendNet(_msg); +} + +void HWNewNet::RunGame() +{ + HWGame * game = new HWGame(config, 0); + connect(game, SIGNAL(SendNet(const QByteArray &)), this, SLOT(SendNet(const QByteArray &))); + connect(this, SIGNAL(FromNet(const QByteArray &)), game, SLOT(FromNet(const QByteArray &))); + connect(this, SIGNAL(LocalCFG(const QString &)), game, SLOT(LocalCFG(const QString &))); + game->StartNet(); +} diff -r 83773ccf4f09 -r 73003488240b QTfrontend/newnetclient.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/newnetclient.h Wed Jan 10 23:24:55 2007 +0000 @@ -0,0 +1,98 @@ +/* + * Hedgewars, a worms-like game + * Copyright (c) 2006 Ulyanov Igor + * + * 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; version 2 of the License + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef _NEW_NETCLIENT_INCLUDED +#define _NEW_NETCLIENT_INCLUDED + +#include +#include +#include + +#include "team.h" + +class GameUIConfig; + +extern char delimeter; + +class HWNewNet : public QObject +{ + Q_OBJECT + + public: + HWNewNet(GameUIConfig * config); + void Connect(const QString & hostName, quint16 port, const QString & nick); + void Disconnect(); + void JoinGame(const QString & game); + void AddTeam(const HWTeam & team); + void StartGame(); + + private: + GameUIConfig* config; + + QString mynick; + QTcpSocket NetSocket; + QString seed; + + void ConfigAsked(); + void RunGame(); + + template + void SendCfgStrNet(T a) { + QByteArray strmsg; + strmsg.append(a); + quint8 sz = strmsg.size(); + QByteArray enginemsg = QByteArray((char *)&sz, 1) + strmsg; + QString _msg = delimeter + QString(enginemsg.toBase64()); + RawSendNet(_msg); + } + + template + void SendCfgStrLoc(T a) { + QByteArray strmsg; + strmsg.append(QString(a).toUtf8()); + quint8 sz = strmsg.size(); + QByteArray enginemsg = QByteArray((char *)&sz, 1) + strmsg; + emit FromNet(enginemsg); + } + + void RawSendNet(const QString & buf); + void RawSendNet(const QByteArray & buf); + void ParseLine(const QByteArray & line); + + signals: + void Connected(); + void Disconnected(); + void AddGame(const QString & chan); + void EnteredGame(); + void FromNet(const QByteArray & buf); + void LocalCFG(const QString & team); + void ChangeInTeams(const QStringList & teams); + + public slots: + void SendNet(const QByteArray & buf); + + private slots: + void ClientRead(); + void OnConnect(); + void OnDisconnect(); + //void Perform(); + void displayError(QAbstractSocket::SocketError socketError); + //void FlushNetBuf(); +}; + +#endif // _NEW_NETCLIENT_INCLUDED