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

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Markus Koschany
  • Date: 2014-02-28 15:39:47 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20140228153947-1a5z05x3alj61wx1
Tags: 0.9.5-1
* Imported Upstream version 0.9.5.
  - Add support for IPv6 and systemd.
* Update watch file and point to the new upstream location
  at tuxfamily.org.
* Drop all patches. Merged upstream.
* debian/control:
  - Drop libcapsinetwork-dev from Build-Depends.
    Essential features of libcapsinetwork were merged into monopd and
    IPv6 support was added.
  - Add pkg-config to Build-Depends.
  - Add libsystemd-daemon-dev [linux-any] to Build-Depends.
  - Update homepage field and point to gtkatlantic.gradator.net.
* Add monopd.service and monopd.socket file and support systemd.
* Update monopd.6 man page.
* Use dh-systemd helper.
* Update debian/copyright. Add new BSD license.

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
 
}