summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortotycro <totycro@unknown-horizons.org>2011-04-09 19:20:13 +0200
committertotycro <totycro@unknown-horizons.org>2011-04-09 19:20:13 +0200
commit4f88849caf6533d965849952c9ea153fd8c518c5 (patch)
tree809d22c6a8fab16dc32eaf0c22fb65d57640f72f
parent4e3c33632e811d5b57c9b61ec7f219fa06856fd2 (diff)
downloadfoop-4f88849caf6533d965849952c9ea153fd8c518c5.tar.gz
foop-4f88849caf6533d965849952c9ea153fd8c518c5.tar.bz2
foop-4f88849caf6533d965849952c9ea153fd8c518c5.zip
first version of multiplayer
-rw-r--r--pacman-c++/constants.h3
-rw-r--r--pacman-c++/mainwidget.cpp82
-rw-r--r--pacman-c++/mainwidget.h4
-rw-r--r--pacman-c++/pacman.pro2
-rw-r--r--pacman-c++/pacman.proto2
-rw-r--r--pacman-c++/pacman.server.pro4
-rwxr-xr-xpacman-c++/rebuild-client.sh4
-rwxr-xr-xpacman-c++/rebuild-server.sh4
-rw-r--r--pacman-c++/sceneholder.cpp3
-rw-r--r--pacman-c++/server.cpp104
-rw-r--r--pacman-c++/server.h25
-rw-r--r--pacman-c++/util.cpp8
-rw-r--r--pacman-c++/util.h2
13 files changed, 209 insertions, 38 deletions
diff --git a/pacman-c++/constants.h b/pacman-c++/constants.h
index 44999f7..d81f474 100644
--- a/pacman-c++/constants.h
+++ b/pacman-c++/constants.h
@@ -15,6 +15,9 @@ namespace Constants {
15 const unsigned int sprite_margin = 2; 15 const unsigned int sprite_margin = 2;
16 const unsigned int sprite_offset = 20; 16 const unsigned int sprite_offset = 20;
17 const unsigned int tick = 250; // ms 17 const unsigned int tick = 250; // ms
18
19 const unsigned int port = 7321;
20 const unsigned int connection_timeout = 3000;
18} 21}
19 22
20namespace Color 23namespace Color
diff --git a/pacman-c++/mainwidget.cpp b/pacman-c++/mainwidget.cpp
index 06a0b9c..da08d89 100644
--- a/pacman-c++/mainwidget.cpp
+++ b/pacman-c++/mainwidget.cpp
@@ -4,6 +4,7 @@
4#include "constants.h" 4#include "constants.h"
5#include "audioplayer.h" 5#include "audioplayer.h"
6#include "util.h" 6#include "util.h"
7#include "pacman.pb.h"
7 8
8MainWidget::MainWidget(QWidget *parent) 9MainWidget::MainWidget(QWidget *parent)
9 : SceneHolder(parent), m_currentKey(0), m_running(false) 10 : SceneHolder(parent), m_currentKey(0), m_running(false)
@@ -14,9 +15,15 @@ MainWidget::MainWidget(QWidget *parent)
14 //connect(AudioPlayer::self(), SIGNAL(finished()), this, SLOT(startGame())); 15 //connect(AudioPlayer::self(), SIGNAL(finished()), this, SLOT(startGame()));
15 //AudioPlayer::self()->play(AudioPlayer::Intro); 16 //AudioPlayer::self()->play(AudioPlayer::Intro);
16 17
17 QTimer *timer = new QTimer(this); 18 bool connected = connectToServer();
18 connect(timer, SIGNAL(timeout()), this, SLOT(tick())); 19 if (!connected) {
19 timer->start(Constants::tick); 20 QMessageBox::critical(this, "Error", "Failed to connect to server, falling back to local test mode");
21 // TODO: quit application here or sth
22 QTimer *timer = new QTimer(this);
23 connect(timer, SIGNAL(timeout()), this, SLOT(tick()));
24 timer->start(Constants::tick);
25 }
26 connect(m_socket, SIGNAL(readyRead()), this, SLOT(tick()));
20 27
21 startGame(); 28 startGame();
22} 29}
@@ -120,21 +127,49 @@ Transmission::field_t MainWidget::translateKey(int key)
120 127
121void MainWidget::tick() 128void MainWidget::tick()
122{ 129{
123 Actor::Movement mov = Util::transmissionMovementToActor(m_currentKey, Actor::None); 130#if 0
131 Actor::Movement mov = Util::transmissionMovementToActor(m_currentKey, Actor::None);
124 132
125 QMapIterator<Color::Color, Actor*> i(m_actors); 133 QMapIterator<Color::Color, Actor*> i(m_actors);
126 while (i.hasNext()) 134 while (i.hasNext())
127 {
128 i.next();
129 i.value()->move(mov);
130 QList<QGraphicsItem *> list(i.value()->collidingItems());
131 for(int j = 0; j < list.count(); ++j)
132 { 135 {
133 if (list.at(j)->parentItem() == i.value()) 136 i.next();
134 continue; 137 i.value()->move(mov);
135 list.at(j)->setOpacity(0.6); 138 QList<QGraphicsItem *> list(i.value()->collidingItems());
139 for(int j = 0; j < list.count(); ++j)
140 {
141 if (list.at(j)->parentItem() == i.value())
142 continue;
143 list.at(j)->setOpacity(0.6);
144 }
145 }
146#else
147 QByteArray data = m_socket->readAll();
148 //qDebug() << "read qbytes " << data.length();
149 // TODO: normal conversion to std::string won't work,
150 // probably due to \0-bytes. both those methods will yield
151 // a 3 char long string
152 //std::string dataStr = std::string(data.constData());
153 //std::string dataStr = QString(data).toStdString();
154 std::string dataStr;
155 for (int i = 0; i < data.size(); ++i) {
156 dataStr += data[i];
157 }
158
159 //qDebug() << "read str " << dataStr.length();
160 ProtoBuf::MapUpdate packet;
161 packet.ParseFromString(dataStr);
162 Transmission::map_t map = Util::createUninitialisedMap();
163 Q_ASSERT(packet.field_size() == (int) (Constants::map_size.width * Constants::map_size.height));
164 int i = 0;
165 for (unsigned int x = 0; x < Constants::map_size.width; ++x) {
166 for (unsigned int y = 0; y < Constants::map_size.height; ++y) {
167 map[x][y] = packet.field(i);
168 ++i;
136 } 169 }
137 } 170 }
171 updateMap(map);
172 #endif
138} 173}
139 174
140 175
@@ -144,8 +179,19 @@ void MainWidget::keyPressEvent(QKeyEvent* event)
144 return; 179 return;
145 180
146 QWidget::keyPressEvent(event); 181 QWidget::keyPressEvent(event);
182 // TODO: remove m_currentKey when we don't need it any more for testing
147 m_currentKey = translateKey(event->key()); 183 m_currentKey = translateKey(event->key());
148 184
185 // send to server
186 ProtoBuf::KeyPressUpdate packet;
187 packet.set_newkey(m_currentKey);
188 std::string dataStr = packet.SerializeAsString();
189 unsigned int bytesWritten = m_socket->write(dataStr.c_str(), dataStr.length());
190 m_socket->flush();
191 Q_ASSERT(bytesWritten == dataStr.length());
192
193 qDebug() << "send key: " << m_currentKey;
194
149 return; 195 return;
150 196
151 // test stuff 197 // test stuff
@@ -186,3 +232,11 @@ void MainWidget::playerScoreClicked()
186 tmp->setChecked(true); 232 tmp->setChecked(true);
187 return; 233 return;
188} 234}
235
236bool MainWidget::connectToServer()
237{
238 m_socket = new QTcpSocket(this);
239 m_socket->connectToHost("127.0.0.1", Constants::port);
240 return m_socket->waitForConnected(3000);
241}
242
diff --git a/pacman-c++/mainwidget.h b/pacman-c++/mainwidget.h
index 6adc876..eaa8be0 100644
--- a/pacman-c++/mainwidget.h
+++ b/pacman-c++/mainwidget.h
@@ -6,6 +6,7 @@
6#include "pixmapitem.h" 6#include "pixmapitem.h"
7#include <QtGui> 7#include <QtGui>
8#include <QtCore> 8#include <QtCore>
9#include <QTcpSocket>
9 10
10class Actor; 11class Actor;
11 12
@@ -29,6 +30,7 @@ private:
29 void createMenu(); 30 void createMenu();
30 void updateScore(); 31 void updateScore();
31 bool isRunning(); 32 bool isRunning();
33 bool connectToServer();
32 34
33private slots: 35private slots:
34 void startGame(); 36 void startGame();
@@ -47,6 +49,8 @@ private:
47 49
48 // game running 50 // game running
49 bool m_running; 51 bool m_running;
52
53 QTcpSocket *m_socket;
50}; 54};
51 55
52#endif // MAINWIDGET_H 56#endif // MAINWIDGET_H
diff --git a/pacman-c++/pacman.pro b/pacman-c++/pacman.pro
index 3670bc0..a346f20 100644
--- a/pacman-c++/pacman.pro
+++ b/pacman-c++/pacman.pro
@@ -2,7 +2,7 @@ TEMPLATE = app
2LANGUAGE = C++ 2LANGUAGE = C++
3VERSION = 0.1 3VERSION = 0.1
4 4
5QT += phonon 5QT += phonon network
6SOURCES += pixmapitem.cpp \ 6SOURCES += pixmapitem.cpp \
7 actor.cpp \ 7 actor.cpp \
8 animationmanager.cpp \ 8 animationmanager.cpp \
diff --git a/pacman-c++/pacman.proto b/pacman-c++/pacman.proto
index 39c68f7..7a582df 100644
--- a/pacman-c++/pacman.proto
+++ b/pacman-c++/pacman.proto
@@ -1,3 +1,5 @@
1package ProtoBuf;
2
1message KeyPressUpdate { 3message KeyPressUpdate {
2 required uint32 newKey = 1; 4 required uint32 newKey = 1;
3} 5}
diff --git a/pacman-c++/pacman.server.pro b/pacman-c++/pacman.server.pro
index 7e23f21..631bc50 100644
--- a/pacman-c++/pacman.server.pro
+++ b/pacman-c++/pacman.server.pro
@@ -3,7 +3,9 @@ LANGUAGE = C++
3VERSION = 0.1 3VERSION = 0.1
4DEFINES += SERVER 4DEFINES += SERVER
5 5
6QT += phonon 6TARGET = pacman-server
7
8QT += phonon network
7SOURCES += pixmapitem.cpp \ 9SOURCES += pixmapitem.cpp \
8 actor.cpp \ 10 actor.cpp \
9 animationmanager.cpp \ 11 animationmanager.cpp \
diff --git a/pacman-c++/rebuild-client.sh b/pacman-c++/rebuild-client.sh
index 6cbcaed..f317d6d 100755
--- a/pacman-c++/rebuild-client.sh
+++ b/pacman-c++/rebuild-client.sh
@@ -1,4 +1,4 @@
1#!/bin/sh 1#!/bin/sh
2make distclean 2#make distclean
3qmake CONFIG+=DEBUG pacman.pro 3qmake CONFIG+=DEBUG pacman.pro
4make 4make -j2
diff --git a/pacman-c++/rebuild-server.sh b/pacman-c++/rebuild-server.sh
index b573a2e..f00d67b 100755
--- a/pacman-c++/rebuild-server.sh
+++ b/pacman-c++/rebuild-server.sh
@@ -1,4 +1,4 @@
1#!/bin/sh 1#!/bin/sh
2make distclean 2#make distclean
3qmake CONFIG+=DEBUG pacman.server.pro 3qmake CONFIG+=DEBUG pacman.server.pro
4make 4make -j2
diff --git a/pacman-c++/sceneholder.cpp b/pacman-c++/sceneholder.cpp
index 0cb7d15..515d5ec 100644
--- a/pacman-c++/sceneholder.cpp
+++ b/pacman-c++/sceneholder.cpp
@@ -78,7 +78,8 @@ void SceneHolder::updateMap(const Transmission::map_t& map)
78 78
79 Actor::Movement direction = 79 Actor::Movement direction =
80 Util::transmissionMovementToActor(cur & Transmission::direction_mask); 80 Util::transmissionMovementToActor(cur & Transmission::direction_mask);
81 //actor->move(direction, mapPositionToCoord(x, y)); 81 actor->move(direction);
82 qDebug() << "actor move " << direction;
82 } 83 }
83 else { 84 else {
84 qDebug() << "abort at " << cur; 85 qDebug() << "abort at " << cur;
diff --git a/pacman-c++/server.cpp b/pacman-c++/server.cpp
index 8539410..8f9e42d 100644
--- a/pacman-c++/server.cpp
+++ b/pacman-c++/server.cpp
@@ -1,34 +1,39 @@
1#include "server.h" 1#include "server.h"
2 2
3#include <QtNetwork/QTcpServer>
4#include <QtNetwork/QTcpSocket>
3#include "util.h" 5#include "util.h"
4
5#include "pacman.pb.h" 6#include "pacman.pb.h"
6 7
7Server::Server(QWidget *parent) 8Server::Server(QWidget *parent)
8 : SceneHolder(parent) 9 : SceneHolder(parent)
9{ 10{
11 qDebug() << "waiting for clients";
12 waitForClientConnections();
13 qDebug() << "clients connected";
14
10 updateMap(Util::createDummyMap()); 15 updateMap(Util::createDummyMap());
11 16
12 Transmission::map_t map = calculateUpdates(); 17 QTimer *timer = new QTimer(this);
13 for (int i=0; i<10; ++i) { 18 connect(timer, SIGNAL(timeout()), this, SLOT(tick()));
14 qDebug() << "doing srv update"; 19 timer->start(500);
15 updateMap(map);
16 }
17} 20}
18 21
19QMap< Color::Color, Actor::Movement > Server::getActorDirections() 22void Server::tick()
20{ 23{
21 QMap<Color::Color, Actor::Movement> directions; 24 qDebug() << "doing srv update";
22 directions[Color::red] = Actor::Down; 25 Transmission::map_t map = calculateUpdates();
23 return directions; 26 updateMap(map);
27
28 QSharedPointer<ProtoBuf::MapUpdate> packet = createUpdatePacket(map);
29 sendUpdate(packet);
24} 30}
25 31
26Transmission::map_t Server::calculateUpdates() 32Transmission::map_t Server::calculateUpdates()
27{ 33{
28 Transmission::map_t map = Util::createEmptyMap(); 34 Transmission::map_t map = Util::createEmptyMap();
29 35
30 QMap<Color::Color, Actor::Movement> directions = getActorDirections(); 36 QMapIterator<Color::Color, Actor::Movement> i(m_actorMovements);
31 QMapIterator<Color::Color, Actor::Movement> i(directions);
32 while (i.hasNext()) { 37 while (i.hasNext()) {
33 i.next(); 38 i.next();
34 Actor *actor = m_actors.value( i.key() ); 39 Actor *actor = m_actors.value( i.key() );
@@ -52,8 +57,83 @@ Transmission::map_t Server::calculateUpdates()
52 return map; 57 return map;
53} 58}
54 59
60QSharedPointer< ProtoBuf::MapUpdate > Server::createUpdatePacket(Transmission::map_t map)
61{
62 QSharedPointer<ProtoBuf::MapUpdate> updatePacket =
63 QSharedPointer<ProtoBuf::MapUpdate>(new ProtoBuf::MapUpdate);
64
65 for (unsigned int x = 0; x < Constants::map_size.width; ++x) {
66 for (unsigned int y = 0; y < Constants::map_size.height; ++y) {
67 updatePacket->add_field(map[x][y]);
68 }
69 }
70 //qDebug() << "field sz "<< updatePacket->field_size();
71 return updatePacket;
72}
73
74void Server::waitForClientConnections()
75{
76 QTcpServer *tcpSrv = new QTcpServer(this);
77 // server must stay alive as long as sockets (qt parent mem mechanism)
78 tcpSrv->listen(QHostAddress::Any, Constants::port);
79
80 //for (unsigned int i=0; i<Color::max; ++i) {
81 for (unsigned int i=0; i<1; ++i) {
82 bool connectionAvailable = tcpSrv->waitForNewConnection(-1);
83 Q_ASSERT(connectionAvailable);
84 QTcpSocket *socket = tcpSrv->nextPendingConnection();
85 // TODO: color assignment
86 m_clientConnections[Color::red] = socket;
87 connect(socket, SIGNAL(readyRead()), this, SLOT(keyPressUpdate()));
88 }
89}
90
91void Server::sendUpdate(QSharedPointer< ProtoBuf::MapUpdate > packet)
92{
93 std::string dataStr = packet->SerializeAsString();
94 const char *data = dataStr.c_str();
95 foreach(QTcpSocket *socket, m_clientConnections) {
96 //qDebug() << "sending str len: " << dataStr.length();
97 int bytesWritten = socket->write(data, dataStr.length());
98 Q_ASSERT(bytesWritten == dataStr.length());
99 }
100 foreach(QTcpSocket *socket, m_clientConnections) {
101 socket->flush();
102 }
103}
104
105void Server::keyPressUpdate()
106{
107 qDebug() << "kpress";
108 QMapIterator<Color::Color, QTcpSocket*> i(m_clientConnections);
109 while (i.hasNext()) {
110 i.next();
111 Color::Color color = i.key();
112 QTcpSocket *socket = i.value();
113 qDebug() << "data?";
114 if (socket->bytesAvailable() > 0) {
115 qDebug() << "data!";
116 QByteArray data = socket->readAll();
117 // see mainwidget.cpp:153
118 std::string dataStr;
119 for (int i = 0; i < data.size(); ++i) {
120 dataStr += data[i];
121 }
122 ProtoBuf::KeyPressUpdate packet;
123 packet.ParseFromString(dataStr);
124 Transmission::field_t direction = packet.newkey();
125 qDebug() << "data:" << direction;
126 m_actorMovements[ color ] = Util::transmissionMovementToActor(direction);
127 }
128 }
129
130}
131
132
55int main(int argc, char ** argv) 133int main(int argc, char ** argv)
56{ 134{
135 GOOGLE_PROTOBUF_VERIFY_VERSION;
136
57 QApplication app(argc, argv); 137 QApplication app(argc, argv);
58 app.setApplicationName("Pacman Server"); 138 app.setApplicationName("Pacman Server");
59 app.setWindowIcon(QIcon(":/appicon")); 139 app.setWindowIcon(QIcon(":/appicon"));
diff --git a/pacman-c++/server.h b/pacman-c++/server.h
index 006b104..6ffbb35 100644
--- a/pacman-c++/server.h
+++ b/pacman-c++/server.h
@@ -5,6 +5,9 @@
5 5
6#include <QtGui> 6#include <QtGui>
7#include "actor.h" 7#include "actor.h"
8#include "pacman.pb.h"
9
10class QTcpSocket;
8 11
9class Server 12class Server
10 : public SceneHolder 13 : public SceneHolder
@@ -13,13 +16,29 @@ class Server
13public: 16public:
14 Server(QWidget *parent = 0); 17 Server(QWidget *parent = 0);
15 18
19protected slots:
20 void tick();
21
22 // receive updates of client
23 void keyPressUpdate();
24
16protected: 25protected:
17 // returns packets read from network until now 26
18 // for clients not sending a direction, no change is assumed 27 // block until we have connections from all clients
19 QMap<Color::Color, Actor::Movement> getActorDirections(); 28 void waitForClientConnections();
20 29
21 // calculate updates of current tick for sending to client 30 // calculate updates of current tick for sending to client
22 Transmission::map_t calculateUpdates(); 31 Transmission::map_t calculateUpdates();
32
33 QSharedPointer<ProtoBuf::MapUpdate> createUpdatePacket(Transmission::map_t);
34
35 // update client maps
36 void sendUpdate(QSharedPointer< ProtoBuf::MapUpdate > );
37
38 QMap<Color::Color, QTcpSocket*> m_clientConnections;
39
40 // current movements. required to make pacmans continue their movement.
41 QMap<Color::Color, Actor::Movement> m_actorMovements;
23}; 42};
24 43
25#endif // SERVER_H 44#endif // SERVER_H
diff --git a/pacman-c++/util.cpp b/pacman-c++/util.cpp
index 99a643e..6b9780b 100644
--- a/pacman-c++/util.cpp
+++ b/pacman-c++/util.cpp
@@ -2,12 +2,16 @@
2 2
3namespace Util { 3namespace Util {
4 4
5 Transmission::map_t createEmptyMap() { 5 Transmission::map_t createUninitialisedMap() {
6 Transmission::map_t map; 6 Transmission::map_t map;
7 map = new Transmission::field_t*[Constants::map_size.width]; 7 map = new Transmission::field_t*[Constants::map_size.width];
8 for (unsigned int i = 0; i < Constants::map_size.width; ++i) 8 for (unsigned int i = 0; i < Constants::map_size.width; ++i)
9 map[i] = new Transmission::field_t[Constants::map_size.height]; 9 map[i] = new Transmission::field_t[Constants::map_size.height];
10 return map;
11 }
10 12
13 Transmission::map_t createEmptyMap() {
14 Transmission::map_t map = createUninitialisedMap();
11 for (unsigned int x = 0; x < Constants::map_size.width; ++x) 15 for (unsigned int x = 0; x < Constants::map_size.width; ++x)
12 { 16 {
13 for (unsigned int y = 0; y < Constants::map_size.height; ++y) 17 for (unsigned int y = 0; y < Constants::map_size.height; ++y)
diff --git a/pacman-c++/util.h b/pacman-c++/util.h
index 1754f54..8bd03bc 100644
--- a/pacman-c++/util.h
+++ b/pacman-c++/util.h
@@ -5,6 +5,8 @@
5#include "actor.h" 5#include "actor.h"
6 6
7namespace Util { 7namespace Util {
8 Transmission::map_t createUninitialisedMap();
9
8 Transmission::map_t createDummyMap(); 10 Transmission::map_t createDummyMap();
9 11
10 Transmission::map_t createEmptyMap(); 12 Transmission::map_t createEmptyMap();