summaryrefslogtreecommitdiffstats
path: root/libkdegames/kgame/kgamenetwork.h
blob: 6ff5cf9485795b2077a947b2f8a6310f4d5f32c8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
/*
    This file is part of the KDE games library
    Copyright (C) 2001 Martin Heni (martin@heni-online.de)
    Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de)

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/
/*
    $Id$
*/
#ifndef __KGAMENETWORK_H_
#define __KGAMENETWORK_H_

#include <qstring.h>
#include <qobject.h>
#include <kdemacros.h>
class KGameIO;
class KMessageClient;
class KMessageServer;

class KGameNetworkPrivate;

/**
 * The KGameNetwork class is the KGame class with network
 * support. All other features are the same but they are
 * now network transparent. It is not used directly but
 * only via a KGame object. So you do not really have
 * to bother with this object.
 *
 * @short The main KDE game object
 * @author Martin Heni <martin@heni-online.de>
 * @version $Id$
 */
class KDE_EXPORT KGameNetwork : public QObject
{
  Q_OBJECT

public:
    /**
     * Create a KGameNetwork object
     */
    KGameNetwork(int cookie=42,QObject* parent=0);
    virtual ~KGameNetwork();

    /**
     * Gives debug output of the game status
     **/
    virtual void Debug();

    /**
     * @return TRUE if this is a network game - i.e. you are either MASTER or
     * connected to a remote MASTER.
     **/
    bool isNetwork() const;

    /**
     * Is this the game MASTER (i.e. has started theKMessageServer). A
     * game has always exactly one MASTER. This is either a KGame object (i.e. a
     * Client) or an own MessageServer-process. A KGame object that has the
     * MASTER status is always admin.
     *
     * You probably don't want to use this. It is a mostly internal method which
     * will probably become protected. Better use isAdmin
     *
     * @see isAdmin
     * @return Whether this client has started the KMessageServer
     **/
    bool isMaster() const;

    /**
     * The admin of a game is the one who initializes newly connected clients
     * using  negotiateNetworkGame and is allowed to configure the game.
     * E.g. only the admin is allowed to use KGame::setMaxPlayers.
     *
     * If one KGame object in the game is MASTER then this client is the admin
     * as well. isMaster and isAdmin differ only if the KMessageServer
     * is running in an own process.
     * @return Whether this client (KGame object) is the admin
     **/
    bool isAdmin() const;

    /**
     * The unique ID of this game
     *
     * @return int id
     **/
    Q_UINT32 gameId() const;

    /**
     * Inits a network game as network MASTER. Note that if the
     * KMessageServer is not yet started it will be started here (see 
     * setMaster). Any existing connection will be disconnected.
     *
     * If you already offer connections the port is changed.
     *
     * @param port The port on which the service is offered
     * @return true if it worked
     **/
    bool offerConnections (Q_UINT16 port);
    
    /**
     * Announces game MASTER on network using DNS-SD. Clients then can discover it using
     * DNSSD::ServiceBrowser (or KGameConnectWidget) instead of manually entering 
     * IP address.
     * @param type service type (something like _kwin4._tcp). 
     * It should be unique for application.
     * @param name game name that will be displayed by clients.  If not
     * set hostname will be used. In case of name conflict -2, -3 and so on will be added to name.
     * @since 3.4
     **/
    void setDiscoveryInfo(const QString& type, const QString& name=QString::null);
    
    /**
     * Inits a network game as a network CLIENT
     *
     * @param host the host to which we want to connect
     * @param port the port we want to connect to
     *
     * @return true if connected
     **/
    bool connectToServer(const QString& host, Q_UINT16 port);

    /**
     * @since 3.2
     * @return The port we are listening to if offerConnections was called
     * or the port we are connected to if connectToServer was called.
     * Otherwise 0.
     **/
    Q_UINT16 port() const;

    /**
     * @since 3.2
     * @return The name of the host that we are currently connected to is
     * isNetwork is TRUE and we are not the MASTER, i.e. if connectToServer
     * was called. Otherwise this will return "localhost".
     **/
    QString hostName() const;

    /**
     * Stops offering server connections - only for game MASTER
     * @return true
     **/
    bool stopServerConnection();

    /**
     * Changes the maximal connection number of the KMessageServer to max.
     * -1 Means infinite connections are possible. Note that existing
     * connections are not affected, so even if you set this to 0 in a running
     * game no client is being disconnected. You can call this only if you are
     * the ADMIN!
     *
     * @see KMessageServer::setMaxClients
     * @param max The maximal number of connections possible.
     **/
    void setMaxClients(int max);

    //AB: is this now internal only? Can we make it protected (maybe with
    //friends)? sendSystemMessage AND sendMessage is very confusing to the
    //user.
    /**
     * Sends a network message msg with a given msg id msgid to all clients.
     * Use this to communicate with KGame (e.g. to add a player ot to configure
     * the game - usually not necessary). 
     *
     * For your own messages use  sendMessage instead! This is mostly
     * internal!
     *
     * @param buffer the message which will be send. See messages.txt for contents
     * @param msgid an id for this message. See
     * KGameMessage::GameMessageIds
     * @param receiver the KGame / KPlayer this message is for.
     * @param sender The KGame / KPlayer this message is from (i.e.
     * you). You
     * probably want to leave this 0, then KGameNetwork will create the correct
     * value for you. You might want to use this if you send a message from a
     * specific player.
     * @return true if worked
     */
    // AB: TODO: doc on how "receiver" and "sender" should be created!
    bool sendSystemMessage(const QByteArray& buffer, int msgid, Q_UINT32 receiver=0, Q_UINT32 sender=0);

    /**
     * @overload
     **/
    bool sendSystemMessage(int data, int msgid, Q_UINT32 receiver=0, Q_UINT32 sender=0);

    /**
     * @overload
     **/
    bool sendSystemMessage(const QDataStream &msg, int msgid, Q_UINT32 receiver=0, Q_UINT32 sender=0);

    /**
     * @overload
     **/
    bool sendSystemMessage(const QString& msg, int msgid, Q_UINT32 receiver=0, Q_UINT32 sender=0);

    /**
     * Sends a network message
     * @param error The error code
     * @param message The error message - use KGameError
     * @param receiver the KGame / KPlayer this message is for. 0 For
     * all
     * @param sender The KGame / KPlayer this message is from (i.e.
     * you). You probably want to leave this 0, then KGameNetwork will create 
     * the correct value for you. You might want to use this if you send a 
     * message from a specific player.
     **/
    void sendError(int error, const QByteArray& message, Q_UINT32 receiver=0, Q_UINT32 sender=0);

    /**
     * Are we still offer offering server connections - only for game MASTER
     * @return true/false
     **/
    bool isOfferingConnections() const;

    /**
     * Application cookie. this idendifies the game application. It
     * help to distinguish between e.g. KPoker and KWin4
     * @return the application cookie
     **/
    int cookie() const;

    /**
     * Send a network message msg with a given message ID msgid to all clients.
     * You want to use this to send a message to the clients.
     *
     * Note that a message is always sent to ALL clients! This is necessary so
     * that all clients always have the same data and can easily be changed from
     * network to non-network without restarting the game. If you want a
     * specific KGame / KPlayer to react to the message use the
     * receiver and sender parameters. See KGameMessage::calsMessageId
     *
     * SendMessage differs from sendSystemMessage only by the msgid parameter.
     * sendSystemMessage is thought as a KGame only mehtod while
     * sendMessage is for public use. The msgid parameter will be
     * +=KGameMessage::IdUser and in KGame::signalNetworkData msgid will
     * be -= KGameMessage::IdUser again, so that one can easily distinguish
     * between system and user messages.
     *
     * Use sendSystemMessage to comunicate with KGame (e.g. by adding a
     * player) and sendMessage for your own user message.
     *
     * Note: a player should send messages through a KGameIO!
     *
     * @param buffer the message which will be send. See messages.txt for contents
     * @param msgid an id for this message. See KGameMessage::GameMessageIds
     * @param receiver the KGame / KPlayer this message is for.
     * @param sender The KGame / KPlayer this message is from (i.e.
     * you). You
     * probably want to leave this 0, then KGameNetwork will create the correct
     * value for you. You might want to use this if you send a message from a
     * specific player.
     * @return true if worked
     **/
    // AB: TODO: doc on how "receiver" and "sender" should be created!
    bool sendMessage(const QByteArray& buffer, int msgid, Q_UINT32 receiver=0, Q_UINT32 sender=0);

    /**
     * This is an overloaded member function, provided for convenience.
     **/
    bool sendMessage(const QDataStream &msg, int msgid, Q_UINT32 receiver=0, Q_UINT32 sender=0);

    /**
     * This is an overloaded member function, provided for convenience.
     **/
    bool sendMessage(const QString& msg, int msgid, Q_UINT32 receiver=0, Q_UINT32 sender=0);

    /**
     * This is an overloaded member function, provided for convenience.
     **/
    bool sendMessage(int data, int msgid, Q_UINT32 receiver=0, Q_UINT32 sender=0);


    /**
     * Called by ReceiveNetworkTransmission(). Will be overwritten by
     * KGame and handle the incoming message.
     **/
    virtual void networkTransmission(QDataStream&, int, Q_UINT32, Q_UINT32, Q_UINT32 clientID) = 0;


    /**
     * Disconnect the current connection and establish a new local one.
     **/
    void disconnect();


    /**
     * If you are the ADMIN of the game you can give the ADMIN status away to
     * another client. Use this e.g. if you want to quit the game or if you want
     * another client to administrate the game (note that disconnect calls
     * this automatically).
     * @param clientID the ID of the new ADMIN (note: this is the _client_ID
     * which has nothing to do with the player IDs. See KMessageServer)
     **/
    void electAdmin(Q_UINT32 clientID);

    /**
     * Don't use this unless you really know what youre doing! You might
     * experience some strange behaviour if you send your messages directly
     * through the KMessageClient!
     *
     * @return a pointer to the KMessageClient used internally to send the
     * messages. You should rather use one of the send functions!
     **/
    KMessageClient* messageClient() const;

    /**
     * Don't use this unless you really know what you are doing! You might
     * experience some strange behaviour if you use the message server directly!
     *
     * @return a pointer to the message server if this is the MASTER KGame
     * object. Note that it might be possible that no KGame object contains
     * the KMessageServer at all! It might even run stand alone!
     **/
    KMessageServer* messageServer() const;

    /**
     * You should call this before doing thigs like, e.g. qApp->processEvents().
     * Don't forget to call unlock once you are done!
     * 
     * @see KMessageClient::lock
     **/
    virtual void lock();

    /**
     * @see KMessageClient::unlock
     **/
    virtual void unlock();

signals:
    /**
     * A network error occurred
     * @param error the error code
     * @param text the error text
     */
    void signalNetworkErrorMessage(int error, QString text);

    /**
     * Our connection to the KMessageServer has broken.
     * See KMessageClient::connectionBroken
     **/
    void signalConnectionBroken();

    /**
     * This signal is emitted whenever the KMessageServer sends us a message that a
     * new client connected. KGame uses this to call KGame::negotiateNetworkGame
     * for the newly connected client if we are admin (see isAdmin)
     *
     * @see KMessageClient::eventClientConnected
     *
     * @param clientID the ID of the newly connected client
     **/
    void signalClientConnected(Q_UINT32 clientID);

    /**
     * This signal is emitted whenever the KMessageServer sends us a message
     * that a connection to a client was detached. The second parameter can be used
     * to distinguish between network errors or removing on purpose.
     *
     * @see KMessageClient::eventClientDisconnected
     *
     * @param clientID the client that has disconnected
     * @param broken true if the connection was lost because of a network error, false
     *        if the connection was closed by the message server admin.
     */
    void signalClientDisconnected(Q_UINT32 clientID, bool broken);

    /**
     * This client gets or loses the admin status.
     * @see KMessageClient::adminStatusChanged
     * @param isAdmin True if this client gets the ADMIN status otherwise FALSE
     **/
    void signalAdminStatusChanged(bool isAdmin);

protected:
    /**
     * @internal
     * Start a KMessageServer object and use it as the MASTER of the game.
     * Note that you must not call this if there is already another master
     * running!
     **/
    void setMaster();

protected slots:
    /**
     * Called by KMessageClient::broadcastReceived() and will check if the
     * message format is valid. If it is not, it will generate an error (see
     * signalNetworkVersionError and signalNetworkErorrMessage).
     * If it is valid, the pure virtual method networkTransmission() is called.
     * (This one is overwritten in KGame.)
     **/
    void receiveNetworkTransmission(const QByteArray& a, Q_UINT32 clientID);

    /**
     * This KGame object receives or loses the admin status.
     * @param isAdmin Whether we are admin or not
     **/
    void slotAdminStatusChanged(bool isAdmin);

    /**
     * Called when the network connection is about to terminate. Is used
     * to store the network parameter like the game id
     */
     void aboutToLoseConnection(Q_UINT32 id);

    /**
     * Called when the network connection is terminated. Used to clean
     * up the disconnect parameter
     */
     void slotResetConnection();


private:
     void tryPublish();
     void tryStopPublishing();
     KGameNetworkPrivate* d;
};

#endif