1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2011
3 //
4 // This file is part of Scorched3D.
5 //
6 // Scorched3D is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // Scorched3D is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20
21 #include <server/ScorchedServer.h>
22 #include <server/ServerSimulator.h>
23 #include <server/ServerState.h>
24 #include <server/ServerDestinations.h>
25 #include <server/ServerAuthHandlerStore.h>
26 #include <server/ServerTimedMessage.h>
27 #include <server/ServerBanned.h>
28 #include <server/ServerTextFilter.h>
29 #include <server/ServerHandlers.h>
30 #include <server/ServerLoadLevel.h>
31 #include <server/ServerChannelManager.h>
32 #include <server/ServerAdminSessions.h>
33 #include <server/ServerSyncCheck.h>
34 #include <server/ServerMessageHandler.h>
35 #include <server/ServerFileServer.h>
36 #include <common/OptionsScorched.h>
37 #include <common/OptionsTransient.h>
38 #include <common/Logger.h>
39 #include <engine/ModFiles.h>
40 #include <engine/ActionController.h>
41 #include <engine/SaveGame.h>
42 #include <tank/TankDeadContainer.h>
43 #include <target/TargetContainer.h>
44 #include <tank/TankModelStore.h>
45 #include <tanket/TanketTypes.h>
46 #include <tankai/TankAIStrings.h>
47 #include <tankai/TankAIStore.h>
48 #include <tankai/TankAIWeaponSets.h>
49 #include <tankai/TankAIAdder.h>
50 #include <target/TargetSpace.h>
51 #include <landscapedef/LandscapeDefinitions.h>
52 #include <coms/ComsSimulateResultMessage.h>
53 #include <lua/LUAScriptHook.h>
54 #include <weapons/EconomyStore.h>
55 #include <weapons/AccessoryStore.h>
56 #include <net/NetServerTCP3.h>
57 #include <net/NetLoopBack.h>
58
59 #ifndef S3D_SERVER
60 #include <client/ClientParams.h>
61 #include <client/ScorchedClient.h>
62 #include <console/ConsoleRuleMethodIAdapter.h>
63 #endif
64
65 ScorchedServer *ScorchedServer::instance_ = 0;
66 static ScorchedServer *instanceLock = 0;
67 bool ScorchedServer::started_ = false;
68 TargetSpace *ScorchedServer::targetSpace_ = new TargetSpace();
69
instance()70 ScorchedServer *ScorchedServer::instance()
71 {
72 return instance_;
73 }
74
startServer(const ScorchedServerSettings & settings,bool local,ProgressCounter * counter)75 bool ScorchedServer::startServer(const ScorchedServerSettings &settings,
76 bool local, ProgressCounter *counter)
77 {
78 #ifndef S3D_SERVER
79 if (ClientParams::instance()->getConnectedToServer() &&
80 ScorchedClient::instance()->getTargetContainer().getCurrentDestinationId() != 0)
81 {
82 DIALOG_ASSERT(0);
83 }
84 #endif
85
86 stopServer();
87
88 DIALOG_ASSERT(!instanceLock);
89 instanceLock = new ScorchedServer;
90 instance_ = instanceLock;
91 instanceLock = 0;
92
93 started_ = instance_->startServerInternal(settings, local, counter);
94 return started_;
95 }
96
stopServer()97 void ScorchedServer::stopServer()
98 {
99 if (instance_)
100 {
101 delete instance_;
102 instance_ = 0;
103 }
104 started_ = false;
105 }
106
ScorchedServer()107 ScorchedServer::ScorchedServer() :
108 ScorchedContext("Server")
109 {
110 targetSpace_->setContext(this);
111
112 economyStore_ = new EconomyStore();
113 serverState_ = new ServerState();
114 serverFileServer_ = new ServerFileServer();
115 serverSimulator_ = new ServerSimulator();
116 serverSimulator_->setScorchedContext(this);
117 serverDestinations_ = new ServerDestinations();
118 deadContainer_ = new TankDeadContainer();
119 tankAIStore_ = new TankAIStore();
120 authHandler_ = new ServerAuthHandlerStore();
121 timedMessage_ = new ServerTimedMessage();
122 bannedPlayers_ = new ServerBanned();
123 textFilter_ = new ServerTextFilter();
124 serverLoadLevel_ = new ServerLoadLevel(getComsMessageHandler());
125 serverChannelManager_ = new ServerChannelManager(getComsMessageHandler());
126 serverAdminSessions_ = new ServerAdminSessions();
127 serverSyncCheck_ = new ServerSyncCheck(getComsMessageHandler());
128 serverHandlers_ = new ServerHandlers(getComsMessageHandler());
129 getComsMessageHandler().addHandler(
130 ComsSimulateResultMessage::ComsSimulateResultMessageType,
131 serverSimulator_);
132 getLUAScriptHook().addHookProvider("server_channeltext");
133
134 serverMessageHandler_ = new ServerMessageHandler();
135 getComsMessageHandler().setConnectionHandler(serverMessageHandler_);
136 }
137
~ScorchedServer()138 ScorchedServer::~ScorchedServer()
139 {
140 targetSpace_->clear();
141 delete deadContainer_;
142 delete tankAIStore_;
143 delete serverSimulator_;
144 delete serverDestinations_;
145 delete serverState_;
146 delete authHandler_;
147 delete timedMessage_;
148 delete bannedPlayers_;
149 delete textFilter_;
150 delete serverHandlers_;
151 delete serverLoadLevel_;
152 delete serverChannelManager_;
153 delete serverAdminSessions_;
154 delete serverSyncCheck_;
155 delete serverMessageHandler_;
156 delete serverFileServer_;
157 delete economyStore_;
158 }
159
getSimulator()160 Simulator &ScorchedServer::getSimulator()
161 {
162 return *serverSimulator_;
163 }
164
getAuthHandler()165 ServerAuthHandler *ScorchedServer::getAuthHandler()
166 {
167 return authHandler_->getAuthHandler();
168 }
169
getServerConnectAuthHandler()170 ServerConnectAuthHandler &ScorchedServer::getServerConnectAuthHandler()
171 {
172 return serverHandlers_->getServerConnectAuthHandler();
173 }
174
startServerInternal(const ScorchedServerSettings & settings,bool local,ProgressCounter * counter)175 bool ScorchedServer::startServerInternal(const ScorchedServerSettings &settings,
176 bool local, ProgressCounter *counter)
177 {
178 Logger::log(S3D::formatStringBuffer("Scorched3D - Version %s (%s) - %s",
179 S3D::ScorchedVersion.c_str(),
180 S3D::ScorchedProtocolVersion.c_str(),
181 S3D::ScorchedBuildTime.c_str()));
182
183 std::string settingsType = ((ScorchedServerSettings &) settings).type();
184 if (settingsType == "FILE")
185 {
186 ScorchedServerSettingsOptions &options = (ScorchedServerSettingsOptions &) settings;
187
188 // Load options
189 getOptionsGame().getMainOptions().readOptionsFromFile(options.settingsFile_);
190 if (options.rewriteOptions_)
191 {
192 getOptionsGame().getMainOptions().writeOptionsToFile(
193 options.settingsFile_,
194 options.writeFullOptions_);
195 }
196 }
197 else if (settingsType == "SAVE")
198 {
199 ScorchedServerSettingsSave &options = (ScorchedServerSettingsSave &) settings;
200
201 // Load the saved game state (settings)
202 if (!SaveGame::loadState(options.saveFile_))
203 {
204 S3D::dialogExit("Scorched3D", S3D::formatStringBuffer(
205 "Cannot load save file \"%s\".",
206 options.saveFile_.c_str()),
207 false);
208 }
209 }
210 else
211 {
212 S3D::dialogExit("Scorched3D", "ScorchedServer::startServerInternal - Unknown settings type");
213 }
214
215 // Setup the message handling classes
216 if (local)
217 {
218 setNetInterface(new NetLoopBack(true));
219 }
220 else
221 {
222 // Only create a net server for the actual multiplayer case
223 // A loopback is created by the client for a single player game
224 setNetInterface(new NetServerTCP3());
225 }
226
227 getOptionsGame().updateChangeSet();
228 getNetInterface().setMessageHandler(&getComsMessageHandler());
229
230 // Set the mod
231 S3D::setDataFileMod(getOptionsGame().getMod());
232
233 // Load mod
234 #ifdef S3D_SERVER
235 {
236 if (!getModFiles().loadModFiles(getOptionsGame().getMod(), false, counter)) return false;
237 }
238 #endif
239
240 // Parse config
241 if (!getAccessoryStore().parseFile(getContext(), counter)) return false;
242 if (!getTanketTypes().loadTanketTypes(getContext())) return false;
243 if (!getTankModels().loadTankMeshes(getContext(), 2, counter)) return false;
244 getOptionsTransient().reset();
245 if (!getLandscapes().readLandscapeDefinitions()) return false;
246
247 // Add the server side bots
248 // Add any new AIs
249 if (!getTankAIs().loadAIs()) return false;
250 TankAIAdder::addTankAIs(*this);
251 getTankAIStrings().load();
252
253 checkSettings();
254
255 // Load all script hooks
256 if (!getLUAScriptHook().loadHooks()) return false;
257
258 #ifndef S3D_SERVER
259 new ConsoleRuleMethodIAdapter<ActionController>(
260 &getActionController(),
261 &ActionController::logActions, "ActionsLog");
262 new ConsoleRuleMethodIAdapter<ActionController>(
263 &getActionController(),
264 &ActionController::startActionProfiling, "ActionsProfilingStart");
265 new ConsoleRuleMethodIAdapter<ActionController>(
266 &getActionController(),
267 &ActionController::stopActionProfiling, "ActionsProfilingStop");
268 #endif
269
270 return true;
271 }
272
checkSettings()273 void ScorchedServer::checkSettings()
274 {
275 getLandscapes().checkEnabled(getOptionsGame());
276
277 if (getOptionsGame().getTeamBallance() == OptionsGame::TeamBallanceBotsVs &&
278 getOptionsGame().getTeams() > 2)
279 {
280 S3D::dialogExit("ScorchedServer",
281 "Cannot start a game with more than 2 teams in the bots vs mode");
282 }
283 }
284