~ubuntu-branches/debian/sid/monopd/sid

« back to all changes in this revision

Viewing changes to .pc/01_gcc43_includes.diff/src/server.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Schepler
  • Date: 2011-07-18 22:07:44 UTC
  • Revision ID: james.westby@ubuntu.com-20110718220744-bg6e0yij97p8xxno
Tags: 0.9.3-5
* Orphaning package (see #634499).
* Bump Standards-Version to 3.9.2.
* Update to 3.0 (quilt) source format.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) 2001-2004 Rob Kaper <cap@capsi.com>,
 
2
//               2001 Erik Bourget <ebourg@cs.mcgill.ca>
 
3
//
 
4
// This program is free software; you can redistribute it and/or
 
5
// modify it under the terms of the GNU General Public License
 
6
// version 2 as published by the Free Software Foundation.
 
7
//
 
8
// This program is distributed in the hope that it will be useful,
 
9
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
11
// General Public License for more details.
 
12
//
 
13
// You should have received a copy of the GNU General Public License
 
14
// along with this program; see the file COPYING.  If not, write to
 
15
// the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
16
// Boston, MA 02111-1307, USA.
 
17
 
 
18
#include <dirent.h>
 
19
#include <netdb.h>
 
20
#include <stdio.h>
 
21
#include <stdarg.h>
 
22
#include <sys/time.h>
 
23
#include <sys/socket.h>
 
24
#include <sys/types.h>
 
25
#include <netinet/in.h>
 
26
#include <syslog.h>
 
27
#include <unistd.h>
 
28
 
 
29
#include <string>
 
30
 
 
31
#include <libcapsinetwork/socket.h>
 
32
 
 
33
#include "const.h"
 
34
#include "auction.h"
 
35
#include "event.h"
 
36
#include "game.h"
 
37
#include "gameobject.h"
 
38
#include "gameconfig.h"
 
39
#include "io.h"
 
40
#include "player.h"
 
41
#include "server.h"
 
42
 
 
43
MonopdServer::MonopdServer() : GameObject(0)
 
44
{
 
45
        m_nextGameId = m_nextPlayerId = 1;
 
46
        m_gatorIdentity = "";
 
47
        m_port = 1234;
 
48
        m_gatorHost = "monopd.unixcode.org";
 
49
        m_gatorPort = 80;
 
50
        m_gatorFrequency = 60;
 
51
        m_useMonopigator = false;
 
52
        m_monopigatorEvent = 0;
 
53
 
 
54
        loadConfig();
 
55
        loadGameTemplates();
 
56
}
 
57
 
 
58
void MonopdServer::setPort(int port)
 
59
{
 
60
        m_port = port;
 
61
}
 
62
 
 
63
MonopdServer::~MonopdServer()
 
64
{
 
65
        // We are responsible for the objects allocated
 
66
        while (!m_events.empty()) { delete *m_events.begin(); m_events.erase(m_events.begin()); }
 
67
        while (!m_games.empty()) { delete *m_games.begin(); m_games.erase(m_games.begin()); }
 
68
        while (!m_gameConfigs.empty()) { delete *m_gameConfigs.begin(); m_gameConfigs.erase(m_gameConfigs.begin()); }
 
69
        while (!m_players.empty()) { delete *m_players.begin(); m_players.erase(m_players.begin()); }
 
70
}
 
71
 
 
72
Event *MonopdServer::newEvent(unsigned int eventType, Game *game, int id)
 
73
{
 
74
        Event *newEvent = new Event(id, (Event::EventType)eventType, game);
 
75
        m_events.push_back(newEvent);
 
76
        printf("newEvent %d/%d\n", id, m_events.size());
 
77
        return newEvent;
 
78
}
 
79
 
 
80
void MonopdServer::delEvent(Event *event)
 
81
{
 
82
        for(std::vector<Event *>::iterator it = m_events.begin(); it != m_events.end() && (*it) ; ++it)
 
83
                if (*it == event)
 
84
                {
 
85
                        printf("delEvent %d/%d\n", event->id(), m_events.size()-1);
 
86
                        delete event;
 
87
                        m_events.erase(it);
 
88
                        break;
 
89
                }
 
90
}
 
91
 
 
92
Event *MonopdServer::findEvent(Game *game, unsigned int eventType)
 
93
{
 
94
        Event *event = 0;
 
95
        for(std::vector<Event *>::iterator it = m_events.begin(); it != m_events.end() && (event = *it) ; ++it)
 
96
                if (event->game() == game && event->type() == eventType)
 
97
                        return event;
 
98
 
 
99
        return 0;
 
100
}
 
101
 
 
102
Event *MonopdServer::findEvent(Game *game, GameObject *object)
 
103
{
 
104
        for(std::vector<Event *>::iterator it = m_events.begin(); it != m_events.end() && (*it) ; ++it)
 
105
                if ( (*it)->game() == game && (*it)->object() == object)
 
106
                        return (*it);
 
107
 
 
108
        return 0;
 
109
}
 
110
 
 
111
void MonopdServer::newGame(Player *player, const std::string gameType)
 
112
{
 
113
        Game *game = new Game(m_nextGameId++);
 
114
        m_games.push_back(game);
 
115
 
 
116
        game->setProperty("name", (gameType.size() ? gameType : "atlantic"), this);
 
117
 
 
118
        // Hardcoded reasonable defaults, which also ensure the entire server is the scope
 
119
        game->setProperty("master", -1, this); // addPlayer will set the correct playerid
 
120
        game->setProperty("description", "", this);
 
121
        game->setProperty("minplayers", 1, this);
 
122
        game->setProperty("maxplayers", 1, this);
 
123
        game->setProperty("players", 0, this);
 
124
        game->setBoolProperty("canbejoined", true, this);
 
125
 
 
126
        game->loadGameType(gameType);
 
127
 
 
128
        if (!game->isValid())
 
129
        {
 
130
                delGame(game, false);
 
131
                player->ioWrite("<monopd><msg type=\"error\" value=\"Could not load valid configuration for gametype %s.\"/></monopd>\n", gameType.c_str());
 
132
                m_nextGameId--;
 
133
                return;
 
134
        }
 
135
 
 
136
        syslog( LOG_INFO, "new game: id=[%d], type=[%s], games=[%d]", game->id(), gameType.c_str(), m_games.size() );
 
137
 
 
138
        game->addPlayer(player, true);
 
139
 
 
140
        // FIXME: DEPRECATED 1.0
 
141
        ioWrite(std::string("<monopd><updategamelist type=\"add\"><game id=\"") + itoa(game->id()) + "\" players=\"1\" gametype=\"" + game->gameType() + "\" name=\"" + game->name() + "\" description=\"" + game->getStringProperty("description") + "\" canbejoined=\"" + itoa(game->getBoolProperty("canbejoined")) + "\"/></updategamelist></monopd>\n");
 
142
}
 
143
 
 
144
void MonopdServer::joinGame(Player *pInput, unsigned int gameId, const bool &spectator)
 
145
{
 
146
        Game *game = findGame(gameId);
 
147
        if (!game)
 
148
        {
 
149
                pInput->ioError("There is no game with id %ld.", gameId);
 
150
                return;
 
151
        }
 
152
 
 
153
        if ( spectator )
 
154
        {
 
155
                GameObject *config = game->findConfigOption( "allowspectators" );
 
156
                if ( config && config->getBoolProperty( "value" ) && game->status() == Game::Run )
 
157
                {
 
158
                        game->addPlayer( pInput, false, true );
 
159
                        game->ioInfo("%s joins as spectator.", pInput->name().c_str());
 
160
                }
 
161
                else
 
162
                        pInput->ioError("Game %ld doesn't allow spectators.", gameId);
 
163
                return;
 
164
        }
 
165
 
 
166
        int maxPlayers = game->getIntProperty("maxplayers");
 
167
        if (game->players() >= maxPlayers)
 
168
        {
 
169
                pInput->ioError("This game already has the maximum of %d players.", maxPlayers);
 
170
                return;
 
171
        }
 
172
 
 
173
        if (game->status() != Game::Config)
 
174
        {
 
175
                pInput->ioError("You cannot join game %d, it is already in progress.", game->id());
 
176
                return;
 
177
        }
 
178
 
 
179
        game->addPlayer(pInput);
 
180
 
 
181
        // FIXME: DEPRECATED 1.0
 
182
        ioWrite(std::string("<monopd><updategamelist type=\"edit\"><game id=\"") + itoa(game->id()) + "\" players=\"" + itoa(game->players()) + "\" canbejoined=\"" + itoa(game->getBoolProperty("canbejoined")) + "\"/></updategamelist></monopd>\n");
 
183
}
 
184
 
 
185
void MonopdServer::exitGame(Game *game, Player *pInput)
 
186
{
 
187
        game->removePlayer(pInput);
 
188
        if (game->connectedPlayers() == 0)
 
189
                delGame(game);
 
190
 
 
191
        pInput->reset();
 
192
 
 
193
        // Send new game list
 
194
        sendGameList(pInput);
 
195
}
 
196
 
 
197
Game *MonopdServer::findGame(unsigned int gameId)
 
198
{
 
199
        Game *game = 0;
 
200
        for(std::vector<Game *>::iterator it = m_games.begin(); it != m_games.end() && (game = *it) ; ++it)
 
201
                if (game->id() == gameId)
 
202
                        return game;
 
203
 
 
204
        return 0;
 
205
}
 
206
 
 
207
void MonopdServer::delGame(Game *game, bool verbose)
 
208
{
 
209
        if (verbose)
 
210
                ioWrite("<monopd><deletegame gameid=\"" + itoa(game->id()) + "\"/></monopd>\n");
 
211
 
 
212
        // Remove everyone from the game
 
213
        while (game->players())
 
214
        {
 
215
                Player *player = 0;
 
216
                for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (player = *it) ; ++it)
 
217
                        if (player->game() == game)
 
218
                        {
 
219
                                game->removePlayer(player);
 
220
                                delPlayer(player);
 
221
                                break;
 
222
                        }
 
223
        }
 
224
 
 
225
        // Remove events from game
 
226
        for(std::vector<Event *>::iterator it = m_events.begin(); it != m_events.end() && (*it) ; ++it)
 
227
        {
 
228
                if ( (*it)->game() == game )
 
229
                {
 
230
                        delEvent( (*it) );
 
231
                        it = m_events.begin();
 
232
                        continue;
 
233
                }
 
234
        }
 
235
 
 
236
        // Remove game
 
237
        for(std::vector<Game *>::iterator it = m_games.begin(); it != m_games.end() && (*it) ; ++it)
 
238
                if (*it == game)
 
239
                {
 
240
                        // FIXME: DEPRECATED 1.0
 
241
                        if (verbose)
 
242
                                ioWrite(std::string("<monopd><updategamelist type=\"del\"><game id=\"") + itoa(game->id()) + "\"/></updategamelist></monopd>\n");
 
243
                        syslog( LOG_INFO, "del game: id=[%d], games=[%d]", game->id(), m_games.size() - 1 );
 
244
                        m_games.erase(it);
 
245
                        break;
 
246
                }
 
247
        delete game;
 
248
}
 
249
 
 
250
void MonopdServer::setGameDescription(Player *pInput, const std::string data)
 
251
{
 
252
        Game *game = pInput->game();
 
253
        if (pInput == game->master())
 
254
        {
 
255
                game->setProperty("description", data);
 
256
 
 
257
                // FIXME: DEPRECATED 1.0
 
258
                ioWrite("<monopd><updategamelist type=\"edit\"><game id=\"" + itoa(game->id()) + "\" gametype=\"" + game->gameType() + "\" name=\"" + game->name() + "\" description=\"" + game->getStringProperty("description") + "\"/></updategamelist></monopd>\n");
 
259
        }
 
260
        else
 
261
                pInput->ioError("Only the master can set the game description!");
 
262
}
 
263
 
 
264
Player *MonopdServer::newPlayer(Socket *socket, const std::string &name)
 
265
{
 
266
        // Players completed the handshake, delete socket timeout event
 
267
        delSocketTimeoutEvent( socket->fd() );
 
268
 
 
269
        Player *player = new Player(socket, m_nextPlayerId++);
 
270
        m_players.push_back(player);
 
271
        addToScope(player);
 
272
 
 
273
        player->setProperty("game", -1, this);
 
274
        player->setProperty("host", socket->fqdn(), this);
 
275
        setPlayerName(player, name);
 
276
 
 
277
        player->sendClientMsg();
 
278
        sendGameList(player, true);
 
279
 
 
280
        syslog( LOG_INFO, "new player: id=[%d], fd=[%d], name=[%s], players=[%d]", player->id(), socket->fd(), name.c_str(), m_players.size() );
 
281
        player = 0;
 
282
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (player = *it) ; ++it)
 
283
                printf("  player %16s %16s game %d bankrupt %d socket %d fd %d\n", player->name().c_str(), player->getStringProperty("host").c_str(), (player->game() ? player->game()->id() : -1), player->getBoolProperty("bankrupt"), player->socket(), player->socket() ? (int)player->socket()->fd() : -1);
 
284
 
 
285
        // Re-register to meta server with updated player count.
 
286
        registerMonopigator();
 
287
        if (m_monopigatorEvent)
 
288
                m_monopigatorEvent->setLaunchTime(time(0) + m_monopigatorEvent->frequency() );
 
289
 
 
290
        return player;
 
291
}
 
292
 
 
293
void MonopdServer::reconnectPlayer(Player *pInput, const std::string &cookie)
 
294
{
 
295
        Player *player = findCookie(cookie);
 
296
        if (!player)
 
297
        {
 
298
                pInput->ioError("Invalid cookie.");
 
299
                return;
 
300
        }
 
301
 
 
302
        Game *game = player->game();
 
303
        if (game)
 
304
        {
 
305
                if (player->socket())
 
306
                        pInput->ioError("Cannot reconnect, target player already has a socket.");
 
307
                else
 
308
                {
 
309
                        pInput->ioInfo("Reconnecting.");
 
310
                        player->setSocket(pInput->socket());
 
311
                        player->sendClientMsg();
 
312
                        sendGameList(player, true);
 
313
                        if (game->status() == Game::Run)
 
314
                        {
 
315
                                game->setStatus(Game::Init);
 
316
                                game->sendFullUpdate(player);
 
317
                                game->setStatus(Game::Run);
 
318
                                game->sendStatus(player);
 
319
                        }
 
320
                        else
 
321
                                game->sendFullUpdate(player);
 
322
 
 
323
                        game->ioInfo("%s reconnected.", player->name().c_str());
 
324
                        pInput->setSocket(0);
 
325
                        delPlayer(pInput);
 
326
                }
 
327
        }
 
328
}
 
329
 
 
330
void MonopdServer::delPlayer(Player *player)
 
331
{
 
332
        // Delete timeout event, if present.
 
333
        Game *game = player ? player->game() : 0;
 
334
        if ( player && game )
 
335
        {
 
336
                Event *event = findEvent( game, dynamic_cast<GameObject *> (player) );
 
337
                if ( event )
 
338
                {
 
339
                        printf("cleared event for player\n");
 
340
                        event->setObject( 0 );
 
341
                }
 
342
                game->removePlayer( player );
 
343
        }
 
344
 
 
345
        ioWrite("<monopd><deleteplayer playerid=\"" + itoa(player->id()) + "\"/></monopd>\n");
 
346
 
 
347
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (*it) ; ++it)
 
348
                if (*it == player)
 
349
                {
 
350
                        removeFromScope(player);
 
351
                        syslog( LOG_INFO, "del player: id=[%d], fd=[%d], name=[%s], players=[%d]", player->id(), player->socket() ? player->socket()->fd() : 0, player->getStringProperty("name").c_str(), m_players.size() - 1 );
 
352
                        printf("delPlayer %d/%d\n", player->id(), m_players.size()-1);
 
353
                        delete player;
 
354
                        m_players.erase(it);
 
355
                        player = 0;
 
356
                        break;
 
357
                }
 
358
 
 
359
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (player = *it) ; ++it)
 
360
                printf("  player %16s %16s game %d bankrupt %d socket %d fd %d\n", player->name().c_str(), player->getStringProperty("host").c_str(), (player->game() ? player->game()->id() : -1), player->getBoolProperty("bankrupt"), player->socket(), player->socket() ? (int)player->socket()->fd() : -1);
 
361
 
 
362
        // Re-register to meta server with updated player count.
 
363
        registerMonopigator();
 
364
        if (m_monopigatorEvent)
 
365
                m_monopigatorEvent->setLaunchTime(time(0) + m_monopigatorEvent->frequency() );
 
366
}
 
367
 
 
368
Player *MonopdServer::findPlayer(int playerId)
 
369
{
 
370
        Player *player = 0;
 
371
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (player = *it) ; ++it)
 
372
                if (player->id() == playerId)
 
373
                        return player;
 
374
 
 
375
        return 0;
 
376
}
 
377
 
 
378
Player *MonopdServer::findPlayer(Socket *socket)
 
379
{
 
380
        Player *player = 0;
 
381
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (player = *it) ; ++it)
 
382
                if (player->socket() == socket)
 
383
                        return player;
 
384
 
 
385
        return 0;
 
386
}
 
387
 
 
388
Player *MonopdServer::findPlayer(const std::string &name)
 
389
{
 
390
        Player *player = 0;
 
391
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (player = *it) ; ++it)
 
392
                if (player->getStringProperty("name") == name)
 
393
                        return player;
 
394
 
 
395
        return 0;
 
396
}
 
397
 
 
398
Player *MonopdServer::findCookie(const std::string &cookie)
 
399
{
 
400
        Player *player = 0;
 
401
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (player = *it) ; ++it)
 
402
                if (player->getStringProperty("cookie") == cookie)
 
403
                        return player;
 
404
 
 
405
        return 0;
 
406
}
 
407
 
 
408
GameConfig *MonopdServer::newGameConfig(const std::string id, const std::string name, const std::string description)
 
409
{
 
410
        GameConfig *newGameConfig = new GameConfig(id, name, description);
 
411
        m_gameConfigs.push_back(newGameConfig);
 
412
        syslog( LOG_INFO, "loaded game configuration: game=[%s]", name.c_str() );
 
413
        return newGameConfig;
 
414
}
 
415
 
 
416
void MonopdServer::delGameConfig(GameConfig *gameConfig)
 
417
{
 
418
        for(std::vector<GameConfig *>::iterator it = m_gameConfigs.begin(); it != m_gameConfigs.end() && (*it) ; ++it)
 
419
                if (*it == gameConfig)
 
420
                {
 
421
                        delete gameConfig;
 
422
                        m_gameConfigs.erase(it);
 
423
                        break;
 
424
                }
 
425
}
 
426
 
 
427
void MonopdServer::closedSocket(Socket *socket)
 
428
{
 
429
        Player *pInput = findPlayer(socket);
 
430
        if (!pInput)
 
431
        {
 
432
                // Delete socket timeout event, socket is closed already
 
433
                delSocketTimeoutEvent( socket->fd() );
 
434
                return;
 
435
        }
 
436
 
 
437
        Game *game = pInput->game();
 
438
        if (!game)
 
439
        {
 
440
                delPlayer(pInput);
 
441
                return;
 
442
        }
 
443
 
 
444
        pInput->setSocket( 0 );
 
445
        printf("%s socket 0 spec %d, bank %d, gamerun %d\n", pInput->name().c_str(), pInput->getBoolProperty("spectator"), pInput->getBoolProperty("bankrupt"), game->status() == Game::Run );
 
446
        game->ioInfo("Connection with %s lost.", pInput->name().c_str());
 
447
        
 
448
        // Only remove from game when game not running, or when it's merely a spectator.
 
449
        bool exitFromGame = false;
 
450
        if (game->status() == Game::Run)
 
451
        {
 
452
                if ( pInput->getBoolProperty("spectator") )
 
453
                        exitFromGame = true;
 
454
                else if ( !pInput->getBoolProperty("bankrupt") )
 
455
                {
 
456
                        printf("may reconnect\n");
 
457
                        unsigned int timeout = 180;
 
458
                        game->ioInfo("Player has %ds to reconnect until bankruptcy.", timeout);
 
459
                        Event *event = newEvent( Event::PlayerTimeout, game );
 
460
                        event->setLaunchTime(time(0) + timeout);
 
461
                        event->setObject( dynamic_cast<GameObject *> (pInput) );
 
462
                }
 
463
        }
 
464
        else
 
465
                exitFromGame = true;
 
466
        
 
467
        if (exitFromGame)
 
468
        {
 
469
                printf("exit from game %d: %d\n", game->id(), pInput->id());
 
470
                exitGame(game, pInput);
 
471
                printf("delplayer %d\n", pInput->id());
 
472
                delPlayer(pInput);
 
473
        }
 
474
}
 
475
 
 
476
int MonopdServer::processEvents()
 
477
{
 
478
        struct timeval tv;
 
479
        gettimeofday(&tv, NULL);
 
480
 
 
481
        int returnvalue = -1;
 
482
        Event *event = 0;
 
483
        for (std::vector<Event *>::iterator it = m_events.begin() ; it != m_events.end() && (event = *it) ; ++it)
 
484
        {
 
485
                if (tv.tv_sec >= event->launchTime())
 
486
                {
 
487
                        Game *game = event->game();
 
488
                        switch(event->type())
 
489
                        {
 
490
                        case Event::TokenMovementTimeout:
 
491
                                if (game)
 
492
                                {
 
493
                                        game->tokenMovementTimeout();
 
494
                                        if ( game->clientsMoving() )
 
495
                                                event->setFrequency( 1 );
 
496
                                        else
 
497
                                                event->setFrequency( 0 );
 
498
                                }
 
499
                                else
 
500
                                        event->setFrequency( 0 );
 
501
                                break;
 
502
                        case Event::SocketTimeout:
 
503
                                returnvalue = event->id();
 
504
                                break;
 
505
                        case Event::AuctionTimeout:
 
506
                                if (game)
 
507
                                {
 
508
                                        unsigned int frequency = game->auctionTimeout();
 
509
                                        event->setFrequency(frequency);
 
510
                                }
 
511
                                break;
 
512
                        case Event::Monopigator:
 
513
                                registerMonopigator();
 
514
                                break;
 
515
                        case Event::PlayerTimeout:
 
516
                                GameObject *object = event->object();
 
517
                                if (!object)
 
518
                                        break;
 
519
 
 
520
                                Player *player;
 
521
                                player = findPlayer(object->id());
 
522
                                if (player)
 
523
                                {
 
524
                                        if (player->socket())
 
525
                                        break;
 
526
 
 
527
                                        Game *game = player->game();
 
528
                                        if (game->status() == Game::Run)
 
529
                                        {
 
530
                                                game->ioInfo("%s did not reconnect in time and is now bankrupt.", player->name().c_str());
 
531
                                                game->bankruptPlayer(player);
 
532
                                        }
 
533
                                        else
 
534
                                        {
 
535
                                                // Game might have ended, silently remove.
 
536
                                                exitGame(game, player);
 
537
                                                // Event might have been deleted now.
 
538
                                                event = 0;
 
539
 
 
540
                                                delPlayer(player);
 
541
                                        }
 
542
                                }
 
543
                                if ( event )
 
544
                                        event->setObject(0);
 
545
                                break;
 
546
                        }
 
547
 
 
548
                        if ( event )
 
549
                        {
 
550
                                // Delete event from event list
 
551
                                int frequency = event->frequency();
 
552
                                if (frequency)
 
553
                                        event->setLaunchTime(time(0) + frequency);
 
554
                                else
 
555
                                {
 
556
                                        delEvent(event);
 
557
                                        break; // can't use continue, damn vectors
 
558
                                }
 
559
                        }
 
560
                        else
 
561
                                break;
 
562
                } 
 
563
        }
 
564
        sendXMLUpdates();
 
565
        return returnvalue;
 
566
}
 
567
 
 
568
void MonopdServer::registerMonopigator()
 
569
{
 
570
        int ircsock;
 
571
        struct sockaddr_in sin;
 
572
        struct hostent *hp = gethostbyname(m_gatorHost.c_str());        
 
573
        if (!hp)
 
574
                return;
 
575
 
 
576
        bzero((char *) &sin, sizeof(sin));
 
577
        bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length);
 
578
        sin.sin_family = hp->h_addrtype;
 
579
        sin.sin_port = htons(m_gatorPort);
 
580
        ircsock = socket(AF_INET, SOCK_STREAM, 0);
 
581
        if (connect(ircsock, (struct sockaddr *) & sin, sizeof(sin)))
 
582
                return;
 
583
 
 
584
        std::string getStr = std::string("GET /register.php?host=") + m_gatorIdentity + "&port=" + itoa(m_port) + "&version=" + escapeHTML(MONOPD_VERSION_STRING) + "&users=" + itoa(m_players.size()) + " HTTP/1.1\nHost:" + m_gatorHost + "\nUser-Agent: monopd/" + MONOPD_VERSION_STRING + "\n\n";
 
585
        if (ircsock)
 
586
        {
 
587
                write(ircsock, getStr.c_str(), strlen(getStr.c_str()));
 
588
                close(ircsock);
 
589
        }
 
590
}
 
591
 
 
592
void MonopdServer::loadConfig()
 
593
{
 
594
        FILE *f = fopen(MONOPD_CONFIGDIR "/monopd.conf", "r");
 
595
        if (!f)
 
596
        {
 
597
                syslog( LOG_WARNING, "cannot open configuration: file=[%s]", MONOPD_CONFIGDIR "/monopd.conf" );
 
598
                return;
 
599
        }
 
600
 
 
601
        char str[1024], *buf;
 
602
 
 
603
        fgets(str, sizeof(str), f);
 
604
        while(!feof(f))
 
605
        {
 
606
                if (str[0]=='#') {}
 
607
                else if (strstr(str, "="))
 
608
                {
 
609
                        buf = strtok(str, "=");
 
610
                        if (!strcmp(buf, "gatorfrequency"))
 
611
                                m_gatorFrequency = atoi(strtok(NULL, "\n\0"));
 
612
                        else if (!strcmp(buf, "gatorhost"))
 
613
                                m_gatorHost = strtok(NULL, "\n\0");
 
614
                        else if (!strcmp(buf, "gatoridentity"))
 
615
                        {
 
616
                                m_gatorIdentity = strtok(NULL, "\n\0");
 
617
                                m_useMonopigator = true;
 
618
                        }
 
619
                        else if (!strcmp(buf, "port"))
 
620
                                setPort(atoi(strtok(NULL, "\n\0")));
 
621
                        else if (!strcmp(buf, "gatorport"))
 
622
                                m_gatorPort = atoi(strtok(NULL, "\n\0"));
 
623
                }
 
624
                fgets(str, sizeof(str), f);
 
625
        }
 
626
        fclose(f);
 
627
 
 
628
        if (m_gatorFrequency < 60)
 
629
                m_gatorFrequency = 60;
 
630
}
 
631
 
 
632
void MonopdServer::loadGameTemplates()
 
633
{
 
634
        DIR *dirp;
 
635
        FILE *f;
 
636
        char str[256], *buf;
 
637
        struct dirent *direntp;
 
638
        std::string name = "", description = "";
 
639
        
 
640
        dirp = opendir(MONOPD_DATADIR "/games/");
 
641
        if (!dirp)
 
642
        {
 
643
                syslog( LOG_ERR, "cannot open game directory, dir=[%s]", MONOPD_DATADIR "/games/" );
 
644
                return;
 
645
        }
 
646
        while ((direntp=readdir(dirp)) != NULL)
 
647
        {
 
648
                if (strstr(direntp->d_name, ".conf"))
 
649
                {
 
650
                        std::string filename = std::string(MONOPD_DATADIR) + "/games/" + direntp->d_name;
 
651
                        f = fopen(filename.c_str(), "r");
 
652
                        if (!f)
 
653
                        {
 
654
                                syslog( LOG_WARNING, "cannot open game configuration: file=[%s/%s]", MONOPD_DATADIR "/games", filename.c_str() );
 
655
                                continue;
 
656
                        }
 
657
 
 
658
                        fgets(str, sizeof(str), f);
 
659
                        while (!feof(f))
 
660
                        {
 
661
                                if (str[0]=='#') {}
 
662
                                else if (strstr(str, "="))
 
663
                                {
 
664
                                        buf = strtok(str, "=");
 
665
                                        if (!strcmp(buf, "name"))
 
666
                                                name = strtok(NULL, "\n\0");
 
667
                                        else if (!strcmp(buf, "description"))
 
668
                                                description = strtok(NULL, "\n\0");
 
669
                                }
 
670
                                fgets(str, sizeof(str), f);
 
671
                        }
 
672
                        fclose(f);
 
673
 
 
674
                        newGameConfig(strtok(direntp->d_name, "."), (name.size() ? name : strtok(direntp->d_name, ".")), (description.size() ? description : "No description available"));
 
675
                        name = "";
 
676
                        description = "";
 
677
                }
 
678
        }
 
679
        closedir(dirp);
 
680
}
 
681
 
 
682
void MonopdServer::initMonopigatorEvent()
 
683
{
 
684
        if (m_useMonopigator==true)
 
685
        {
 
686
                // Register Monopigator event
 
687
                m_monopigatorEvent = newEvent(Event::Monopigator);
 
688
                m_monopigatorEvent->setLaunchTime(time(0));
 
689
                m_monopigatorEvent->setFrequency(m_gatorFrequency);
 
690
        }
 
691
}
 
692
 
 
693
void MonopdServer::initSocketTimeoutEvent(int socketFd)
 
694
{
 
695
                Event *socketTimeout = newEvent(Event::SocketTimeout, 0, socketFd);
 
696
                socketTimeout->setLaunchTime(time(0) + 30);
 
697
}
 
698
 
 
699
void MonopdServer::delSocketTimeoutEvent(int socketFd)
 
700
{
 
701
        Event *event = 0;
 
702
        for(std::vector<Event *>::iterator it = m_events.begin(); it != m_events.end() && (event = *it) ; ++it)
 
703
                if (event->id() == socketFd)
 
704
                {
 
705
                        delEvent(event);
 
706
                        return;
 
707
                }
 
708
}
 
709
 
 
710
void MonopdServer::ioWrite(const char *fmt, ...)
 
711
{
 
712
        int n, size = 256;
 
713
        char *buf = new char[size];
 
714
        static std::string ioStr;
 
715
        va_list arg;
 
716
 
 
717
        buf[0] = 0;
 
718
 
 
719
        while (1)
 
720
        {
 
721
                va_start(arg, fmt);
 
722
                n = vsnprintf(buf, size, fmt, arg);
 
723
                va_end(arg);
 
724
 
 
725
                if (n > -1 && n < size)
 
726
                {
 
727
                        ioStr = buf;
 
728
                        delete[] buf;
 
729
                        ioWrite(ioStr);
 
730
                        return;
 
731
                }
 
732
 
 
733
                if (n > -1)
 
734
                        size = n+1;
 
735
                else
 
736
                        size *= 2;
 
737
 
 
738
                delete[] buf;
 
739
                buf = new char[size];
 
740
        }
 
741
}
 
742
 
 
743
void MonopdServer::ioWrite(const std::string &data, const bool &noGameOnly)
 
744
{
 
745
        Player *player = 0;
 
746
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (player = *it) ; ++it)
 
747
                if ( !(noGameOnly && player->game()) )
 
748
                        player->ioWrite(data);
 
749
}
 
750
 
 
751
void MonopdServer::sendGameList(Player *pInput, const bool &sendTemplates)
 
752
{
 
753
        pInput->ioWrite("<monopd>");
 
754
 
 
755
        // Supported game types for new games   
 
756
        GameConfig *gcTmp = 0;
 
757
        if (sendTemplates)
 
758
                for(std::vector<GameConfig *>::iterator it = m_gameConfigs.begin() ; it != m_gameConfigs.end() && (gcTmp = *it) ; ++it )
 
759
                        pInput->ioWrite("<gameupdate gameid=\"-1\" gametype=\"%s\" name=\"%s\" description=\"%s\"/>", gcTmp->id().c_str(), gcTmp->name().c_str(), gcTmp->description().c_str());
 
760
 
 
761
        // FIXME: DEPRECATED 1.0
 
762
        pInput->ioWrite("<updategamelist type=\"full\">");
 
763
 
 
764
        // Supported game types for new games (always send, type=full)
 
765
        gcTmp = 0;
 
766
        for(std::vector<GameConfig *>::iterator it = m_gameConfigs.begin() ; it != m_gameConfigs.end() && (gcTmp = *it) ; ++it )
 
767
                pInput->ioWrite("<game id=\"-1\" gametype=\"%s\" name=\"%s\" description=\"%s\"/>", gcTmp->id().c_str(), gcTmp->name().c_str(), gcTmp->description().c_str());
 
768
 
 
769
        // Games currently under configuration, we can join these
 
770
        Game *gTmp = 0;
 
771
        for(std::vector<Game *>::iterator it = m_games.begin(); it != m_games.end() && (gTmp = *it) ; ++it)
 
772
                if (gTmp->status() == Game::Config)
 
773
                        pInput->ioWrite("<game id=\"%ld\" players=\"%d\" gametype=\"%s\" name=\"%s\" description=\"%s\" canbejoined=\"%d\"/>", gTmp->id(), gTmp->players(), gTmp->gameType().c_str(), gTmp->name().c_str(), gTmp->getStringProperty("description").c_str(), gTmp->getBoolProperty("canbejoined"));
 
774
 
 
775
        pInput->ioWrite("</updategamelist>");
 
776
        // END FIXME: DEPRECATED 1.0
 
777
 
 
778
        pInput->ioWrite("</monopd>\n");
 
779
}
 
780
 
 
781
void MonopdServer::processInput(Socket *socket, const std::string data)
 
782
{
 
783
        Player *pInput = findPlayer(socket);
 
784
        if (!pInput)
 
785
        {
 
786
                // The 'n' name command is available even for non-players. In fact,
 
787
                // it's considered to be the protocol handshake.
 
788
                if (data[0] == '.')
 
789
                {
 
790
                        Player *pNew = 0;
 
791
                        switch(data[1])
 
792
                        {
 
793
                        case 'n':
 
794
                                pNew = newPlayer(socket, data.substr(2));
 
795
                                sendXMLUpdates();
 
796
                                sendXMLUpdate(pNew, true, true); // give new player a full update (excluding self) so it knows who's in the lounge
 
797
                                return;
 
798
                        case 'R':
 
799
                                pNew = newPlayer(socket, "");
 
800
                                reconnectPlayer(pNew, data.substr(2));
 
801
                                return;
 
802
                        }
 
803
                }
 
804
                return;
 
805
        }
 
806
 
 
807
        if (data[0] == '.')
 
808
        {
 
809
                processCommands(pInput, data.substr(1));
 
810
                sendXMLUpdates();
 
811
                return;
 
812
        }
 
813
 
 
814
        if (data.size() > 256)
 
815
                pInput->ioError("Chat messages are limited to 256 characters");
 
816
        else
 
817
        {
 
818
                if (Game *game = pInput->game())
 
819
                        game->ioWrite("<monopd><msg type=\"chat\" playerid=\"%d\" author=\"%s\" value=\"%s\"/></monopd>\n", pInput->id(), pInput->name().c_str(), escapeXML(data).c_str());
 
820
                else
 
821
                        ioWrite("<monopd><msg type=\"chat\" playerid=\"" + itoa(pInput->id()) + "\" author=\"" + pInput->name() + "\" value=\"" + escapeXML(data) + "\"/></monopd>\n", true);
 
822
        }
 
823
}
 
824
 
 
825
void MonopdServer::processCommands(Player *pInput, const std::string data2)
 
826
{
 
827
        char *data = (char *)data2.c_str();
 
828
        if (data[0] != 'f')
 
829
                pInput->setRequestedUpdate(false);
 
830
 
 
831
        // The following commands are _always_ available.
 
832
        switch(data[0])
 
833
        {
 
834
        case 'n':
 
835
                setPlayerName(pInput, std::string(data+1));
 
836
                return;
 
837
        case 'p':
 
838
                switch(data[1])
 
839
                {
 
840
                        case 'i':
 
841
                                pInput->setProperty("image", data+2, this);
 
842
                                return;
 
843
                }
 
844
                break;
 
845
        }
 
846
 
 
847
        // Commands available when player is not within a game.
 
848
        Game *game = pInput->game();
 
849
        if (!game)
 
850
        {
 
851
                switch(data[0])
 
852
                {
 
853
                case 'g':
 
854
                        switch(data[1])
 
855
                        {
 
856
                                case 'l':
 
857
                                        sendGameList(pInput, true);
 
858
                                        return;
 
859
                                case 'n':
 
860
                                        newGame(pInput, data2.substr(2));
 
861
                                        return;
 
862
                                case 'j':
 
863
                                        joinGame(pInput, atol(data2.substr(2).c_str()));
 
864
                                        return;
 
865
                                case 'S':
 
866
                                        joinGame( pInput, atol(data2.substr(2).c_str()), true );
 
867
                                        return;
 
868
                                default:
 
869
                                        pInput->ioNoSuchCmd("you are not within a game");
 
870
                        }
 
871
                        break;
 
872
                case 'R':
 
873
                        reconnectPlayer(pInput, data2.substr(1));
 
874
                        break;
 
875
                default:
 
876
                        pInput->ioNoSuchCmd("you are not within a game");
 
877
                }
 
878
                // The rest of the commands are only available within a game.
 
879
                return;
 
880
        }
 
881
 
 
882
        // These commands are always available in a running game, no matter what.
 
883
        switch(data[0])
 
884
        {
 
885
        case 'f':
 
886
                game->sendFullUpdate(pInput, true);
 
887
                return;
 
888
        case 'g':
 
889
                switch(data[1])
 
890
                {
 
891
                case 'x':
 
892
                        exitGame(game, pInput);
 
893
                        return;
 
894
                }
 
895
                break;
 
896
        }
 
897
 
 
898
        switch(game->status())
 
899
        {
 
900
        case Game::End:
 
901
                pInput->ioNoSuchCmd("this game has ended");
 
902
                // The rest of the commands are only available when the game has not ended.
 
903
                return;
 
904
        default:;
 
905
        }
 
906
 
 
907
        if (game->status() != Game::Config && !pInput->getBoolProperty("bankrupt") && !pInput->getBoolProperty("spectator"))
 
908
                switch(data[0])
 
909
                {
 
910
                        case 'T':
 
911
                                switch(data[1])
 
912
                                {
 
913
                                case 'c':
 
914
                                case 'e':
 
915
                                        pInput->updateTradeObject(data+1);
 
916
                                        return;
 
917
                                case 'm':
 
918
                                        pInput->updateTradeMoney(data+2);
 
919
                                        return;
 
920
                                case 'n':
 
921
                                        game->newTrade(pInput, atol(data2.substr(2).c_str()));
 
922
                                        return;
 
923
                                case 'a':
 
924
                                        game->acceptTrade(pInput, data+2);
 
925
                                        return;
 
926
                                case 'r':
 
927
                                        game->rejectTrade(pInput, atol(data2.substr(2).c_str()));
 
928
                                        return;
 
929
                                }
 
930
                                break;
 
931
                }
 
932
 
 
933
        switch(data[0])
 
934
        {
 
935
        case 't':
 
936
                game->setTokenLocation(pInput, atoi(data+1));
 
937
                if (!game->clientsMoving())
 
938
                        if (Event *event = findEvent(game, Event::TokenMovementTimeout))
 
939
                                delEvent(event);
 
940
                return;
 
941
        }
 
942
 
 
943
        if (pInput->getBoolProperty("spectator") || pInput->getBoolProperty("bankrupt"))
 
944
        {
 
945
                pInput->ioNoSuchCmd("you are only a spectator");
 
946
                // The rest of the commands are only available for participating players
 
947
                return;
 
948
        }
 
949
 
 
950
        if (game->clientsMoving())
 
951
        {
 
952
                pInput->ioNoSuchCmd("other clients are still moving");
 
953
                // The rest of the commands are only available when no clients are moving
 
954
                return;
 
955
        }
 
956
 
 
957
        // If we're in a tax dialog, we don't accept too many commands.
 
958
        if (game->pausedForDialog())
 
959
        {
 
960
                switch(data[0])
 
961
                {
 
962
                case 'T':
 
963
                        switch(data[1])
 
964
                        {
 
965
                        case '$':
 
966
                                pInput->payTax();
 
967
                                return;
 
968
                        case '%':
 
969
                                pInput->payTax(true);
 
970
                                return;
 
971
                        default:
 
972
                                return;
 
973
                        }
 
974
                default:
 
975
                        // The rest of the commands are not available during a tax dialog
 
976
                        return;
 
977
                }
 
978
        }
 
979
 
 
980
        switch(data[0])
 
981
        {
 
982
                case 't': // client authors find the no such command message annoying.
 
983
                        return;
 
984
                break;
 
985
                // From the official rules: "may buy and erect at any time"
 
986
                case 'h':
 
987
                        switch(data[1])
 
988
                        {
 
989
                                case 'b':
 
990
                                        pInput->buyHouse(atoi(data+2));
 
991
                                        return;
 
992
                                case 's':
 
993
                                        pInput->sellHouse(atoi(data+2));
 
994
                                        return;
 
995
                        }
 
996
                        break;
 
997
                // From official rules: "Unimproved properties can be mortgaged
 
998
                // through the Bank at any time"
 
999
                // Selling estates is not officially supported, but it makes most
 
1000
                // sense here.
 
1001
                case 'e':
 
1002
                        switch(data[1])
 
1003
                        {
 
1004
                                case 'm':
 
1005
                                        pInput->mortgageEstate(atoi(data+2));
 
1006
                                        return;
 
1007
                                case 's':
 
1008
                                        pInput->sellEstate(atoi(data+2));
 
1009
                                        return;
 
1010
                        }
 
1011
        }
 
1012
 
 
1013
        // Auctions restrict movement and stuff.
 
1014
        Auction *auction = game->auction();
 
1015
        if (auction && auction->status() != Auction::Completed)
 
1016
        {
 
1017
                switch(data[0])
 
1018
                        {
 
1019
                        case 'a':
 
1020
                                switch(data[1])
 
1021
                                {
 
1022
                                case 'b':
 
1023
                                        if (!game->bidInAuction(pInput, data+2))
 
1024
                                        {
 
1025
                                                Event *event;
 
1026
                                                event = findEvent(game, Event::AuctionTimeout);
 
1027
                                                if (!event)
 
1028
                                                        event = newEvent(Event::AuctionTimeout, game);
 
1029
                                                event->setLaunchTime(time(0) + 4);
 
1030
                                        }
 
1031
                                        return;
 
1032
                                default:
 
1033
                                        pInput->ioNoSuchCmd();
 
1034
                                        return;
 
1035
                                }
 
1036
                        default:
 
1037
                                pInput->ioNoSuchCmd("An auction is in progress.");
 
1038
                                return;
 
1039
                        }
 
1040
        }
 
1041
 
 
1042
        // Declaring bankruptcy is only possible when a player is in debt.
 
1043
        if (game->debts())
 
1044
        {
 
1045
                if (game->findDebt(pInput))
 
1046
                        switch(data[0])
 
1047
                        {
 
1048
                                case 'D':
 
1049
                                        game->declareBankrupt(pInput);
 
1050
                                        break;
 
1051
                                case 'p':
 
1052
                                        game->solveDebts(pInput, true);
 
1053
                                        break;
 
1054
                                default:
 
1055
                                        pInput->ioNoSuchCmd("there are debts to be settled");
 
1056
                        }
 
1057
                else
 
1058
                        pInput->ioNoSuchCmd("there are debts to be settled");
 
1059
                // The rest of the commands are only available when there
 
1060
                // are no debts to be settled.
 
1061
                return;
 
1062
        }
 
1063
 
 
1064
        // These are only available when it's the player's turn
 
1065
        if(pInput->getBoolProperty("hasturn"))
 
1066
        {
 
1067
                if(pInput->getBoolProperty("can_buyestate"))
 
1068
                {
 
1069
                        switch(data[0]) 
 
1070
                        {
 
1071
                        case 'e':
 
1072
                                switch(data[1])
 
1073
                                {
 
1074
                                case 'b':
 
1075
                                        pInput->buyEstate();
 
1076
                                        return;
 
1077
                        case 'a':
 
1078
                                        game->newAuction(pInput);
 
1079
                                        return;
 
1080
                                default:
 
1081
                                        pInput->ioNoSuchCmd();
 
1082
                                        return;
 
1083
                                }
 
1084
                                break;
 
1085
                        }
 
1086
                }
 
1087
                
 
1088
                if(pInput->getBoolProperty("jailed"))
 
1089
                {
 
1090
                        switch(data[0]) 
 
1091
                        {
 
1092
                                case 'j':
 
1093
                                        switch(data[1])
 
1094
                                        {
 
1095
                                                case 'c':
 
1096
                                                        pInput->useJailCard();
 
1097
                                                        return;
 
1098
                                                case 'p':
 
1099
                                                        pInput->payJail();
 
1100
                                                        return;
 
1101
                                                case 'r':
 
1102
                                                        pInput->rollJail();
 
1103
                                                        return;
 
1104
                                                default:
 
1105
                                                        pInput->ioNoSuchCmd();
 
1106
                                        }
 
1107
                                        break;
 
1108
                        }
 
1109
                }
 
1110
                
 
1111
                if(pInput->getBoolProperty("can_roll"))
 
1112
                {
 
1113
                        switch(data[0]) 
 
1114
                        {
 
1115
                                case 'r':
 
1116
                                        pInput->rollDice();
 
1117
                                        Event *event = newEvent(Event::TokenMovementTimeout, game);
 
1118
                                        event->setLaunchTime(time(0) + 10);
 
1119
                                        return;
 
1120
                        }
 
1121
                        
 
1122
                }
 
1123
        }
 
1124
 
 
1125
        // The following commands have their own availability checks.
 
1126
        switch(data[0]) 
 
1127
        {
 
1128
                case 'E':
 
1129
                        pInput->endTurn(true);
 
1130
                        break;
 
1131
                case 'g':
 
1132
                        switch(data[1])
 
1133
                        {
 
1134
                                case 'd':
 
1135
                                        setGameDescription(pInput, data2.substr(2));
 
1136
                                        return;
 
1137
                                case 'c':
 
1138
                                        game->editConfiguration( pInput, data+2 );
 
1139
                                        return;
 
1140
                                case 'e':
 
1141
                                        game->editConfig(pInput, data+2);
 
1142
                                        return;
 
1143
                                case 'k':
 
1144
                                        Player *pKick;
 
1145
                                        pKick = game->kickPlayer( pInput, atoi(data+2) );
 
1146
                                        if (pKick)
 
1147
                                                exitGame(game, pKick);
 
1148
                                        return;
 
1149
                                case 'u':
 
1150
                                        game->upgradePlayer( pInput, atoi(data+2) );
 
1151
                                        return;
 
1152
                                case 'p':
 
1153
                                        // FIXME: DEPRECATED 1.0
 
1154
                                        return;
 
1155
                                case 's':
 
1156
                                        game->start(pInput);
 
1157
 
 
1158
                                        // FIXME: DEPRECATED 1.0
 
1159
                                        if (game->status() == Game::Run)
 
1160
                                                ioWrite("<monopd><updategamelist type=\"del\"><game id=\"" + itoa(game->id()) + "\"/></updategamelist></monopd>\n");
 
1161
                                        return;
 
1162
                                default:
 
1163
                                        pInput->ioNoSuchCmd();
 
1164
                        }
 
1165
                        break;
 
1166
                case 'd':
 
1167
                        pInput->closeSocket();
 
1168
                        return;
 
1169
                default:
 
1170
                        pInput->ioNoSuchCmd();
 
1171
        }
 
1172
}
 
1173
 
 
1174
void MonopdServer::sendXMLUpdates()
 
1175
{
 
1176
        // Send XML to all players
 
1177
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (*it) ; ++it)
 
1178
                sendXMLUpdate((*it));
 
1179
 
 
1180
        // Reset propertiesChanged for all player and game objects
 
1181
        // TODO: cache whether they changed above and reuse here?
 
1182
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (*it) ; ++it)
 
1183
                (*it)->unsetPropertiesChanged();
 
1184
        for(std::vector<Game *>::iterator it = m_games.begin(); it != m_games.end() && (*it) ; ++it)
 
1185
        {
 
1186
                (*it)->unsetPropertiesChanged();
 
1187
 
 
1188
                // Let games handle resets for its own objects ..
 
1189
                (*it)->unsetChildProperties();
 
1190
        }
 
1191
}
 
1192
 
 
1193
void MonopdServer::sendXMLUpdate(Player *pOutput, bool fullUpdate, bool excludeSelf)
 
1194
{
 
1195
        bool updateEmpty = true;
 
1196
 
 
1197
        // Send updates *about* all players ..
 
1198
        Player *pUpdate = 0;
 
1199
        for(std::vector<Player *>::iterator uit = m_players.begin(); uit != m_players.end() && (pUpdate = *uit) ; ++uit)
 
1200
        {
 
1201
                // .. but only when changed (and in property scope)
 
1202
                if (!excludeSelf || pUpdate != pOutput)
 
1203
                {
 
1204
                        std::string updateXML = pUpdate->oldXMLUpdate(pOutput, fullUpdate);
 
1205
                        if (updateXML.size())
 
1206
                        {
 
1207
                                if (updateEmpty)
 
1208
                                {
 
1209
                                        pOutput->ioWrite("<monopd> ");
 
1210
                                        updateEmpty = false;
 
1211
                                }
 
1212
                                pOutput->ioWrite("%s", updateXML.c_str());
 
1213
                        }
 
1214
                }
 
1215
        }
 
1216
 
 
1217
        // Send updates *about* all games ..
 
1218
        Game *gUpdate = 0;
 
1219
        for(std::vector<Game *>::iterator uit = m_games.begin(); uit != m_games.end() && (gUpdate = *uit) ; ++uit)
 
1220
        {
 
1221
                // .. but only when changed (and in property scope)
 
1222
                std::string updateXML = gUpdate->oldXMLUpdate(pOutput, fullUpdate);
 
1223
                if (updateXML.size())
 
1224
                {
 
1225
                        if (updateEmpty)
 
1226
                        {
 
1227
                                pOutput->ioWrite("<monopd> ");
 
1228
                                updateEmpty = false;
 
1229
                        }
 
1230
                        pOutput->ioWrite("%s", updateXML.c_str());
 
1231
                }
 
1232
        }
 
1233
 
 
1234
        // Let game handle updates *about* all of its objects ..
 
1235
        if (Game *game = pOutput->game())
 
1236
                updateEmpty = game->sendChildXMLUpdate(pOutput, updateEmpty);
 
1237
        
 
1238
        if (!updateEmpty)
 
1239
                pOutput->ioWrite("</monopd>\n");
 
1240
}
 
1241
 
 
1242
void MonopdServer::setPlayerName(Player *player, const std::string &name)
 
1243
{
 
1244
                std::string useName = ( name.size() ? name : "anonymous" );
 
1245
 
 
1246
                int i=1;
 
1247
                while (findPlayer(useName))
 
1248
                        useName = ( name.size() ? name : "anonymous" ) + itoa( ++i );
 
1249
 
 
1250
                player->setProperty("name", useName, this);
 
1251
 
 
1252
                Game *game = player->game();
 
1253
                if (game)
 
1254
                {
 
1255
                        // FIXME: DEPRECATED 1.0
 
1256
                        if (game->status() == Game::Config && player == game->master())
 
1257
                                ioWrite(std::string("<monopd><updategamelist type=\"edit\"><game id=\"") + itoa(game->id()) + "\" players=\"" + itoa(game->getIntProperty("players")) + "\" gametype=\"" + game->gameType() + "\" name=\"" + game->name() + "\" description=\"" + game->getStringProperty("description") + "\" canbejoined=\"" + itoa(game->getBoolProperty("canbejoined")) + "\"/></updategamelist></monopd>\n");
 
1258
                }
 
1259
}