lobby_moc.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. #include "StdInc.h"
  2. #include "lobby_moc.h"
  3. #include "ui_lobby_moc.h"
  4. #include "../mainwindow_moc.h"
  5. #include "../lib/GameConstants.h"
  6. #include "../jsonutils.h"
  7. #include "../../lib/CConfigHandler.h"
  8. //#include "../../lib/VCMIDirs.h"
  9. SocketLobby::SocketLobby(QObject *parent) :
  10. QObject(parent)
  11. {
  12. socket = new QTcpSocket(this);
  13. connect(socket, SIGNAL(connected()), this, SLOT(connected()));
  14. connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
  15. connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
  16. connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWritten(qint64)));
  17. }
  18. void SocketLobby::connectServer(const QString & host, int port, const QString & usr)
  19. {
  20. const int connectionTimeout = 1000;
  21. username = usr;
  22. emit text("Connecting to " + host + ":" + QString::number(port));
  23. socket->connectToHost(host, port);
  24. if(!socket->waitForDisconnected(connectionTimeout) && !isConnected)
  25. {
  26. emit text("Error: " + socket->errorString());
  27. }
  28. }
  29. void SocketLobby::disconnectServer()
  30. {
  31. socket->disconnectFromHost();
  32. }
  33. void SocketLobby::requestNewSession(const QString & session, int totalPlayers, const QString & pswd)
  34. {
  35. const QString sessionMessage = ProtocolStrings[CREATE].arg(session, pswd, QString::number(totalPlayers));
  36. send(sessionMessage);
  37. }
  38. void SocketLobby::requestJoinSession(const QString & session, const QString & pswd)
  39. {
  40. const QString sessionMessage = ProtocolStrings[JOIN].arg(session, pswd);
  41. send(sessionMessage);
  42. }
  43. void SocketLobby::requestLeaveSession(const QString & session)
  44. {
  45. const QString sessionMessage = ProtocolStrings[LEAVE].arg(session);
  46. send(sessionMessage);
  47. }
  48. void SocketLobby::requestReadySession(const QString & session)
  49. {
  50. const QString sessionMessage = ProtocolStrings[READY].arg(session);
  51. send(sessionMessage);
  52. }
  53. void SocketLobby::send(const QString & msg)
  54. {
  55. int sz = msg.size();
  56. QByteArray pack((const char *)&sz, sizeof(sz));
  57. pack.append(qPrintable(msg));
  58. socket->write(pack);
  59. }
  60. void SocketLobby::connected()
  61. {
  62. isConnected = true;
  63. emit text("Connected!");
  64. QByteArray greetingBytes;
  65. greetingBytes.append(ProtocolVersion);
  66. greetingBytes.append(ProtocolEncoding.size());
  67. const QString greetingConst = QString(greetingBytes)
  68. + ProtocolStrings[GREETING].arg(QString::fromStdString(ProtocolEncoding),
  69. username,
  70. QString::fromStdString(GameConstants::VCMI_VERSION));
  71. send(greetingConst);
  72. }
  73. void SocketLobby::disconnected()
  74. {
  75. isConnected = false;
  76. emit disconnect();
  77. emit text("Disconnected!");
  78. }
  79. void SocketLobby::bytesWritten(qint64 bytes)
  80. {
  81. qDebug() << "We wrote: " << bytes;
  82. }
  83. void SocketLobby::readyRead()
  84. {
  85. qDebug() << "Reading...";
  86. emit receive(socket->readAll());
  87. }
  88. ServerCommand::ServerCommand(ProtocolConsts cmd, const QStringList & args):
  89. command(cmd),
  90. arguments(args)
  91. {
  92. }
  93. Lobby::Lobby(QWidget *parent) :
  94. QWidget(parent),
  95. ui(new Ui::Lobby)
  96. {
  97. ui->setupUi(this);
  98. ui->buttonReady->setEnabled(false);
  99. connect(&socketLobby, SIGNAL(text(QString)), this, SLOT(chatMessage(QString)));
  100. connect(&socketLobby, SIGNAL(receive(QString)), this, SLOT(dispatchMessage(QString)));
  101. connect(&socketLobby, SIGNAL(disconnect()), this, SLOT(onDisconnected()));
  102. }
  103. Lobby::~Lobby()
  104. {
  105. delete ui;
  106. }
  107. void Lobby::serverCommand(const ServerCommand & command) try
  108. {
  109. //initialize variables outside of switch block
  110. const QString statusPlaceholder("%1 %2\n");
  111. QString resText;
  112. const auto & args = command.arguments;
  113. int amount, tagPoint;
  114. QString joinStr;
  115. switch(command.command)
  116. {
  117. case SRVERROR:
  118. protocolAssert(args.size());
  119. chatMessage("System error:" + args[0]);
  120. break;
  121. case CREATED:
  122. protocolAssert(args.size());
  123. hostSession = args[0];
  124. session = args[0];
  125. chatMessage("System: new session started");
  126. ui->buttonReady->setEnabled(true);
  127. break;
  128. case SESSIONS:
  129. protocolAssert(args.size());
  130. amount = args[0].toInt();
  131. protocolAssert(amount * 4 == (args.size() - 1));
  132. ui->sessionsTable->setRowCount(amount);
  133. tagPoint = 1;
  134. for(int i = 0; i < amount; ++i)
  135. {
  136. QTableWidgetItem * sessionNameItem = new QTableWidgetItem(args[tagPoint++]);
  137. ui->sessionsTable->setItem(i, 0, sessionNameItem);
  138. int playersJoined = args[tagPoint++].toInt();
  139. int playersTotal = args[tagPoint++].toInt();
  140. QTableWidgetItem * sessionPlayerItem = new QTableWidgetItem(QString("%1/%2").arg(playersJoined).arg(playersTotal));
  141. ui->sessionsTable->setItem(i, 1, sessionPlayerItem);
  142. QTableWidgetItem * sessionProtectedItem = new QTableWidgetItem(args[tagPoint++]);
  143. ui->sessionsTable->setItem(i, 2, sessionProtectedItem);
  144. }
  145. break;
  146. case JOINED:
  147. case KICKED:
  148. protocolAssert(args.size() == 2);
  149. joinStr = (command.command == JOINED ? "System: %1 joined to the session %2" : "System: %1 left session %2");
  150. if(args[1] == username)
  151. {
  152. ui->chat->clear(); //cleanup the chat
  153. chatMessage(joinStr.arg("you", args[0]));
  154. session = args[0];
  155. ui->stackedWidget->setCurrentWidget(command.command == JOINED ? ui->roomPage : ui->sessionsPage);
  156. if(command.command == KICKED)
  157. ui->buttonReady->setEnabled(false);
  158. }
  159. else
  160. {
  161. chatMessage(joinStr.arg(args[1], args[0]));
  162. }
  163. break;
  164. case STATUS:
  165. protocolAssert(args.size() > 0);
  166. amount = args[0].toInt();
  167. protocolAssert(amount * 2 == (args.size() - 1));
  168. tagPoint = 1;
  169. ui->roomChat->clear();
  170. resText.clear();
  171. for(int i = 0; i < amount; ++i, tagPoint += 2)
  172. {
  173. resText += statusPlaceholder.arg(args[tagPoint], args[tagPoint + 1] == "True" ? "ready" : "");
  174. }
  175. ui->roomChat->setPlainText(resText);
  176. break;
  177. case START: {
  178. protocolAssert(args.size() == 1);
  179. //actually start game
  180. //Settings node = settings.write["server"];
  181. gameArguments.clear();
  182. gameArguments << "--lobby";
  183. gameArguments << ui->hostEdit->text();
  184. gameArguments << ui->portEdit->text();
  185. gameArguments << args[0];
  186. /*node["lobby"].Bool() = true;
  187. node["server"].String() = ui->hostEdit->text().toStdString();
  188. node["serverport"].Integer() = ui->portEdit->text().toInt();
  189. node["uuid"].String() = args[0].toStdString();*/
  190. startGame = true;
  191. //on_startGameButton_clicked
  192. //node["names"].Vector().clear();
  193. //node["names"].Vector().pushBack(username.toStdString());
  194. break;
  195. }
  196. case HOST: {
  197. protocolAssert(args.size() == 2);
  198. Settings node = settings.write["server"]["host"];
  199. node["uuid"].String() = args[0].toStdString();
  200. node["connections"].Integer() = args[1].toInt();
  201. break;
  202. }
  203. case CHAT:
  204. protocolAssert(args.size() > 1);
  205. QString msg;
  206. for(int i = 1; i < args.size(); ++i)
  207. msg += args[i];
  208. chatMessage(QString("%1: %2").arg(args[0], msg));
  209. break;
  210. }
  211. }
  212. catch(const ProtocolError & e)
  213. {
  214. chatMessage(QString("System error: %1").arg(e.what()));
  215. }
  216. void Lobby::dispatchMessage(QString txt) try
  217. {
  218. if(txt.isEmpty())
  219. return;
  220. QStringList parseTags = txt.split(":>>");
  221. protocolAssert(parseTags.size() > 1 && parseTags[0].isEmpty() && !parseTags[1].isEmpty());
  222. for(int c = 1; c < parseTags.size(); ++c)
  223. {
  224. QStringList parseArgs = parseTags[c].split(":");
  225. protocolAssert(parseArgs.size() > 1);
  226. auto ctype = ProtocolStrings.key(parseArgs[0]);
  227. parseArgs.pop_front();
  228. ServerCommand cmd(ctype, parseArgs);
  229. serverCommand(cmd);
  230. }
  231. if(startGame)
  232. qobject_cast<MainWindow *>(qApp->activeWindow())->startGame(gameArguments);
  233. }
  234. catch(const ProtocolError & e)
  235. {
  236. chatMessage(QString("System error: %1").arg(e.what()));
  237. }
  238. void Lobby::onDisconnected()
  239. {
  240. ui->stackedWidget->setCurrentWidget(ui->sessionsPage);
  241. ui->connectButton->setChecked(false);
  242. }
  243. void Lobby::chatMessage(QString txt)
  244. {
  245. QTextCursor curs(ui->chat->document());
  246. curs.movePosition(QTextCursor::End);
  247. curs.insertText(txt + "\n");
  248. }
  249. void Lobby::protocolAssert(bool expr)
  250. {
  251. if(!expr)
  252. throw ProtocolError("Protocol error");
  253. }
  254. void Lobby::on_messageEdit_returnPressed()
  255. {
  256. socketLobby.send(ProtocolStrings[MESSAGE].arg(ui->messageEdit->text()));
  257. ui->messageEdit->clear();
  258. }
  259. void Lobby::on_connectButton_toggled(bool checked)
  260. {
  261. if(checked)
  262. {
  263. username = ui->userEdit->text();
  264. Settings node = settings.write["launcher"];
  265. node["lobbyUrl"].String() = ui->hostEdit->text().toStdString();
  266. node["lobbyPort"].Integer() = ui->portEdit->text().toInt();
  267. node["lobbyUsername"].String() = username.toStdString();
  268. socketLobby.connectServer(ui->hostEdit->text(), ui->portEdit->text().toInt(), username);
  269. }
  270. else
  271. {
  272. socketLobby.disconnectServer();
  273. }
  274. }
  275. void Lobby::on_newButton_clicked()
  276. {
  277. bool ok;
  278. QString sessionName = QInputDialog::getText(this, tr("New session"), tr("Session name:"), QLineEdit::Normal, "", &ok);
  279. if(ok && !sessionName.isEmpty())
  280. socketLobby.requestNewSession(sessionName, 2, ui->passwordInput->text());
  281. }
  282. void Lobby::on_joinButton_clicked()
  283. {
  284. auto * item = ui->sessionsTable->item(ui->sessionsTable->currentRow(), 0);
  285. if(item)
  286. socketLobby.requestJoinSession(item->text(), ui->passwordInput->text());
  287. }
  288. void Lobby::on_buttonLeave_clicked()
  289. {
  290. socketLobby.requestLeaveSession(session);
  291. }
  292. void Lobby::on_buttonReady_clicked()
  293. {
  294. socketLobby.requestReadySession(session);
  295. }