1 // ==============================================================
2 // This file is part of Glest (www.glest.org)
3 //
4 // Copyright (C) 2001-2008 Marti�o Figueroa
5 //
6 // You can redistribute this code and/or modify it under
7 // the terms of the GNU General Public License as published
8 // by the Free Software Foundation; either version 2 of the
9 // License, or (at your option) any later version
10 // ==============================================================
11
12 #include "server_interface.h"
13
14 #include <cassert>
15 #include <stdexcept>
16
17 #include "platform_util.h"
18 #include "conversion.h"
19 #include "config.h"
20 #include "lang.h"
21
22 #include "leak_dumper.h"
23
24 using namespace std;
25 using namespace Shared::Platform;
26 using namespace Shared::Util;
27
28 namespace Glest{ namespace Game{
29
30 // =====================================================
31 // class ServerInterface
32 // =====================================================
33
ServerInterface()34 ServerInterface::ServerInterface(){
35 for(int i= 0; i<GameConstants::maxPlayers; ++i){
36 slots[i]= NULL;
37 }
38 serverSocket.setBlock(false);
39 serverSocket.bind(GameConstants::serverPort);
40 }
41
~ServerInterface()42 ServerInterface::~ServerInterface(){
43 for(int i= 0; i<GameConstants::maxPlayers; ++i){
44 delete slots[i];
45 }
46 }
47
addSlot(int playerIndex)48 void ServerInterface::addSlot(int playerIndex){
49 assert(playerIndex>=0 && playerIndex<GameConstants::maxPlayers);
50
51 delete slots[playerIndex];
52 slots[playerIndex]= new ConnectionSlot(this, playerIndex);
53 updateListen();
54 }
55
removeSlot(int playerIndex)56 void ServerInterface::removeSlot(int playerIndex){
57 delete slots[playerIndex];
58 slots[playerIndex]= NULL;
59 updateListen();
60 }
61
getSlot(int playerIndex)62 ConnectionSlot* ServerInterface::getSlot(int playerIndex){
63 return slots[playerIndex];
64 }
65
getConnectedSlotCount()66 int ServerInterface::getConnectedSlotCount(){
67 int connectedSlotCount= 0;
68
69 for(int i= 0; i<GameConstants::maxPlayers; ++i){
70 if(slots[i]!= NULL){
71 ++connectedSlotCount;
72 }
73 }
74 return connectedSlotCount;
75 }
76
update()77 void ServerInterface::update(){
78
79 //update all slots
80 for(int i= 0; i<GameConstants::maxPlayers; ++i){
81 if(slots[i]!= NULL){
82 slots[i]->update();
83 }
84 }
85
86 //process text messages
87 chatText.clear();
88 chatSender.clear();
89 chatTeamIndex= -1;
90
91 for(int i= 0; i<GameConstants::maxPlayers; ++i){
92 ConnectionSlot* connectionSlot= slots[i];
93
94 if(connectionSlot!= NULL){
95 if(connectionSlot->isConnected()){
96 if(connectionSlot->getNextMessageType()==nmtText){
97 NetworkMessageText networkMessageText;
98 if(connectionSlot->receiveMessage(&networkMessageText)){
99 broadcastMessage(&networkMessageText, i);
100 chatText= networkMessageText.getText();
101 chatSender= networkMessageText.getSender();
102 chatTeamIndex= networkMessageText.getTeamIndex();
103 break;
104 }
105 }
106 }
107 }
108 }
109 }
110
updateKeyframe(int frameCount)111 void ServerInterface::updateKeyframe(int frameCount){
112
113 NetworkMessageCommandList networkMessageCommandList(frameCount);
114
115 //build command list, remove commands from requested and add to pending
116 while(!requestedCommands.empty()){
117 if(networkMessageCommandList.addCommand(&requestedCommands.back())){
118 pendingCommands.push_back(requestedCommands.back());
119 requestedCommands.pop_back();
120 }
121 else{
122 break;
123 }
124 }
125
126 //broadcast commands
127 broadcastMessage(&networkMessageCommandList);
128 }
129
waitUntilReady(Checksum * checksum)130 void ServerInterface::waitUntilReady(Checksum* checksum){
131
132 Chrono chrono;
133 bool allReady= false;
134
135 chrono.start();
136
137 //wait until we get a ready message from all clients
138 while(!allReady){
139
140 allReady= true;
141 for(int i= 0; i<GameConstants::maxPlayers; ++i){
142 ConnectionSlot* connectionSlot= slots[i];
143
144 if(connectionSlot!=NULL){
145 if(!connectionSlot->isReady()){
146 NetworkMessageType networkMessageType= connectionSlot->getNextMessageType();
147 NetworkMessageReady networkMessageReady;
148
149 if(networkMessageType==nmtReady && connectionSlot->receiveMessage(&networkMessageReady)){
150 connectionSlot->setReady();
151 }
152 else if(networkMessageType!=nmtInvalid){
153 throw runtime_error("Unexpected network message: " + intToStr(networkMessageType));
154 }
155
156 allReady= false;
157 }
158 }
159 }
160
161 //check for timeout
162 if(chrono.getMillis()>readyWaitTimeout){
163 throw runtime_error("Timeout waiting for clients");
164 }
165 }
166
167 //send ready message after, so clients start delayed
168 for(int i= 0; i<GameConstants::maxPlayers; ++i){
169 NetworkMessageReady networkMessageReady(checksum->getSum());
170 ConnectionSlot* connectionSlot= slots[i];
171
172 if(connectionSlot!=NULL){
173 connectionSlot->sendMessage(&networkMessageReady);
174 }
175 }
176 }
177
sendTextMessage(const string & text,int teamIndex)178 void ServerInterface::sendTextMessage(const string &text, int teamIndex){
179 NetworkMessageText networkMessageText(text, getHostName(), teamIndex);
180 broadcastMessage(&networkMessageText);
181 }
182
quitGame()183 void ServerInterface::quitGame(){
184 NetworkMessageQuit networkMessageQuit;
185 broadcastMessage(&networkMessageQuit);
186 }
187
getNetworkStatus() const188 string ServerInterface::getNetworkStatus() const{
189 Lang &lang= Lang::getInstance();
190 string str;
191
192 for(int i= 0; i<GameConstants::maxPlayers; ++i){
193 ConnectionSlot* connectionSlot= slots[i];
194
195 str+= intToStr(i)+ ": ";
196
197 if(connectionSlot!= NULL){
198 if(connectionSlot->isConnected()){
199 str+= connectionSlot->getName();
200 }
201 }
202 else
203 {
204 str+= lang.get("NotConnected");
205 }
206
207 str+= '\n';
208 }
209 return str;
210 }
211
launchGame(const GameSettings * gameSettings)212 void ServerInterface::launchGame(const GameSettings* gameSettings){
213 NetworkMessageLaunch networkMessageLaunch(gameSettings);
214 broadcastMessage(&networkMessageLaunch);
215 }
216
broadcastMessage(const NetworkMessage * networkMessage,int excludeSlot)217 void ServerInterface::broadcastMessage(const NetworkMessage* networkMessage, int excludeSlot){
218 for(int i= 0; i<GameConstants::maxPlayers; ++i){
219 ConnectionSlot* connectionSlot= slots[i];
220
221 if(i!= excludeSlot && connectionSlot!= NULL){
222 if(connectionSlot->isConnected()){
223 connectionSlot->sendMessage(networkMessage);
224 }
225 else{
226 removeSlot(i);
227 }
228 }
229 }
230 }
231
updateListen()232 void ServerInterface::updateListen(){
233 int openSlotCount= 0;
234
235 for(int i= 0; i<GameConstants::maxPlayers; ++i){
236 if(slots[i]!= NULL && !slots[i]->isConnected()){
237 ++openSlotCount;
238 }
239 }
240
241 serverSocket.listen(openSlotCount);
242 }
243
244 }}//end namespace
245