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