1 // Copyright (C) 2008 Ole Laursen
2 // Copyright (C) 2008, 2011, 2014, 2015, 2017 Ben Asselstine
3 //
4 //  This program is free software; you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation; either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU Library General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program; if not, write to the Free Software
16 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 //  02110-1301, USA.
18 
19 #include <iostream>
20 #include <sstream>
21 #include <list>
22 #include "game-parameters.h"
23 #include "game-server.h"
24 
25 #include "File.h"
26 #include "network-server.h"
27 #include "game.h"
28 #include "xmlhelper.h"
29 #include "GameScenario.h"
30 #include "playerlist.h"
31 #include "player.h"
32 #include "network-action.h"
33 #include "network-history.h"
34 #include "Configuration.h"
35 #include "network_player.h"
36 #include "real_player.h"
37 #include "GameScenarioOptions.h"
38 #include "ucompose.hpp"
39 
40 class NetworkAction;
41 
42 //! A helper class for GameServer.  A connected user in a network game.
43 struct Participant
44 {
45   void *conn;
46   std::list<GameParameters::Player> players;
47   std::map<guint32, bool> id_end_turn;
48   std::list<NetworkAction *> actions;
49   std::list<NetworkHistory *> histories;
50   Glib::ustring nickname;
51   bool departed;
52   Glib::ustring profile_id;
53 };
54 
55 GameServer * GameServer::s_instance = 0;
56 
getInstance()57 GameServer* GameServer::getInstance()
58 {
59     if (s_instance == 0)
60         s_instance = new GameServer();
61 
62     return s_instance;
63 }
64 
deleteInstance()65 void GameServer::deleteInstance()
66 {
67     if (s_instance)
68         delete s_instance;
69 
70     s_instance = 0;
71 }
72 
73 
GameServer()74 GameServer::GameServer()
75 {
76   d_game_has_begun = false;
77 
78   remote_player_moved.connect
79     (sigc::mem_fun(*this, &GameServer::on_player_finished_turn));
80   local_player_moved.connect
81     (sigc::mem_fun(*this, &GameServer::on_player_finished_turn));
82   d_stop = false;
83 }
84 
notifyRoundOver()85 void GameServer::notifyRoundOver()
86 {
87   for (auto &i: participants)
88     network_server->send(i->conn, MESSAGE_TYPE_ROUND_OVER, "");
89 }
90 
check_end_of_round()91 bool GameServer::check_end_of_round()
92 {
93   if (Playerlist::getInstance()->getNeutral()->hasAlreadyEndedTurn())
94     {
95       Playerlist::getInstance()->getNeutral()->clearActionlist();
96       notifyRoundOver();
97       round_ends.emit();
98       return true;
99     }
100   return false;
101 }
102 
on_player_finished_turn(Player * player)103 void GameServer::on_player_finished_turn(Player *player)
104 {
105   if (check_end_of_round() == false)
106     {
107       //if the end of turn is asynchronous, start a new turn from here
108       //otherwise, just fall through back to the nextTurn method, and it's
109       //inner loop.
110       if (player->getType() == Player::HUMAN ||
111           player->getType() == Player::NETWORKED)
112         {
113           if (nextTurn())
114             on_player_finished_turn(Playerlist::getInstance()->getNeutral());
115         }
116     }
117 }
118 
remove_all_participants()119 void GameServer::remove_all_participants()
120 {
121   stopListeningForLocalEvents();
122   //say goodbye to all participants
123   for (auto &i: participants)
124     network_server->send(i->conn, MESSAGE_TYPE_SERVER_DISCONNECT, "bye");
125   for (auto &i: participants)
126     delete i;
127   participants.clear();
128   players_seated_locally.clear();
129 }
130 
~GameServer()131 GameServer::~GameServer()
132 {
133   if (network_server.get() != NULL)
134     {
135       if (network_server->isListening())
136         network_server->stop();
137     }
138 }
139 
isListening()140 bool GameServer::isListening()
141 {
142   if (network_server.get() != NULL)
143     return network_server->isListening();
144   else
145     return false;
146 }
147 
start(GameScenario * game_scenario,int port,Glib::ustring profile_id,Glib::ustring nick)148 void GameServer::start(GameScenario *game_scenario, int port, Glib::ustring profile_id, Glib::ustring nick)
149 {
150   setGameScenario(game_scenario);
151   setNickname(nick);
152   setProfileId(profile_id);
153 
154   if (network_server.get() != NULL && network_server->isListening())
155     return;
156   network_server.reset(new NetworkServer());
157   network_server->port_in_use.connect
158     (sigc::mem_fun(port_in_use, &sigc::signal<void, int>::emit));
159   network_server->got_message.connect
160     (sigc::mem_fun(this, &GameServer::onGotMessage));
161   network_server->connection_lost.connect
162     (sigc::mem_fun(this, &GameServer::onConnectionLost));
163   network_server->connection_made.connect
164     (sigc::mem_fun(this, &GameServer::onConnectionMade));
165 
166   network_server->startListening(port);
167 
168   listenForLocalEvents(Playerlist::getInstance()->getNeutral());
169   for (auto &it: *Playerlist::getInstance())
170     if (it->getType() == Player::NETWORKED)
171       listenForLocalEvents(it);
172 }
173 
sendNextPlayer()174 bool GameServer::sendNextPlayer()
175 {
176   Glib::ustring s =
177     String::ucompose("%1", Playerlist::getActiveplayer()->getId());
178   //now we can send the start round message, and begin the round ourselves.
179   for (auto &i: participants)
180     network_server->send(i->conn, MESSAGE_TYPE_NEXT_PLAYER, s);
181   Participant *part = findParticipantByPlayerId
182     (Playerlist::getActiveplayer()->getId());
183   if (!part)
184     return false;
185   return true;
186 }
187 
nextTurn()188 bool GameServer::nextTurn()
189 {
190   while (1)
191     {
192       Player *p = get_next_player.emit();
193       if (p)
194         {
195           if (p->getType() == Player::NETWORKED)
196             {
197               sendNextPlayer();
198               start_player_turn.emit(p);
199               break; //now it goes to on_player_finished_turn if player avail.
200             }
201           else
202             {
203               sendNextPlayer();
204               if (p->getType() == Player::HUMAN)
205                 {
206                   start_player_turn.emit(p);
207                   break;
208                 }
209               else if (p->getType() == Player::AI_DUMMY)
210                 {
211                   start_player_turn.emit(p);
212                   return true;
213                 }
214               else
215                 start_player_turn.emit(p);
216             }
217         }
218       else
219         break;
220     }
221   return false;
222 }
223 
sendRoundStart()224 bool GameServer::sendRoundStart()
225 {
226   sendTurnOrder();
227   //now we can send the start round message, and begin the round ourselves.
228   for (auto &i: participants)
229     network_server->send(i->conn, MESSAGE_TYPE_ROUND_START, "");
230   round_begins.emit();
231   Playerlist::getInstance()->setActiveplayer(NULL);
232   return nextTurn();
233 }
234 
gotChat(void * conn,Glib::ustring message)235 void GameServer::gotChat(void *conn, Glib::ustring message)
236 {
237   Participant *part = findParticipantByConn(conn);
238   if (part)
239     {
240       gotChatMessage(part->nickname, message);
241       for (auto &i: participants)
242         network_server->send(i->conn, MESSAGE_TYPE_CHATTED, message);
243 
244     }
245   return;
246 }
247 
248 
onGotMessage(void * conn,int type,Glib::ustring payload)249 bool GameServer::onGotMessage(void *conn, int type, Glib::ustring payload)
250 {
251   //std::cerr << "got message of type " << type << std::endl;
252   switch (MessageType(type)) {
253   case MESSAGE_TYPE_PING:
254     //std::cerr << "sending pong" << std::endl;
255     network_server->send(conn, MESSAGE_TYPE_PONG, "");
256     break;
257 
258   case MESSAGE_TYPE_PONG:
259     break;
260 
261   case MESSAGE_TYPE_SENDING_ACTIONS:
262     gotRemoteActions(conn, payload);
263     break;
264 
265   case MESSAGE_TYPE_SENDING_MAP:
266     // should never occur
267     break;
268 
269   case MESSAGE_TYPE_SENDING_HISTORY:
270     gotRemoteHistory(conn, payload);
271     break;
272 
273   case MESSAGE_TYPE_PARTICIPANT_CONNECT:
274     join(conn, payload);
275     break;
276 
277   case MESSAGE_TYPE_REQUEST_SEAT_MANIFEST:
278     sendChatRoster(conn);
279     sendSeats(conn);
280     if (gameHasBegun())
281       network_server->send(conn, MESSAGE_TYPE_GAME_MAY_BEGIN, "");
282     break;
283 
284   case MESSAGE_TYPE_PARTICIPANT_DISCONNECT:
285     depart(conn);
286     break;
287 
288   case MESSAGE_TYPE_PARTICIPANT_CONNECTED:
289     break;
290 
291   case MESSAGE_TYPE_CHAT:
292     gotChat(conn, payload);
293     break;
294 
295   case MESSAGE_TYPE_ROUND_OVER:
296     //what do we do now?
297     break;
298 
299   case MESSAGE_TYPE_LOBBY_ACTIVITY:
300       {
301         guint32 id;
302         gint32 action;
303         bool reported;
304         Glib::ustring data;
305         bool success =
306           get_message_lobby_activity (payload, id, action, reported, data);
307         if (success)
308           {
309             if (reported == false) //player is /reporting/
310               {
311                 switch (action)
312                   {
313                   case LOBBY_MESSAGE_TYPE_SIT:
314                     sit(conn, Playerlist::getInstance()->getPlayer(id), data);
315                     break;
316                   case LOBBY_MESSAGE_TYPE_STAND:
317                     stand(conn, Playerlist::getInstance()->getPlayer(id), data);
318                     break;
319                   case LOBBY_MESSAGE_TYPE_CHANGE_NAME:
320                     change_name(conn,
321                                 Playerlist::getInstance()->getPlayer(id), data);
322                     break;
323                   case LOBBY_MESSAGE_TYPE_CHANGE_TYPE:
324                     change_type(conn,
325                                 Playerlist::getInstance()->getPlayer(id),
326                                 atoi(data.c_str()));
327                     break;
328                   default:
329                     break;
330                   }
331               }
332           }
333       }
334     break;
335 
336   case MESSAGE_TYPE_PARTICIPANT_DISCONNECTED:
337     break;
338 
339   case MESSAGE_TYPE_SERVER_DISCONNECT:
340   case MESSAGE_TYPE_CHATTED:
341   case MESSAGE_TYPE_TURN_ORDER:
342   case MESSAGE_TYPE_KILL_PLAYER:
343   case MESSAGE_TYPE_ROUND_START:
344   case MESSAGE_TYPE_CHANGE_NICKNAME:
345   case MESSAGE_TYPE_GAME_MAY_BEGIN:
346   case MESSAGE_TYPE_OFF_PLAYER:
347   case MESSAGE_TYPE_NEXT_PLAYER:
348     //faulty client
349     break;
350   }
351   return true;
352 }
353 
onConnectionMade(void * conn)354 void GameServer::onConnectionMade(void *conn)
355 {
356   (void) conn;
357   remote_participant_connected.emit();
358 }
359 
onConnectionLost(void * conn)360 void GameServer::onConnectionLost(void *conn)
361 {
362   std::cerr << "connection lost" << std::endl;
363 
364   Participant *part = findParticipantByConn(conn);
365   if (part)
366     {
367       std::list<GameParameters::Player> players_to_stand = part->players;
368 
369       depart(conn);
370       participants.remove(part);
371       //tell everybode else that we've just stood up.
372       for (auto &i: players_to_stand)
373 	notifyStand(Playerlist::getInstance()->getPlayer(i.id), d_nickname);
374       remote_participant_disconnected.emit();
375       delete part;
376     }
377   network_server->onConnectionLost(conn);
378 }
379 
findParticipantByConn(void * conn)380 Participant *GameServer::findParticipantByConn(void *conn)
381 {
382   for (auto &i: participants)
383     if (i->conn == conn)
384       return i;
385 
386   return NULL;
387 }
388 
onLocalNonNetworkedActionDone(NetworkAction * action)389 void GameServer::onLocalNonNetworkedActionDone(NetworkAction *action)
390 {
391   Glib::ustring desc = action->toString();
392   std::cerr << String::ucompose("Game Server got action: %1 description: %2", Action::actionTypeToString(action->getAction()->getType()), desc) << std::endl;
393 
394   if (action->getAction()->getType() == Action::END_TURN)
395     local_player_moved.emit(action->getOwner());
396   if (action->getAction()->getType() == Action::INIT_TURN)
397     local_player_starts_move.emit(action->getOwner());
398 
399   for (auto &i: participants)
400     {
401       i->actions.push_back(new NetworkAction (action->getAction(),
402                                               action->getOwnerId()));
403       sendActions(i);
404     }
405   for (auto &i: participants)
406     clearNetworkActionlist(i->actions);
407 
408   //do it here.
409   delete action;
410 }
411 
onActionDone(Action * a,guint32 id)412 void GameServer::onActionDone(Action *a, guint32 id)
413 {
414   if (d_stop)
415     return;
416   NetworkAction *action = new NetworkAction (a, id);
417   Player *p = Playerlist::getInstance()->getPlayer(action->getOwnerId());
418   if (p->getType() != Player::NETWORKED)
419     onLocalNonNetworkedActionDone(action);
420 
421 }
422 
onLocalNonNetworkedHistoryDone(NetworkHistory * history)423 void GameServer::onLocalNonNetworkedHistoryDone(NetworkHistory *history)
424 {
425   Glib::ustring desc = history->toString();
426   std::cerr << String::ucompose("Game Server got history: %1 %2", History::historyTypeToString(history->getHistory()->getType()), desc) << std::endl;
427 
428   if (history->getHistory()->getType() == History::PLAYER_VANQUISHED)
429     local_player_died(history->getOwner());
430 
431   for (auto &i: participants)
432     {
433       i->histories.push_back (new NetworkHistory (history->getHistory(),
434                                                   history->getOwnerId()));
435       sendHistories(i);
436       clearNetworkHistorylist(i->histories);
437     }
438   delete history;
439 }
440 
onLocalNetworkedHistoryDone(NetworkHistory * history)441 void GameServer::onLocalNetworkedHistoryDone(NetworkHistory *history)
442 {
443   //okay we only care about two locally generated history events.
444   Glib::ustring desc = history->toString();
445 
446   for (auto &i: participants)
447     {
448       i->histories.push_back (new NetworkHistory (history->getHistory(),
449                                                   history->getOwnerId()));
450       if (history->getHistory()->getType() == History::GOLD_TOTAL ||
451           history->getHistory()->getType() == History::SCORE)
452         {
453           std::cerr << String::ucompose("Game Server got locally generated networked history event: %1", desc) << std::endl;
454           sendHistories(i);
455         }
456       else
457         {
458           std::cerr << String::ucompose("Game Server got locally generated networked history event but not sending: %1", desc) << std::endl;
459         }
460 
461       clearNetworkHistorylist(i->histories);
462     }
463   delete history;
464 }
465 
onHistoryDone(History * h,guint32 id)466 void GameServer::onHistoryDone(History *h, guint32 id)
467 {
468   NetworkHistory *history = new NetworkHistory(h, id);
469   Player *p = Playerlist::getInstance()->getPlayer(history->getOwnerId());
470   if (p->getType() != Player::NETWORKED)
471     onLocalNonNetworkedHistoryDone(history);
472   else
473     onLocalNetworkedHistoryDone(history);
474 }
475 
notifyJoin(Glib::ustring nickname)476 void GameServer::notifyJoin(Glib::ustring nickname)
477 {
478   remote_participant_joins.emit(nickname);
479   for (auto &i: participants)
480     network_server->send(i->conn, MESSAGE_TYPE_PARTICIPANT_CONNECTED, nickname);
481   gotChatMessage("[server]", String::ucompose (_("%1 connected."), nickname));
482 }
483 
notifyDepart(void * conn,Glib::ustring nickname)484 void GameServer::notifyDepart(void *conn, Glib::ustring nickname)
485 {
486   remote_participant_departs.emit(nickname);
487   for (auto &i: participants)
488     {
489       if (i->conn == conn)
490 	continue;
491       network_server->send(i->conn, MESSAGE_TYPE_PARTICIPANT_DISCONNECTED,
492                            nickname);
493       network_server->send(i->conn, MESSAGE_TYPE_CHATTED,
494                            String::ucompose (_("%1 disconnected."), nickname));
495     }
496   gotChatMessage("", String::ucompose (_("%1 disconnected"), nickname));
497 }
498 
notifySit(Player * player,Glib::ustring nickname)499 void GameServer::notifySit(Player *player, Glib::ustring nickname)
500 {
501   if (!player)
502     return;
503   Glib::ustring payload =
504     String::ucompose("%1 %2 %3 %4", player->getId(), LOBBY_MESSAGE_TYPE_SIT,
505                      1, nickname);
506   player_sits.emit(player, nickname);
507 
508   for (auto &i: participants)
509     {
510       network_server->send(i->conn, MESSAGE_TYPE_LOBBY_ACTIVITY, payload);
511       network_server->send(i->conn, MESSAGE_TYPE_CHATTED,
512                            nickname + " assumes control of " +
513                            player->getName() +".");
514     }
515   gotChatMessage("", nickname + " assumes control of " +
516 		 player->getName() +".");
517 }
518 
notifyTypeChange(Player * player,int type)519 void GameServer::notifyTypeChange(Player *player, int type)
520 {
521   if (!player)
522     return;
523   Glib::ustring payload =
524     String::ucompose("%1 %2 %3 %4", player->getId(),
525                      LOBBY_MESSAGE_TYPE_CHANGE_TYPE, 1, type);
526   player_changes_type.emit(player, type);
527 
528   for (auto &i: participants)
529     network_server->send(i->conn, MESSAGE_TYPE_LOBBY_ACTIVITY, payload);
530 }
531 
notifyNameChange(Player * player,Glib::ustring name)532 void GameServer::notifyNameChange(Player *player, Glib::ustring name)
533 {
534   if (!player)
535     return;
536   Glib::ustring payload =
537     String::ucompose("%1 %2 %3 %4", player->getId(),
538                      LOBBY_MESSAGE_TYPE_CHANGE_NAME, 1, name);
539   player_changes_name.emit(player, name);
540 
541   for (auto &i: participants)
542     network_server->send(i->conn, MESSAGE_TYPE_LOBBY_ACTIVITY, payload);
543 }
544 
findParticipantByPlayerId(guint32 id)545 Participant *GameServer::findParticipantByPlayerId(guint32 id)
546 {
547   for (auto &i: participants)
548     for (auto &j: i->players)
549       if (j.id == id)
550         return i;
551 
552   return NULL;
553 }
554 
findParticipantByNick(Glib::ustring nickname)555 Participant *GameServer::findParticipantByNick(Glib::ustring nickname)
556 {
557   for (auto &i: participants)
558     if (i->nickname == nickname)
559       return i;
560 
561   return NULL;
562 }
563 
make_nickname_unique(Glib::ustring nickname)564 Glib::ustring GameServer::make_nickname_unique(Glib::ustring nickname)
565 {
566   Glib::ustring new_nickname;
567   int count = 0;
568   //okay, does this nickname appear twice?
569   for (auto &i: participants)
570     if (i->nickname == nickname)
571       count++;
572   if (nickname == d_nickname)
573     count++;
574   if (count <= 1)
575     return nickname;
576   count = 2;
577   while (1)
578     {
579       new_nickname = String::ucompose("%1-%2", nickname, count);
580       Participant *part = findParticipantByNick(new_nickname);
581       if (!part)
582         break;
583       count++;
584       if (count == 1000)
585         break;
586     }
587   if (count == 1000)
588     return "";
589   return new_nickname;
590 }
591 
join(void * conn,Glib::ustring nickname_and_profile_id)592 void GameServer::join(void *conn, Glib::ustring nickname_and_profile_id)
593 {
594   bool new_participant = false;
595   std::cout << "JOIN: " << conn << std::endl;
596 
597   size_t pos;
598   pos = nickname_and_profile_id.rfind(' ');
599   if (pos == Glib::ustring::npos)
600     return;
601   Glib::ustring nickname = nickname_and_profile_id.substr(0, pos);
602   Glib::ustring profile_id = nickname_and_profile_id.substr(pos + 1);
603   Participant *part = findParticipantByConn(conn);
604   if (!part) {
605     part = new Participant;
606     part->conn = conn;
607     part->nickname = nickname;
608     part->profile_id = profile_id;
609     participants.push_back(part);
610     part->departed = false;
611     new_participant = true;
612   }
613   if (new_participant)
614     sendMap(part);
615 
616   Glib::ustring new_nickname = make_nickname_unique(nickname);
617   if (new_nickname != "")
618     {
619       if (new_nickname != nickname)
620         {
621           part->nickname = new_nickname;
622           network_server->send(conn, MESSAGE_TYPE_CHANGE_NICKNAME,
623                                new_nickname);
624         }
625       notifyJoin(new_nickname);
626     }
627 }
628 
depart(void * conn)629 void GameServer::depart(void *conn)
630 {
631   Participant *part = findParticipantByConn(conn);
632   if (part && part->departed == false)
633     {
634       std::cout << "DEPART: " << conn << std::endl;
635       notifyDepart(conn, part->nickname);
636       part->departed = true;
637     }
638   //we don't delete the participant, it gets deleted when it disconnects.
639   //see onConnectionLost
640 }
641 
player_already_sitting(Player * p)642 bool GameServer::player_already_sitting(Player *p)
643 {
644   //check if the player p is already sitting down as a participant.
645   for (auto &i: participants)
646     for (auto &j: i->players)
647       if (p->getId() == j.id)
648         return true;
649   return false;
650 }
651 
sit(void * conn,Player * player,Glib::ustring nickname)652 void GameServer::sit(void *conn, Player *player, Glib::ustring nickname)
653 {
654   std::cout << "SIT: " << conn << " " << player << std::endl;
655 
656   if (!player || !conn)
657     return;
658   Participant *part = findParticipantByConn(conn);
659   if (!part)
660     return;
661 
662   if (player_already_sitting(player) == true)
663     return;
664 
665   //is this player already locally instantiated as an ai or human player?
666   if (player->getType() != Player::NETWORKED)
667     return;
668 
669   add_to_player_list(part->players, player->getId(), player->getName(),
670                      GameParameters::player_type_to_player_param(player->getType()));
671 
672   if (player)
673     dynamic_cast<NetworkPlayer*>(player)->setConnected(true);
674 
675   notifySit(player, nickname);
676 }
677 
change_name(void * conn,Player * player,Glib::ustring name)678 void GameServer::change_name(void *conn, Player *player, Glib::ustring name)
679 {
680   std::cout << "CHANGE NAME: " << conn << " " << player << " " << name << std::endl;
681 
682   if (!player || !conn)
683     return;
684   Participant *part = findParticipantByConn(conn);
685   if (!part)
686     return;
687 
688   update_player_name (part->players, player->getId(), name);
689   name_change(player, name);
690 }
691 
change_type(void * conn,Player * player,int type)692 void GameServer::change_type(void *conn, Player *player, int type)
693 {
694   std::cout << "CHANGE TYPE: " << conn << " " << player << " " << type << std::endl;
695 
696   if (!player || !conn)
697     return;
698   Participant *part = findParticipantByConn(conn);
699   if (!part)
700     return;
701 
702   update_player_type (part->players, player->getId(), (guint32) type);
703   notifyTypeChange(player, type);
704 }
705 
notifyStand(Player * player,Glib::ustring nickname)706 void GameServer::notifyStand(Player *player, Glib::ustring nickname)
707 {
708   if (!player)
709     return;
710   Glib::ustring payload =
711     String::ucompose("%1 %2 %3 %4", player->getId(),
712                      LOBBY_MESSAGE_TYPE_STAND, 1, nickname);
713   player_stands.emit(player, nickname);
714 
715   for (auto &i: participants)
716     {
717       network_server->send(i->conn, MESSAGE_TYPE_LOBBY_ACTIVITY, payload);
718       network_server->send(i->conn, MESSAGE_TYPE_CHATTED,
719 			   nickname + " relinquishes control of " +
720 			   player->getName() +".");
721     }
722   gotChatMessage("", nickname + " relinquishes control of " +
723 		 player->getName() +".");
724 }
725 
726 bool
update_player_type(std::list<GameParameters::Player> & list,guint32 id,guint32 type)727 GameServer::update_player_type (std::list<GameParameters::Player> &list, guint32 id, guint32 type)
728 {
729   bool found = false;
730   for (auto &i: list)
731     {
732       if (i.id == id)
733 	{
734 	  found = true;
735           i.type = GameParameters::Player::Type(type);
736 	  break;
737 	}
738     }
739   return found;
740 }
741 
742 bool
update_player_name(std::list<GameParameters::Player> & list,guint32 id,Glib::ustring name)743 GameServer::update_player_name (std::list<GameParameters::Player> &list, guint32 id, Glib::ustring name)
744 {
745   bool found = false;
746   for (auto &i: list)
747     {
748       if (i.id == id)
749 	{
750 	  found = true;
751           i.name = name;
752 	  break;
753 	}
754     }
755   return found;
756 }
757 
758 bool
add_to_player_list(std::list<GameParameters::Player> & list,guint32 id,Glib::ustring name,guint32 type)759 GameServer::add_to_player_list(std::list<GameParameters::Player> &list, guint32 id, Glib::ustring name, guint32 type)
760 {
761   bool found = false;
762   for (auto &i: list)
763     {
764       if (i.id == id)
765 	{
766 	  found = true;
767           i.type = GameParameters::Player::Type(type);
768           i.name = name;
769 	  break;
770 	}
771     }
772   if (found == false)
773     {
774       GameParameters::Player p;
775       p.id = id;
776       p.type = GameParameters::Player::Type(type);
777       p.name = name;
778       list.push_back(p);
779     }
780   return found;
781 }
782 
783 bool
remove_from_player_list(std::list<GameParameters::Player> & list,guint32 id)784 GameServer::remove_from_player_list(std::list<GameParameters::Player> &list, guint32 id)
785 {
786   //remove player id from part.
787   for (std::list<GameParameters::Player>::iterator i = list.begin(); i != list.end(); i++)
788     {
789       if ((*i).id == id)
790 	{
791 	  list.erase (i);
792 	  return true;
793 	}
794     }
795   return false;
796 }
797 
stand(void * conn,Player * player,Glib::ustring nickname)798 void GameServer::stand(void *conn, Player *player, Glib::ustring nickname)
799 {
800   std::cout << "STAND: " << conn << " " << player << std::endl;
801   if (!player || !conn)
802     return;
803 
804   Participant *part = findParticipantByConn(conn);
805   if (!part)
806     return;
807 
808   //remove player id from part.
809   bool found = remove_from_player_list (part->players, player->getId());
810 
811   if (!found)
812     //okay somebody's trying to boot another player.
813     return;
814 
815   if (player && player->getType() == Player::NETWORKED)
816     dynamic_cast<NetworkPlayer*>(player)->setConnected(false);
817   notifyStand(player, nickname);
818 }
819 
gotRemoteActions(void * conn,const Glib::ustring & payload)820 void GameServer::gotRemoteActions(void *conn, const Glib::ustring &payload)
821 {
822   gotActions(payload);
823   for (auto &i: participants)
824     if (i->conn != conn)
825       network_server->send(i->conn, MESSAGE_TYPE_SENDING_ACTIONS, payload);
826 }
827 
gotRemoteHistory(void * conn,const Glib::ustring & payload)828 void GameServer::gotRemoteHistory(void *conn, const Glib::ustring &payload)
829 {
830   gotHistories(payload);
831   for (auto &i: participants)
832     if (i->conn != conn)
833       network_server->send(i->conn, MESSAGE_TYPE_SENDING_HISTORY, payload);
834 }
835 
sendMap(Participant * part)836 void GameServer::sendMap(Participant *part)
837 {
838   // first hack the players so the player type we serialize is right
839   std::vector<Player*> players;
840   for (auto &i: *Playerlist::getInstance())
841     {
842       bool connected = false;
843       players.push_back(i);
844       if (i->isComputer() == true)
845 	connected = true;
846       NetworkPlayer *new_p = new NetworkPlayer(*i);
847       new_p->setConnected(connected);
848       Playerlist::getInstance()->swap(i, new_p);
849     }
850 
851   // send the map, and save it to a file somewhere temporarily
852   Glib::ustring tmpfile = File::get_tmp_file();
853   File::erase(tmpfile);
854   tmpfile += SAVE_EXT;
855 
856   d_game_scenario->saveGame(tmpfile);
857 
858   std::cerr << "sending map" << std::endl;
859   network_server->sendFile(part->conn, MESSAGE_TYPE_SENDING_MAP, tmpfile);
860   //file gets erased in NetworkConnection::sendFileMessage
861 
862   // unhack the players
863   std::vector<Player*> deletables;
864   for (auto i : players)
865     {
866       Player *p = Playerlist::getInstance()->getPlayer(i->getId());
867       deletables.push_back(p);
868       Playerlist::getInstance()->swap(p, i);
869     }
870 
871   /*
872   std::vector<Player*>::iterator j = players.begin();
873   for (Playerlist::iterator i = Playerlist::getInstance()->begin();
874        i != Playerlist::getInstance()->end(); ++i)
875     {
876       Playerlist::getInstance()->swap(*i, *j);
877       j++;
878     }
879     */
880   for (auto i : deletables)
881     {
882       NetworkPlayer *p = dynamic_cast<NetworkPlayer*>(i);
883       delete p;
884     }
885 }
886 
sendActions(Participant * part)887 void GameServer::sendActions(Participant *part)
888 {
889   std::ostringstream os;
890   XML_Helper helper(&os);
891 
892   helper.begin("1");
893   helper.openTag("actions");
894 
895   for (auto &i: part->actions)
896     (*i).save(&helper);
897 
898   helper.closeTag();
899 
900   network_server->send(part->conn, MESSAGE_TYPE_SENDING_ACTIONS, os.str());
901 }
902 
sendHistories(Participant * part)903 void GameServer::sendHistories(Participant *part)
904 {
905   std::ostringstream os;
906   XML_Helper helper(&os);
907 
908   helper.begin("1");
909   helper.openTag("histories");
910 
911   for (auto &i: part->histories)
912     {
913       std::cerr << String::ucompose("sending history %1 from person %2 %3 to person %4", History::historyTypeToString(i->getHistory()->getType()), d_nickname, Playerlist::getInstance()->getPlayer(i->getOwnerId())->getName(), part->nickname) << std::endl;
914       (*i).save(&helper);
915     }
916 
917   helper.closeTag();
918 
919   network_server->send(part->conn, MESSAGE_TYPE_SENDING_HISTORY, os.str());
920 }
921 
dumpActionsAndHistories(XML_Helper * helper,Player * player)922 bool GameServer::dumpActionsAndHistories(XML_Helper *helper, Player *player)
923 {
924   Participant *part = NULL;
925   for (auto &i: participants)
926     {
927       bool found = false;
928       for (auto &it: i->players)
929 	{
930 	  if (it.id == player->getId())
931 	    {
932 	      found = true;
933 	      break;
934 	    }
935 	}
936 
937       if (found)
938 	{
939 	  part = i;
940 	  break;
941 	}
942     }
943   if (part == NULL)
944     return false;
945   for (auto &i: part->histories)
946     (*i).save(helper);
947   for (auto &i: part->actions)
948     (*i).save(helper);
949   return true;
950 }
951 
dumpActionsAndHistories(XML_Helper * helper)952 bool GameServer::dumpActionsAndHistories(XML_Helper *helper)
953 {
954   Player *player = Playerlist::getActiveplayer();
955   return dumpActionsAndHistories(helper, player);
956 }
957 
sit_down(Player * player)958 void GameServer::sit_down (Player *player)
959 {
960   if (!player)
961     return;
962   if (player->getType() == Player::NETWORKED)
963     {
964       //alright, we want to sit down as this player
965       //convert the network player to a human player
966       dynamic_cast<NetworkPlayer*>(player)->setConnected(true);
967       RealPlayer *new_p = new RealPlayer (*player);
968       Playerlist::getInstance()->swap(player, new_p);
969       stopListeningForLocalEvents(player);
970       listenForLocalEvents(new_p);
971       delete player;
972       player = new_p;
973       add_to_player_list (players_seated_locally, new_p->getId(),
974                           new_p->getName(),
975                           GameParameters::player_type_to_player_param(new_p->getType()));
976       notifySit(new_p, d_nickname);
977     }
978   else if (player->getType() == Player::HUMAN)
979     {
980       //alright, we want to sit down as this player
981       //wait, we're already human.
982       // do nothing
983     }
984   else // an ai player
985     {
986       stopListeningForLocalEvents(player);
987       listenForLocalEvents(player);
988       add_to_player_list (players_seated_locally, player->getId(),
989                           player->getName(),
990                           GameParameters::player_type_to_player_param(player->getType()));
991       notifySit(player, d_nickname);
992     }
993   notifyTypeChange(player, player->getType());
994 }
995 
stand_up(Player * player)996 void GameServer::stand_up (Player *player)
997 {
998   if (!player)
999     return;
1000   if (player->getType() == Player::HUMAN)
1001     {
1002       //alright, we want to stand up as this player
1003       //convert the player from a human player back to a network player
1004 
1005       NetworkPlayer *new_p = new NetworkPlayer(*player);
1006       Playerlist::getInstance()->swap(player, new_p);
1007       stopListeningForLocalEvents(player);
1008       delete player;
1009       listenForLocalEvents(new_p);
1010       player = new_p;
1011       new_p->setConnected(false);
1012       notifyStand(new_p, d_nickname);
1013       remove_from_player_list (players_seated_locally, new_p->getId());
1014     }
1015   else if (player->getType() == Player::NETWORKED)
1016     {
1017       //this is the forcibly booted, made to stand-up case. .
1018       Participant *part = findParticipantByPlayerId(player->getId());
1019       stand(part->conn, player, part->nickname);
1020     }
1021   else // an ai player
1022     {
1023       stopListeningForLocalEvents(player);
1024       remove_from_player_list (players_seated_locally, player->getId());
1025       notifyStand(player, d_nickname);
1026     }
1027   notifyTypeChange(player, GameParameters::Player::NETWORKED);
1028 }
1029 
name_change(Player * player,Glib::ustring name)1030 void GameServer::name_change (Player *player, Glib::ustring name)
1031 {
1032   if (!player)
1033     return;
1034   player->rename(name);
1035   update_player_name (players_seated_locally, player->getId(), name);
1036   notifyNameChange(player, name);
1037 }
1038 
type_change(Player * player,int type)1039 void GameServer::type_change (Player *player, int type)
1040 {
1041   if (!player)
1042     return;
1043   update_player_type (players_seated_locally, player->getId(), (guint32) type);
1044   notifyTypeChange(player, type);
1045   player_changes_type.emit(player, type);
1046 }
1047 
chat(Glib::ustring message)1048 void GameServer::chat (Glib::ustring message)
1049 {
1050   notifyChat(d_nickname + ":" + message);
1051 }
1052 
notifyChat(Glib::ustring message)1053 void GameServer::notifyChat(Glib::ustring message)
1054 {
1055   gotChatMessage(d_nickname, message);
1056   for (auto &i: participants)
1057     network_server->send(i->conn, MESSAGE_TYPE_CHATTED, message);
1058 }
1059 
sendSeat(void * conn,GameParameters::Player player,Glib::ustring nickname)1060 void GameServer::sendSeat(void *conn, GameParameters::Player player, Glib::ustring nickname)
1061 {
1062   Glib::ustring payload = String::ucompose ("%1 %2 %3 %4", player.id,
1063                                             LOBBY_MESSAGE_TYPE_SIT, 1,
1064                                             nickname);
1065   network_server->send(conn, MESSAGE_TYPE_LOBBY_ACTIVITY, payload);
1066 
1067   payload = String::ucompose ("%1 %2 %3 %4", player.id,
1068                               LOBBY_MESSAGE_TYPE_CHANGE_TYPE, 1, player.type);
1069   network_server->send(conn, MESSAGE_TYPE_LOBBY_ACTIVITY, payload);
1070 
1071   payload = String::ucompose ("%1 %2 %3 %4", player.id,
1072                               LOBBY_MESSAGE_TYPE_CHANGE_NAME, 1,
1073                               player.name);
1074   network_server->send(conn, MESSAGE_TYPE_LOBBY_ACTIVITY, payload);
1075 }
1076 
sendSeats(void * conn)1077 void GameServer::sendSeats(void *conn)
1078 {
1079   Participant *part = findParticipantByConn(conn);
1080   if (!part)
1081     return;
1082   //send seatedness info for remote participants
1083 
1084   for (auto &i: participants)
1085     {
1086       if (i->conn == part->conn)
1087 	continue;
1088 
1089       for (auto &j: i->players)
1090         sendSeat(conn, j, i->nickname);
1091     }
1092   //send out seatedness info for local server
1093   for (auto &j: players_seated_locally)
1094     sendSeat(conn, j, d_nickname);
1095 }
1096 
sendChatRoster(void * conn)1097 void GameServer::sendChatRoster(void *conn)
1098 {
1099   Participant *part = findParticipantByConn(conn);
1100   if (!part)
1101     return;
1102   for (auto &i: participants)
1103     {
1104       if (i->conn == part->conn)
1105 	continue;
1106       network_server->send(part->conn, MESSAGE_TYPE_PARTICIPANT_CONNECTED,
1107 			   i->nickname);
1108     }
1109   network_server->send(part->conn, MESSAGE_TYPE_PARTICIPANT_CONNECTED,
1110 		       d_nickname);
1111 }
1112 
sendOffPlayer(Player * p)1113 void GameServer::sendOffPlayer(Player *p)
1114 {
1115   std::stringstream player;
1116   player << p->getId();
1117   for (auto &i: participants)
1118     network_server->send(i->conn, MESSAGE_TYPE_OFF_PLAYER, player.str());
1119 
1120   remote_player_died.emit(p);
1121 }
1122 
sendKillPlayer(Player * p)1123 void GameServer::sendKillPlayer(Player *p)
1124 {
1125   std::stringstream player;
1126   player << p->getId();
1127   for (auto &i: participants)
1128     network_server->send(i->conn, MESSAGE_TYPE_KILL_PLAYER, player.str());
1129 
1130   remote_player_died.emit(p);
1131 }
1132 
sendTurnOrder()1133 void GameServer::sendTurnOrder()
1134 {
1135   std::list<guint32> ids;
1136   std::stringstream players;
1137   for (auto &it: *Playerlist::getInstance())
1138     {
1139       players << it->getId() << " ";
1140       ids.push_back(it->getId());
1141     }
1142   for (auto &i: participants)
1143     network_server->send(i->conn, MESSAGE_TYPE_TURN_ORDER, players.str());
1144   playerlist_reorder_received.emit();
1145 }
1146 
gameHasBegun()1147 bool GameServer::gameHasBegun()
1148 {
1149   return d_game_has_begun;
1150 }
1151 
notifyClientsGameMayBeginNow()1152 void GameServer::notifyClientsGameMayBeginNow()
1153 {
1154   d_game_has_begun = true;
1155   syncLocalPlayers();
1156   //notify everyone that the game can finally start.
1157   for (auto &i: participants)
1158     network_server->send(i->conn, MESSAGE_TYPE_GAME_MAY_BEGIN, "");
1159 }
1160 
syncLocalPlayers()1161 void GameServer::syncLocalPlayers()
1162 {
1163   std::list<guint32> ids;
1164   for (auto &j: players_seated_locally)
1165     {
1166       Player *p = Playerlist::getInstance()->getPlayer(j.id);
1167       if (j.type == GameParameters::Player::OFF)
1168         {
1169           stopListeningForLocalEvents(p);
1170           player_gets_turned_off.emit(p);
1171           sendOffPlayer(p);
1172           ids.push_back(p->getId());
1173           Playerlist::getInstance()->syncPlayer(j);
1174         }
1175       else
1176         {
1177           stopListeningForLocalEvents(p);
1178           Playerlist::getInstance()->syncPlayer(j);
1179           listenForLocalEvents(Playerlist::getInstance()->getPlayer(j.id));
1180         }
1181     }
1182   for (auto &i: ids)
1183     remove_from_player_list (players_seated_locally, i);
1184 }
1185 
on_turn_aborted()1186 void GameServer::on_turn_aborted()
1187 {
1188   d_stop = true;
1189   remove_all_participants();
1190 }
1191 
1192 // End of file
1193