QTfrontend/netconnectedclient.cpp
author unc0rr
Mon, 29 Sep 2008 22:14:23 +0000
changeset 1301 c6fe8a4bfd34
parent 1082 596b1dcdc1df
child 1302 4290ba4a14ca
permissions -rw-r--r--
Fix a bug screwing team selection up in network game (REMOVETEAM message doesn't have teamID, and after removing the team QMap still contains old info, when add and remove team with the same name, total hedgehogs number will be decreased by first team hh number)

/*
 * Hedgewars, a free turn based strategy game
 * Copyright (c) 2006-2008 Igor Ulyanov <iulyanov@gmail.com>
 *
 * 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 <QTcpServer>
#include <QTcpSocket>
#include <QStringList>
#include <QDebug>

#include "netconnectedclient.h"
#include "netserver.h"

extern char delimeter;

HWConnectedClient::HWConnectedClient(HWNetServer* hwserver, QTcpSocket* client) :
  readyToStart(false),
  m_hwserver(hwserver),
  m_client(client)
{
  connect(client, SIGNAL(disconnected()), this, SLOT(ClientDisconnect()));
  connect(client, SIGNAL(readyRead()), this, SLOT(ClientRead()));
}

HWConnectedClient::~HWConnectedClient()
{
}

void HWConnectedClient::ClientDisconnect()
{
  emit(HWClientDisconnected(this));
}

void HWConnectedClient::ClientRead()
{
  try {
	while (m_client->canReadLine()) {
		QString s = QString::fromUtf8(m_client->readLine().trimmed());
		if (s.size() == 0) {
			ParseCmd(cmdbuf);
			cmdbuf.clear();
		} else
			cmdbuf << s;
	}
  } catch(ShouldDisconnectException& e) {
    m_client->close();
  }
}

void HWConnectedClient::ParseCmd(const QStringList & lst)
{
//qDebug() << "Server: Parsing:" << lst;
  if(!lst.size())
  {
    qWarning("Net server: Bad message");
    return;
  }
  if (lst[0] == "NICK") {
    if(lst.size() < 2)
    {
      qWarning("Net server: Bad 'NICK' message");
	  return;
    }
    if(m_hwserver->haveNick(lst[1])) {
      RawSendNet(QString("ERRONEUSNICKNAME"));
      throw ShouldDisconnectException();
    }

    client_nick=lst[1];
    RawSendNet(QString("CONNECTED"));
    if(m_hwserver->isChiefClient(this)) {
      RawSendNet(QString("CONFIGASKED"));
    }
    else {
      RawSendNet(QString("SLAVE"));
      // send teams
      QList<QStringList> team_conf=m_hwserver->getTeamsConfig();
      for(QList<QStringList>::iterator tmit=team_conf.begin(); tmit!=team_conf.end(); ++tmit) {
	    RawSendNet(QString("ADDTEAM:")+delimeter+tmit->join(QString(delimeter)));
      }
      // send config
      QMap<QString, QStringList> conf=m_hwserver->getGameCfg();
      for(QMap<QString, QStringList>::iterator it=conf.begin(); it!=conf.end(); ++it) {
	    RawSendNet(QString("CONFIG_PARAM")+delimeter+it.key()+delimeter+it.value().join(QString(delimeter)));
      }
    }
    m_hwserver->sendNicks(this);
    m_hwserver->sendOthers(this, QString("JOINED")+delimeter+client_nick);
    return;
  }

  if(client_nick=="")
  {
  	qWarning() << "Net server: Message from unnamed client:" << lst;
  	return;
  }

  if (lst[0]=="START:") {
    readyToStart=true;
    if(m_hwserver->shouldStart(this)) {
      // start
      m_hwserver->sendAll("RUNGAME");
      m_hwserver->resetStart();
    }
    return;
  }

  if(lst[0]=="HHNUM") {
    if (lst.size()<4) {
      qWarning() << "Net server: Bad 'HHNUM' message:" << lst;
      return;
    }
    if(!m_hwserver->isChiefClient(this))
    {
      return; // permission denied
    }
    const QString confstr=lst[0]+"+"+lst[1]+"+"+lst[2];
    QMap<QString, QStringList>::iterator it=m_hwserver->m_gameCfg.find(confstr);
    int oldTeamHHNum = it==m_hwserver->m_gameCfg.end() ? 0 : it.value()[0].toUInt();
    int newTeamHHNum = lst[3].toUInt();
    m_hwserver->hhnum+=newTeamHHNum-oldTeamHHNum;
qDebug() << "HHNUM hhnum = " << m_hwserver->hhnum;
    // create CONFIG_PARAM to save HHNUM at server from lst
    QStringList tmp = lst;
    tmp=QStringList("CONFIG_PARAM") << confstr << lst[3];
    m_hwserver->sendOthers(this, tmp.join(QString(delimeter)));
    m_hwserver->m_gameCfg[tmp[1]]=tmp.mid(2);
qDebug() << QString("[%1] = %2").arg(tmp[1]).arg(tmp.mid(2)[0]);
    return;
  }

  if(lst[0]=="CONFIG_PARAM") {
    if (lst.size()<3) {
      qWarning() << "Net server: Bad 'CONFIG_PARAM' message:" << lst;
      return;
    }

    if(!m_hwserver->isChiefClient(this))
    {
      return; // permission denied
    }
    else m_hwserver->m_gameCfg[lst[1]]=lst.mid(2);
  }

  if(lst[0]=="ADDTEAM:") {
    if(lst.size() < 14)
    {
      qWarning("Net server: Bad 'ADDTEAM' message");
	  return;
    }
    QStringList tmp = lst;
    tmp.pop_front();

    // add team ID
    static unsigned int netTeamID=0;
    tmp.insert(1, QString::number(++netTeamID));

    // hedgehogs num count
    int maxAdd = 18 - m_hwserver->hhnum;
    if (maxAdd <= 0)
    {
	  qWarning("Net server: 'ADDTEAM' message: rejecting");
	  return; // reject command
    }
    int toAdd=maxAdd < 4 ? maxAdd : 4;
    m_hwserver->hhnum+=toAdd;
qDebug() << "to add = " << toAdd << "m_hwserver->hhnum = " << m_hwserver->hhnum;
    // hedgehogs num config
    QString hhnumCfg=QString("CONFIG_PARAM%1HHNUM+%2+%3%1%4").arg(delimeter).arg(tmp[0])\
      .arg(netTeamID)\
      .arg(toAdd);

    // creating color config for new team
    QString colorCfg=QString("CONFIG_PARAM%1TEAM_COLOR+%2+%3%1%4").arg(delimeter).arg(tmp[0])\
      .arg(netTeamID)\
      .arg(tmp.takeAt(2));

    m_hwserver->m_gameCfg[colorCfg.split(delimeter)[1]]=colorCfg.split(delimeter).mid(2);
    m_hwserver->m_gameCfg[hhnumCfg.split(delimeter)[1]]=hhnumCfg.split(delimeter).mid(2);
    m_teamsCfg.push_back(tmp);
qDebug() << QString("[%1] = %2").arg(hhnumCfg.split(delimeter)[1]).arg(hhnumCfg.split(delimeter).mid(2)[0]);
    m_hwserver->sendOthers(this, QString("ADDTEAM:")+delimeter+tmp.join(QString(delimeter)));
    RawSendNet(QString("TEAM_ACCEPTED%1%2%1%3").arg(delimeter).arg(tmp[0]).arg(tmp[1]));
    m_hwserver->sendAll(colorCfg);
    m_hwserver->sendAll(hhnumCfg);
    return;
  }

  if(lst[0]=="REMOVETEAM:") {
    if(lst.size() < 2)
    {
      qWarning("Net server: Bad 'REMOVETEAM' message");
      return;
    }

    for(QMap<QString, QStringList>::iterator it=m_hwserver->m_gameCfg.begin(); it!=m_hwserver->m_gameCfg.end(); ++it)
    {
      QStringList hhTmpList=it.key().split('+');
      if(hhTmpList[0] == "HHNUM")
      {
        if(hhTmpList[1]==lst[1])
        {
		  m_hwserver->hhnum-=it.value()[0].toUInt();
		  m_hwserver->m_gameCfg.remove(it.key());
qDebug() << "REMOVETEAM hhnum = " << m_hwserver->hhnum;
		  break;
        }
      }
    }

    unsigned int netID=removeTeam(lst[1]);
    m_hwserver->sendOthers(this, QString("REMOVETEAM:")+delimeter+lst[1]+delimeter+QString::number(netID));
    return;
  }

  m_hwserver->sendOthers(this, lst.join(QString(delimeter)));
}

unsigned int HWConnectedClient::removeTeam(const QString& tname)
{
	unsigned int netID=0;
	for(QList<QStringList>::iterator it=m_teamsCfg.begin(); it!=m_teamsCfg.end(); ++it) {
		if((*it)[0]==tname) {
			netID=(*it)[1].toUInt();
			m_teamsCfg.erase(it);
			break;
		}
	}
	if (netID == 0)
		qDebug() << QString("removeTeam: team '%1' not found").arg(tname);

	return netID;
}

QList<QStringList> HWConnectedClient::getTeamNames() const
{
  return m_teamsCfg;
}

void HWConnectedClient::RawSendNet(const QString & str)
{
  RawSendNet(str.toUtf8());
}

void HWConnectedClient::RawSendNet(const QByteArray & buf)
{
  m_client->write(buf);
  m_client->write("\n\n", 2);
}

QString HWConnectedClient::getClientNick() const
{
  return client_nick;
}

bool HWConnectedClient::isReady() const
{
  return readyToStart;
}

QString HWConnectedClient::getHedgehogsDescription() const
{
  return QString();//pclent_team->TeamGameConfig(65535, 4, 100, true).join((QString)delimeter);
}