summaryrefslogtreecommitdiffstats
path: root/pacman-c++
diff options
context:
space:
mode:
Diffstat (limited to 'pacman-c++')
-rw-r--r--pacman-c++/client.cpp10
-rw-r--r--pacman-c++/mainwidget.cpp34
-rw-r--r--pacman-c++/pacman.proto1
-rw-r--r--pacman-c++/server.cpp85
-rw-r--r--pacman-c++/server.h4
-rw-r--r--pacman-c++/util.cpp122
-rw-r--r--pacman-c++/util.h14
7 files changed, 190 insertions, 80 deletions
diff --git a/pacman-c++/client.cpp b/pacman-c++/client.cpp
index 4843d95..5cc9279 100644
--- a/pacman-c++/client.cpp
+++ b/pacman-c++/client.cpp
@@ -67,6 +67,9 @@ bool Constants::server = false;
67 67
68int main(int argc, char ** argv) 68int main(int argc, char ** argv)
69{ 69{
70 /* Verify that the version of the library that we linked against is
71 * compatible with the version of the headers we compiled against.
72 */
70 GOOGLE_PROTOBUF_VERIFY_VERSION; 73 GOOGLE_PROTOBUF_VERIFY_VERSION;
71 74
72 QApplication app(argc, argv, true); 75 QApplication app(argc, argv, true);
@@ -80,5 +83,10 @@ int main(int argc, char ** argv)
80 client.show(); 83 client.show();
81 client.setWindowTitle(app.applicationName()); 84 client.setWindowTitle(app.applicationName());
82 85
83 return app.exec(); 86 int ret = app.exec();
87
88 /* Delete all global objects allocated by libprotobuf */
89 google::protobuf::ShutdownProtobufLibrary();
90
91 return ret;
84} 92}
diff --git a/pacman-c++/mainwidget.cpp b/pacman-c++/mainwidget.cpp
index 5dc392c..d441607 100644
--- a/pacman-c++/mainwidget.cpp
+++ b/pacman-c++/mainwidget.cpp
@@ -35,11 +35,14 @@ MainWidget::MainWidget(QWidget *parent)
35 35
36 /* call updateMap after m_color ist set! */ 36 /* call updateMap after m_color ist set! */
37 createGui(); 37 createGui();
38 m_scene->updateMap(Util::createDemoMap()); 38 Transmission::map_t map = Util::createDemoMap();
39 m_scene->updateMap(map);
40 Util::deleteMap(map);
41 map = NULL;
39 42
40 connect(m_socket, SIGNAL(readyRead()), this, SLOT(tick())); 43 connect(m_socket, SIGNAL(readyRead()), this, SLOT(tick()));
41 44
42 QTimer *sendTimer = new QTimer(); 45 QTimer *sendTimer = new QTimer(this);
43 connect(sendTimer, SIGNAL(timeout()), this, SLOT(sendKeyUpdate())); 46 connect(sendTimer, SIGNAL(timeout()), this, SLOT(sendKeyUpdate()));
44 sendTimer->start(Constants::tick); 47 sendTimer->start(Constants::tick);
45 48
@@ -143,12 +146,12 @@ Transmission::field_t MainWidget::translateKey(int key)
143 146
144void MainWidget::tick() 147void MainWidget::tick()
145{ 148{
146 std::string dataStr; 149 //TODO: allocate + reuse packet
147 Util::QByteArrayToStdString(m_socket->readAll(), dataStr); 150 QSharedPointer<QByteArray> data = Util::receivePacket(m_socket);
148
149 ProtoBuf::MapUpdate packet; 151 ProtoBuf::MapUpdate packet;
150 bool worked = packet.ParseFromString(dataStr); 152 bool worked = packet.ParseFromArray(data->data(), data->size());
151 Q_ASSERT(worked); 153 Q_ASSERT(worked);
154 Q_UNUSED(worked);
152 Transmission::map_t map = Util::createUninitialisedMap(); 155 Transmission::map_t map = Util::createUninitialisedMap();
153 Q_ASSERT(packet.field_size() == (int) (Constants::map_size.width * Constants::map_size.height)); 156 Q_ASSERT(packet.field_size() == (int) (Constants::map_size.width * Constants::map_size.height));
154 int i = 0; 157 int i = 0;
@@ -161,7 +164,11 @@ void MainWidget::tick()
161 } 164 }
162 } 165 }
163 m_scene->updateMap(map); 166 m_scene->updateMap(map);
167 Util::deleteMap(map);
164 updateScore(packet); 168 updateScore(packet);
169
170 if (m_socket->bytesAvailable() > (qint64)sizeof(qint64))
171 tick();
165} 172}
166 173
167void MainWidget::keyPressEvent(QKeyEvent* event) 174void MainWidget::keyPressEvent(QKeyEvent* event)
@@ -226,28 +233,27 @@ void MainWidget::playerScoreClicked()
226 233
227Color::Color MainWidget::connectToServer() 234Color::Color MainWidget::connectToServer()
228{ 235{
229 // check command line arguments for server port 236 /* TODO: check command line arguments for server port */
230 const QStringList &args = QCoreApplication::arguments(); 237 const QStringList &args = QCoreApplication::arguments();
231 QString srv = args.value(1, "127.0.0.1"); 238 QString srv = args.value(1, "127.0.0.1");
232 qDebug() << "[Connect] server=" << srv; 239 qDebug() << "[Connect] server=" << srv;
233 240
234 // connect to server 241 /* connect to server */
235 m_socket = new QTcpSocket(this); 242 m_socket = new QTcpSocket(this);
236 m_socket->connectToHost(srv, Constants::Networking::port); 243 m_socket->connectToHost(srv, Constants::Networking::port);
237 bool worked = m_socket->waitForConnected(Constants::Networking::connection_timeout); 244 bool worked = m_socket->waitForConnected(Constants::Networking::connection_timeout);
238 if (worked) 245 if (worked)
239 { 246 {
240 // additional init 247 /* additional init: first packet is our color */
241 // first packet is our color
242 worked = m_socket->waitForReadyRead(); 248 worked = m_socket->waitForReadyRead();
243 if (worked) 249 if (worked)
244 { 250 {
245 // receive color 251 /* receive color */
246 std::string data; 252 QSharedPointer<QByteArray> data = Util::receivePacket(m_socket);
247 Util::QByteArrayToStdString(m_socket->readAll(), data);
248 ProtoBuf::WhoAmI packet; 253 ProtoBuf::WhoAmI packet;
249 bool worked = packet.ParseFromString(data); 254 bool worked = packet.ParseFromArray(data->data(), data->size());
250 Q_ASSERT(worked); 255 Q_ASSERT(worked);
256 Q_UNUSED(worked);
251 return static_cast<Color::Color>(packet.color() & Transmission::color_mask); 257 return static_cast<Color::Color>(packet.color() & Transmission::color_mask);
252 } 258 }
253 } 259 }
diff --git a/pacman-c++/pacman.proto b/pacman-c++/pacman.proto
index 40c7af0..98478a0 100644
--- a/pacman-c++/pacman.proto
+++ b/pacman-c++/pacman.proto
@@ -4,7 +4,6 @@ message KeyPressUpdate {
4 required uint32 newKey = 1; 4 required uint32 newKey = 1;
5} 5}
6 6
7//TODO move points inside array
8message MapUpdate { 7message MapUpdate {
9 repeated uint32 field = 1 [packed=true]; 8 repeated uint32 field = 1 [packed=true];
10 repeated uint32 round_points = 2; 9 repeated uint32 round_points = 2;
diff --git a/pacman-c++/server.cpp b/pacman-c++/server.cpp
index 1c42174..b1877ad 100644
--- a/pacman-c++/server.cpp
+++ b/pacman-c++/server.cpp
@@ -14,7 +14,10 @@ Server::Server(QWidget *parent)
14 waitForClientConnections(); 14 waitForClientConnections();
15 qDebug() << "[Server] All Clients connected"; 15 qDebug() << "[Server] All Clients connected";
16 16
17 updateMap(Util::createDemoMap()); 17 Transmission::map_t map = Util::createDemoMap();
18 updateMap(map);
19 Util::deleteMap(map);
20 map = NULL;
18 21
19 QTimer *timer = new QTimer(this); 22 QTimer *timer = new QTimer(this);
20 connect(timer, SIGNAL(timeout()), this, SLOT(tick())); 23 connect(timer, SIGNAL(timeout()), this, SLOT(tick()));
@@ -24,11 +27,10 @@ Server::Server(QWidget *parent)
24void Server::tick() 27void Server::tick()
25{ 28{
26 qDebug() << "[Tick] Doing server update"; 29 qDebug() << "[Tick] Doing server update";
27 Transmission::map_t map = calculateUpdates(); 30 Transmission::map_t map = calculateUpdates();
28 updateMap(map); 31 updateMap(map);
29 32 sendUpdate(map);
30 QSharedPointer<ProtoBuf::MapUpdate> packet = createUpdatePacket(map); 33 Util::deleteMap(map);
31 sendUpdate(packet);
32} 34}
33 35
34Transmission::map_t Server::calculateUpdates() 36Transmission::map_t Server::calculateUpdates()
@@ -145,26 +147,6 @@ invalid_direction:
145 return map; 147 return map;
146} 148}
147 149
148QSharedPointer<ProtoBuf::MapUpdate> Server::createUpdatePacket(Transmission::map_t map)
149{
150 QSharedPointer<ProtoBuf::MapUpdate> updatePacket =
151 QSharedPointer<ProtoBuf::MapUpdate>(new ProtoBuf::MapUpdate);
152
153 for (unsigned int x = 0; x < Constants::map_size.width; ++x)
154 {
155 for (unsigned int y = 0; y < Constants::map_size.height; ++y)
156 updatePacket->add_field(map[x][y]);
157 }
158
159 for(unsigned i = 0; Color::order[i] != Color::none; ++i)
160 {
161 updatePacket->add_round_points(m_actors.value(Color::order[i])->getRoundPoints());
162 updatePacket->add_game_points(m_actors.value(Color::order[i])->getGamePoints());
163 }
164
165 return updatePacket;
166}
167
168void Server::waitForClientConnections() 150void Server::waitForClientConnections()
169{ 151{
170 QTcpServer *tcpSrv = new QTcpServer(this); 152 QTcpServer *tcpSrv = new QTcpServer(this);
@@ -182,13 +164,15 @@ void Server::waitForClientConnections()
182#endif 164#endif
183 bool connectionAvailable = tcpSrv->waitForNewConnection(-1); 165 bool connectionAvailable = tcpSrv->waitForNewConnection(-1);
184 Q_ASSERT(connectionAvailable); 166 Q_ASSERT(connectionAvailable);
167 Q_UNUSED(connectionAvailable);
185 QTcpSocket *socket = tcpSrv->nextPendingConnection(); 168 QTcpSocket *socket = tcpSrv->nextPendingConnection();
186 connect(socket, SIGNAL(readyRead()), this, SLOT(keyPressUpdate())); 169 connect(socket, SIGNAL(readyRead()), this, SLOT(keyPressUpdate()));
187 170
188 // assign color 171 /* assign color */
189 Color::Color color = Color::order[i]; 172 Color::Color color = Color::order[i];
190 m_clientConnections[color] = socket; 173 m_clientConnections[color] = socket;
191 // notify player of color 174 /* notify player of color */
175 //TODO: allocate + reuse packet
192 ProtoBuf::WhoAmI packet; 176 ProtoBuf::WhoAmI packet;
193 packet.set_color(color); 177 packet.set_color(color);
194 Util::sendPacket(packet, socket); 178 Util::sendPacket(packet, socket);
@@ -197,12 +181,31 @@ void Server::waitForClientConnections()
197 } 181 }
198} 182}
199 183
200void Server::sendUpdate(QSharedPointer< ProtoBuf::MapUpdate > packet) 184void Server::sendUpdate(Transmission::map_t map)
201{ 185{
202 std::string dataStr = packet->SerializeAsString(); 186 ProtoBuf::MapUpdate packet;
203 const char *data = dataStr.c_str(); 187
188 for (unsigned int x = 0; x < Constants::map_size.width; ++x)
189 {
190 for (unsigned int y = 0; y < Constants::map_size.height; ++y)
191 packet.add_field(map[x][y]);
192 }
193
194 for(unsigned i = 0; Color::order[i] != Color::none; ++i)
195 {
196 packet.add_round_points(m_actors.value(Color::order[i])->getRoundPoints());
197 packet.add_game_points(m_actors.value(Color::order[i])->getGamePoints());
198 }
199
200 QSharedPointer<QByteArray> data = Util::createPacket(packet);
204 foreach(QTcpSocket *socket, m_clientConnections) 201 foreach(QTcpSocket *socket, m_clientConnections)
205 Util::sendPacket(data, dataStr.length(), socket); 202 {
203 if (!Util::sendPacket(data.data(), socket))
204 {
205 qDebug() << "[sendUpdate] Error while sending data to client, exiting...";
206 qApp->quit();
207 }
208 }
206} 209}
207 210
208void Server::keyPressUpdate() 211void Server::keyPressUpdate()
@@ -213,13 +216,15 @@ void Server::keyPressUpdate()
213 i.next(); 216 i.next();
214 Color::Color color = i.key(); 217 Color::Color color = i.key();
215 QTcpSocket *socket = i.value(); 218 QTcpSocket *socket = i.value();
216 if (socket->bytesAvailable() > 0) 219 QDataStream in(i.value());
220 while (socket->bytesAvailable() > (qint64)sizeof(qint64))
217 { 221 {
218 std::string dataStr; 222 QSharedPointer<QByteArray> data = Util::receivePacket(socket);
219 Util::QByteArrayToStdString(socket->readAll(), dataStr); 223 //TODO: allocate + reuse packet
220 ProtoBuf::KeyPressUpdate packet; 224 ProtoBuf::KeyPressUpdate packet;
221 bool worked = packet.ParseFromString(dataStr); 225 bool worked = packet.ParseFromArray(data->data(), data->size());
222 Q_ASSERT(worked); 226 Q_ASSERT(worked);
227 Q_UNUSED(worked);
223 Transmission::field_t direction = packet.newkey(); 228 Transmission::field_t direction = packet.newkey();
224 qDebug() << "[KeyPress] actor=" << color << "direction=" << direction; 229 qDebug() << "[KeyPress] actor=" << color << "direction=" << direction;
225 m_actorMovements[color] = Util::transmissionMovementToActor(direction); 230 m_actorMovements[color] = Util::transmissionMovementToActor(direction);
@@ -231,6 +236,9 @@ bool Constants::server = true;
231 236
232int main(int argc, char ** argv) 237int main(int argc, char ** argv)
233{ 238{
239 /* Verify that the version of the library that we linked against is
240 * compatible with the version of the headers we compiled against.
241 */
234 GOOGLE_PROTOBUF_VERIFY_VERSION; 242 GOOGLE_PROTOBUF_VERIFY_VERSION;
235 243
236 QApplication app(argc, argv, false); 244 QApplication app(argc, argv, false);
@@ -240,5 +248,10 @@ int main(int argc, char ** argv)
240 qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime())); 248 qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
241 249
242 Server Server; 250 Server Server;
243 return app.exec(); 251 int ret = app.exec();
252
253 /* Delete all global objects allocated by libprotobuf */
254 google::protobuf::ShutdownProtobufLibrary();
255
256 return ret;
244} 257}
diff --git a/pacman-c++/server.h b/pacman-c++/server.h
index 32bdf15..f7505a6 100644
--- a/pacman-c++/server.h
+++ b/pacman-c++/server.h
@@ -28,10 +28,8 @@ protected:
28 /* calculate updates of current tick for sending to client */ 28 /* calculate updates of current tick for sending to client */
29 Transmission::map_t calculateUpdates(); 29 Transmission::map_t calculateUpdates();
30 30
31 QSharedPointer<ProtoBuf::MapUpdate> createUpdatePacket(Transmission::map_t);
32
33 /* update client maps */ 31 /* update client maps */
34 void sendUpdate(QSharedPointer<ProtoBuf::MapUpdate>); 32 void sendUpdate(Transmission::map_t map);
35 33
36 QMap<Color::Color, QTcpSocket *> m_clientConnections; 34 QMap<Color::Color, QTcpSocket *> m_clientConnections;
37 35
diff --git a/pacman-c++/util.cpp b/pacman-c++/util.cpp
index c60f2df..2fb9f69 100644
--- a/pacman-c++/util.cpp
+++ b/pacman-c++/util.cpp
@@ -1,5 +1,4 @@
1#include "util.h" 1#include "util.h"
2
3#include <QtNetwork/QTcpSocket> 2#include <QtNetwork/QTcpSocket>
4 3
5namespace Util 4namespace Util
@@ -27,6 +26,13 @@ namespace Util
27 return map; 26 return map;
28 } 27 }
29 28
29 void deleteMap(Transmission::map_t map)
30 {
31 for (unsigned int x = 0; x < Constants::map_size.width; ++x)
32 delete[] map[x];
33 delete[] map;
34 }
35
30 // temporary 36 // temporary
31 Transmission::map_t createDemoMap() 37 Transmission::map_t createDemoMap()
32 { 38 {
@@ -141,32 +147,108 @@ namespace Util
141 return def; 147 return def;
142 } 148 }
143 149
144 void QByteArrayToStdString(const QByteArray& arr, std::string& str) 150 QSharedPointer<QByteArray> createPacket(const ::google::protobuf::MessageLite& packet)
145 { 151 {
146 // TODO: normal conversion to std::string won't work, 152 qint64 packetlen = packet.ByteSize();
147 // probably due to \0-bytes. 153 /* datalen = packet with length prepended */
148 //std::string dataStr = std::string(data.constData()); 154 qint64 datalen = sizeof(qint64) + packetlen;
149 //std::string dataStr = QString(data).toStdString();
150 for (int i=0; i<arr.size(); ++i)
151 str += arr[i];
152 }
153 155
154 void sendPacket(const ::google::protobuf::Message& packet, QTcpSocket *socket) 156 QSharedPointer<QByteArray> data = QSharedPointer<QByteArray>(new QByteArray);
155 { 157 data->resize(datalen);
156 std::string dataStr = packet.SerializeAsString(); 158
157 const char *data = dataStr.c_str(); 159 /* use QDataStream for length to avoid endianess shit */
158 sendPacket(data, dataStr.length(), socket); 160 QDataStream out(data.data(), QIODevice::WriteOnly);
161 out << packetlen;
162
163 /* use protobuf.SerializeWithCachedSizesToArray() to avoid calling protobuf.ByteSize() again */
164 ::google::protobuf::uint8 *dataptr = reinterpret_cast<google::protobuf::uint8 *>(data->data());
165 packet.SerializeWithCachedSizesToArray(dataptr + sizeof(qint64));
166
167 return data;
159 } 168 }
160 169
161 void sendPacket(const char *data, int length, QTcpSocket *socket) 170 bool sendPacket(QByteArray *data, QTcpSocket *socket)
162 { 171 {
163 int bytesWritten = socket->write(data, length); 172 int bytesWritten = socket->write(*data);
164 if (bytesWritten != length) 173 if (bytesWritten != data->size())
165 { 174 {
166 qDebug() << "[sendPacket] Not all data has been sent." 175 qWarning() << "[sendPacket] Not all data has been sent:"
167 << "written=" << bytesWritten << ", length=" << length; 176 << "written=" << bytesWritten << ", length=" << data->size();
177 return false;
168 } 178 }
169 Q_ASSERT(bytesWritten == length);
170 socket->flush(); 179 socket->flush();
180 return true;
181 }
182
183 bool sendPacket(const ::google::protobuf::MessageLite& packet, QTcpSocket *socket)
184 {
185 return sendPacket(createPacket(packet).data(), socket);
186 }
187
188 QSharedPointer<QByteArray> receivePacket(QTcpSocket *socket)
189 {
190 QDataStream in(socket);
191 qint64 datalen;
192 in >> datalen;
193
194 QSharedPointer<QByteArray> data = QSharedPointer<QByteArray>(new QByteArray);
195 data->resize(datalen);
196 socket->read(data->data(), data->size());
197 return data;
198 }
199
200#if 0
201 void hexdump(void *pAddressIn, long lSize)
202 {
203 char szBuf[100];
204 long lIndent = 1;
205 long lOutLen, lIndex, lIndex2, lOutLen2;
206 long lRelPos;
207 struct { char *pData; unsigned long lSize; } buf;
208 unsigned char *pTmp,ucTmp;
209 unsigned char *pAddress = (unsigned char *)pAddressIn;
210
211 buf.pData = (char *)pAddress;
212 buf.lSize = lSize;
213
214 while (buf.lSize > 0)
215 {
216 pTmp = (unsigned char *)buf.pData;
217 lOutLen = (int)buf.lSize;
218 if (lOutLen > 16)
219 lOutLen = 16;
220
221 // create a 64-character formatted output line:
222 sprintf(szBuf, " > "
223 " "
224 " %08lX", pTmp-pAddress);
225 lOutLen2 = lOutLen;
226
227 for(lIndex = 1+lIndent, lIndex2 = 53-15+lIndent, lRelPos = 0;
228 lOutLen2;
229 lOutLen2--, lIndex += 2, lIndex2++
230 )
231 {
232 ucTmp = *pTmp++;
233
234 sprintf(szBuf + lIndex, "%02X ", (unsigned short)ucTmp);
235 if(!isprint(ucTmp)) ucTmp = '.'; // nonprintable char
236 szBuf[lIndex2] = ucTmp;
237
238 if (!(++lRelPos & 3)) // extra blank after 4 bytes
239 { lIndex++; szBuf[lIndex+2] = ' '; }
240 }
241
242 if (!(lRelPos & 3)) lIndex--;
243
244 szBuf[lIndex ] = '<';
245 szBuf[lIndex+1] = ' ';
246
247 printf("%s\n", szBuf);
248
249 buf.pData += lOutLen;
250 buf.lSize -= lOutLen;
251 }
171 } 252 }
253#endif
172} 254}
diff --git a/pacman-c++/util.h b/pacman-c++/util.h
index e0f1264..87dbd86 100644
--- a/pacman-c++/util.h
+++ b/pacman-c++/util.h
@@ -12,17 +12,21 @@ namespace Util
12 Transmission::map_t createUninitialisedMap(); 12 Transmission::map_t createUninitialisedMap();
13 Transmission::map_t createDemoMap(); 13 Transmission::map_t createDemoMap();
14 Transmission::map_t createEmptyMap(); 14 Transmission::map_t createEmptyMap();
15 void deleteMap(Transmission::map_t map);
15 16
16 // default is to assert false with -1
17 Transmission::field_t actorMovementToTransmission(Actor::Movement mov, 17 Transmission::field_t actorMovementToTransmission(Actor::Movement mov,
18 Transmission::field_t def = Transmission::none); 18 Transmission::field_t def = Transmission::none);
19 Actor::Movement transmissionMovementToActor(Transmission::field_t field, 19 Actor::Movement transmissionMovementToActor(Transmission::field_t field,
20 Actor::Movement def = Actor::None); 20 Actor::Movement def = Actor::None);
21 21
22 void QByteArrayToStdString(const QByteArray& arr, std::string& str); 22 /* send packet with error check and flush */
23 QSharedPointer<QByteArray> createPacket(const ::google::protobuf::MessageLite& packet);
24 bool sendPacket(QByteArray *data, QTcpSocket *socket);
25 bool sendPacket(const ::google::protobuf::MessageLite& packet, QTcpSocket *socket);
26 QSharedPointer<QByteArray> receivePacket(QTcpSocket *socket);
23 27
24 // send packet with error check and flush 28#if 0
25 void sendPacket(const ::google::protobuf::Message& packet, QTcpSocket *socket); 29 void hexdump(void *pAddressIn, long lSize);
26 void sendPacket(const char *data, int length, QTcpSocket *socket); 30#endif
27} 31}
28#endif // UTIL_H 32#endif // UTIL_H