gamehost.cpp
1 //------------------------------------------------------------------------------
2 // gamehost.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301, USA.
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2013 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "gamehost.h"
24 
25 #include "plugins/engineplugin.h"
26 #include "serverapi/gamecreateparams.h"
27 #include "serverapi/message.h"
29 #include "apprunner.h"
30 #include "gamedemo.h"
31 #include <cassert>
32 #include <QFileInfo>
33 #include <QStringList>
34 
35 #define BAIL_ON_ERROR(method) \
36 { \
37  method; \
38  if (d->message.isError()) \
39  { \
40  return; \
41  } \
42 }
43 
44 DClass<GameHost>
45 {
46  public:
47  QString argBexLoading;
48  QString argDehLoading;
49  QString argIwadLoading;
50  QString argOptionalWadLoading;
51  QString argPort;
52  QString argPwadLoading;
53  QString argDemoPlayback;
54  QString argDemoRecord;
55  QString argServerLaunch;
56 
57  CommandLineInfo* currentCmdLine;
58  Message message;
59  GameCreateParams params;
60  EnginePlugin* plugin;
61 
62  void (GameHost::*addIwad)();
63  void (GameHost::*addPwads)();
64  void (GameHost::*addDMFlags)();
65 };
66 
67 DPointered(GameHost)
68 
70 {
71  d->argBexLoading = "-deh";
72  d->argDehLoading = "-deh";
73  d->argIwadLoading = "-iwad";
74  d->argOptionalWadLoading = "-file";
75  d->argPort = "-port";
76  d->argPwadLoading = "-file";
77  d->argDemoPlayback = "-playdemo";
78  d->argDemoRecord = "-record";
79  d->currentCmdLine = NULL;
80  d->plugin = plugin;
81 
82  set_addIwad(&GameHost::addIwad_default);
83  set_addPwads(&GameHost::addPwads_default);
84  set_addDMFlags(&GameHost::addDMFlags_default);
85 }
86 
87 GameHost::~GameHost()
88 {
89 }
90 
91 POLYMORPHIC_DEFINE(void, GameHost, addIwad, (), ());
92 POLYMORPHIC_DEFINE(void, GameHost, addPwads, (), ());
93 POLYMORPHIC_DEFINE(void, GameHost, addDMFlags, (), ());
94 
96 {
97  args().append(params().customParameters());
98 }
99 
100 void GameHost::addDemoPlaybackIfApplicable()
101 {
102  if (params().hostMode() == GameCreateParams::Demo)
103  {
104  args() << argForDemoPlayback();
105  args() << params().demoPath();
106  }
107 }
108 
109 void GameHost::addDemoRecordIfApplicable()
110 {
111  if (params().hostMode() == GameCreateParams::Offline
112  && params().demoRecord() != GameDemo::NoDemo)
113  {
114  args() << argForDemoRecord();
115  args() << params().demoPath();
116  }
117 }
118 
119 void GameHost::addDMFlags_default()
120 {
121 }
122 
124 {
125 }
126 
127 void GameHost::addIwad_default()
128 {
129  const QString& iwadPath = params().iwadPath();
130 
131  if (iwadPath.isEmpty())
132  {
133  setMessage(Message::customError(tr("Iwad is not set")));
134  return;
135  }
136 
137  QFileInfo fi(iwadPath);
138 
139  if (!fi.isFile())
140  {
141  QString error = tr("Iwad Path error:\n\"%1\" doesn't exist or is a directory!").arg(iwadPath);
143  }
144 
145  args() << argForIwadLoading() << iwadPath;
146 }
147 
148 void GameHost::addPwads_default()
149 {
150  const QList<bool> &pwadsOptional = params().pwadsOptional();
151  for(int i = 0;i < params().pwadsPaths().size();++i)
152  {
153  const QString &pwad = params().pwadsPaths()[i];
154 
155  QFileInfo fi(pwad);
156  if (!fi.isFile())
157  {
158  QString error = tr("Pwad path error:\n\"%1\" doesn't exist or is a directory!").arg(pwad);
160  return;
161  }
162  if (pwad.toLower().endsWith(".deh"))
163  {
164  args() << argForDehLoading() << pwad;
165  }
166  else if (pwad.toLower().endsWith(".bex"))
167  {
168  args() << argForBexLoading() << pwad;
169  }
170  else
171  {
172  if(pwadsOptional.size() > i && pwadsOptional[i])
173  args() << argForOptionalWadLoading() << pwad;
174  else
175  args() << argForPwadLoading() << pwad;
176  }
177  }
178 }
179 
180 const QString& GameHost::argForBexLoading() const
181 {
182  return d->argBexLoading;
183 }
184 
185 const QString& GameHost::argForDehLoading() const
186 {
187  return d->argDehLoading;
188 }
189 
190 const QString& GameHost::argForIwadLoading() const
191 {
192  return d->argIwadLoading;
193 }
194 
196 {
197  return d->argOptionalWadLoading;
198 }
199 
200 const QString& GameHost::argForPort() const
201 {
202  return d->argPort;
203 }
204 
205 const QString& GameHost::argForPwadLoading() const
206 {
207  return d->argPwadLoading;
208 }
209 
210 const QString& GameHost::argForDemoPlayback() const
211 {
212  return d->argDemoPlayback;
213 }
214 
215 const QString& GameHost::argForDemoRecord() const
216 {
217  return d->argDemoRecord;
218 }
219 
220 const QString& GameHost::argForServerLaunch() const
221 {
222  return d->argServerLaunch;
223 }
224 
225 QStringList &GameHost::args()
226 {
227  return d->currentCmdLine->args;
228 }
229 
231 {
232  BAIL_ON_ERROR(addIwad());
233  BAIL_ON_ERROR(addPwads());
234 
235  // Port
236  if (params().hostMode() == GameCreateParams::Host && params().port() > 0)
237  {
238  args() << argForPort() << QString::number(params().port());
239  }
240 
241  // CVars
242  const QList<GameCVar> &cvars = params().cvars();
243  foreach (const GameCVar &c, cvars)
244  {
245  args() << QString(c.command()) << c.valueString();
246  }
247 
248  if (params().hostMode() == GameCreateParams::Host)
249  {
250  // Some games may not offer such argument.
251  if (!argForServerLaunch().isEmpty())
252  {
253  args() << argForServerLaunch();
254  }
255  }
256 
257  BAIL_ON_ERROR(addDMFlags());
258  BAIL_ON_ERROR(addExtra());
259  BAIL_ON_ERROR(addCustomParameters());
260 
261  addDemoPlaybackIfApplicable();
262  addDemoRecordIfApplicable();
263  saveDemoMetaData();
264 }
265 
267 {
268  d->message = Message();
269  d->currentCmdLine = &cmdLine;
270  d->params = params;
271 
272  args().clear();
273 
274  setupGamePaths();
275  if (d->message.isError())
276  {
277  return d->message;
278  }
279 
281  return d->message;
282 }
283 
285 {
286  CommandLineInfo cmdLine;
287 
288  Message message = createHostCommandLine(params, cmdLine);
289  if (!message.isIgnore())
290  {
291  return message;
292  }
293 
294 #ifdef Q_OS_WIN32
295  const bool WRAP_IN_SSS_CONSOLE = false;
296 #else
297  const bool WRAP_IN_SSS_CONSOLE = params.hostMode() == GameCreateParams::Host;
298 #endif
299 
300  if (WRAP_IN_SSS_CONSOLE)
301  {
302  QIcon icon;
303  if (plugin() != NULL)
304  {
305  icon = plugin()->icon();
306  }
308  return Message();
309  }
310  else
311  {
312  return AppRunner::runExecutable(cmdLine);
313  }
314 }
315 
317 {
318  return d->params;
319 }
320 
322 {
323  return d->plugin;
324 }
325 
326 void GameHost::saveDemoMetaData()
327 {
328  if (params().demoRecord() == GameDemo::Managed)
329  {
330  GameDemo::saveDemoMetaData(params().demoPath(), *plugin(),
331  params().iwadName(), params().pwadsNames());
332  }
333 }
334 
335 void GameHost::setArgForBexLoading(const QString& arg)
336 {
337  d->argBexLoading = arg;
338 }
339 
340 void GameHost::setArgForDehLoading(const QString& arg)
341 {
342  d->argDehLoading = arg;
343 }
344 
345 void GameHost::setArgForIwadLoading(const QString& arg)
346 {
347  d->argIwadLoading = arg;
348 }
349 
350 void GameHost::setArgForOptionalWadLoading(const QString& arg)
351 {
352  d->argOptionalWadLoading = arg;
353 }
354 
355 void GameHost::setArgForPort(const QString& arg)
356 {
357  d->argPort = arg;
358 }
359 
360 void GameHost::setArgForPwadLoading(const QString& arg)
361 {
362  d->argPwadLoading = arg;
363 }
364 
365 void GameHost::setArgForDemoPlayback(const QString& arg)
366 {
367  d->argDemoPlayback = arg;
368 }
369 
370 void GameHost::setArgForDemoRecord(const QString& arg)
371 {
372  d->argDemoRecord = arg;
373 }
374 
375 void GameHost::setArgForServerLaunch(const QString& arg)
376 {
377  d->argServerLaunch = arg;
378 }
379 
380 void GameHost::setMessage(const Message& message)
381 {
382  d->message = message;
383 }
384 
385 void GameHost::setupGamePaths()
386 {
387  QFileInfo fileInfo(params().executablePath());
388  if (!fileInfo.isFile() && !fileInfo.isBundle())
389  {
390  QString error = tr("%1\n doesn't exist or is not a file.").arg(fileInfo.filePath());
392  return;
393  }
394  d->currentCmdLine->executable = params().executablePath();
395  d->currentCmdLine->applicationDir = fileInfo.dir();
396 }
EnginePlugin * plugin() const
EnginePlugin that this GameHost is associated with.
Definition: gamehost.cpp:321
Game parametrization data used when creating new games.
Structure holding parameters for application launch.
Definition: apprunner.h:37
Message object used to pass messages throughout the Doomseeker's system.
Definition: message.h:62
const QString & argForBexLoading() const
Command line parameter that is used to load a BEX file.
Definition: gamehost.cpp:180
const QString & argForDemoPlayback() const
Command line parameter for playing back a demo.
Definition: gamehost.cpp:210
const QString & argForPort() const
Command line parameter that is used to set network port for the game.
Definition: gamehost.cpp:200
const QString & argForServerLaunch() const
Command line parameter used to launch a server.
Definition: gamehost.cpp:220
void setMessage(const Message &message)
Call this method to convey errors.
Definition: gamehost.cpp:380
const QString & executablePath() const
Path to the game executable.
const QString & demoPath() const
Use if running in HostMode::Demo mode or recording a demo.
const GameCreateParams & params() const
GameCreateParams with which this game should be configured.
Definition: gamehost.cpp:316
const QString & argForOptionalWadLoading() const
Command line parameter that is used to load optional WADs.
Definition: gamehost.cpp:195
virtual void addCustomParameters()
"Custom parameters" are specified directly by user in "Create Game" dialog box.
Definition: gamehost.cpp:95
bool isIgnore() const
True for 'Null' messages.
Definition: message.cpp:109
void addDMFlags()
[Virtual] Creates engine specific command line parameters out of passed DM flags list.
const QString & argForPwadLoading() const
Command line parameter that is used to load a PWAD.
Definition: gamehost.cpp:205
void addPwads()
[Virtual] Loads PWADs and other mod files (dehacked patches, pk3s, etc.)
static void runExecutableWrappedInStandardServerConsole(const QIcon &icon, const CommandLineInfo &cli)
Executes predefined command line.
Definition: apprunner.cpp:116
QStringList & args()
Reference to command line arguments.
Definition: gamehost.cpp:225
virtual void createCommandLineArguments()
Builds command line arguments sequentially by calling other methods.
Definition: gamehost.cpp:230
Message createHostCommandLine(const GameCreateParams &params, CommandLineInfo &cmdLine)
Definition: gamehost.cpp:266
QList< GameCVar > & cvars()
Contents of this list will be passed as "+consoleCommand value" to the command line.
Creates game servers, offline games or demo playbacks.
Definition: gamehost.h:69
const QString & argForDemoRecord() const
Command line parameter for recording a demo.
Definition: gamehost.cpp:215
const QString & argForIwadLoading() const
Command line parameter that is used to set IWAD.
Definition: gamehost.cpp:190
Message host(const GameCreateParams &params)
Definition: gamehost.cpp:284
void addIwad()
[Virtual] Loads IWAD.
static Message customError(const QString &content)
Convenience method. Sets type to Type::CUSTOM_ERROR.
Definition: message.h:122
A general game setting or variable (like fraglimit).
const QString & command() const
Command-line argument that sets this GameCVar.
virtual void addExtra()
Creates engine specific command line parameters out of Server class fields.
Definition: gamehost.cpp:123
const QString & argForDehLoading() const
Command line parameter that is used to load a DEHACKED file.
Definition: gamehost.cpp:185