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