23 #include "gameclientrunner.h"
25 #include "apprunner.h"
26 #include "commandlinetokenizer.h"
27 #include "configuration/doomseekerconfig.h"
28 #include "gui/checkwadsdlg.h"
29 #include "ini/inisection.h"
30 #include "ini/inivariable.h"
32 #include "pathfinder/pathfinder.h"
33 #include "pathfinder/wadpathfinder.h"
34 #include "plugins/engineplugin.h"
35 #include "serverapi/exefile.h"
36 #include "serverapi/gameexeretriever.h"
37 #include "serverapi/message.h"
38 #include "serverapi/server.h"
39 #include "templatedpathresolver.h"
42 #include <QScopedPointer>
43 #include <QStringList>
45 DClass<ServerConnectParams>
48 QString connectPassword;
50 QString inGamePassword;
70 ServerConnectParams::~ServerConnectParams()
76 return d->connectPassword;
86 return d->inGamePassword;
89 void ServerConnectParams::setConnectPassword(
const QString &val)
91 d->connectPassword = val;
94 void ServerConnectParams::setDemoName(
const QString &val)
99 void ServerConnectParams::setInGamePassword(
const QString &val)
101 d->inGamePassword = val;
104 #define BAIL_ON_ERROR(method) \
107 if (isFatalError()) \
114 DClass<GameClientRunner>
117 QString argBexLoading;
119 QString argConnectPassword;
120 QString argDehLoading;
121 QString argInGamePassword;
122 QString argIwadLoading;
123 QString argOptionalWadLoading;
125 QString argPwadLoading;
126 QString argDemoRecord;
129 mutable QString cachedIwadPath;
133 QList<PWad> missingPwads;
134 QList<PWad> incompatiblePwads;
151 POLYMORPHIC_DEFINE(
void, GameClientRunner, addExtra, (), ())
152 POLYMORPHIC_DEFINE(
void, GameClientRunner, addGamePaths, (), ())
153 POLYMORPHIC_DEFINE(
void, GameClientRunner, addInGamePassword, (), ())
154 POLYMORPHIC_DEFINE(
void, GameClientRunner, addIwad, (), ())
155 POLYMORPHIC_DEFINE(
void, GameClientRunner, addModFiles, (const QStringList &files), (files))
156 POLYMORPHIC_DEFINE(
void, GameClientRunner, addPassword, (), ())
157 POLYMORPHIC_DEFINE(
void, GameClientRunner, createCommandLineArguments, (), ())
159 GameClientRunner::GameClientRunner(ServerPtr server)
161 set_addConnectCommand(&GameClientRunner::addConnectCommand_default);
162 set_addGamePaths(&GameClientRunner::addGamePaths_default);
163 set_addExtra(&GameClientRunner::addExtra_default);
164 set_addInGamePassword(&GameClientRunner::addInGamePassword_default);
165 set_addIwad(&GameClientRunner::addIwad_default);
166 set_addModFiles(&GameClientRunner::addModFiles_default);
167 set_addPassword(&GameClientRunner::addPassword_default);
168 set_createCommandLineArguments(&GameClientRunner::createCommandLineArguments_default);
169 d->argBexLoading =
"-deh";
170 d->argConnect =
"-connect";
171 d->argDehLoading =
"-deh";
172 d->argIwadLoading =
"-iwad";
173 d->argOptionalWadLoading =
"-file";
174 d->argPort =
"-port";
175 d->argPwadLoading =
"-file";
176 d->argDemoRecord =
"-record";
181 GameClientRunner::~GameClientRunner()
185 void GameClientRunner::addConnectCommand_default()
187 QString address = QString(
"%1:%2").arg(d->server->address().toString()).arg(d->server->port());
193 IniSection config = gConfig.iniSectionForPlugin(d->server->plugin());
194 QString customParameters = config[
"CustomParameters"];
196 args() << tokenizer.tokenize(customParameters);
204 void GameClientRunner::addGamePaths_default()
206 GamePaths paths = gamePaths();
207 if (!paths.isValid())
213 QDir applicationDir = paths.workingDir;
214 if (paths.workingDir.isEmpty())
216 d->joinError.setType(JoinError::ConfigurationError);
217 d->joinError.setError(tr(
"Cannot determine the working directory for \"%1\". "
218 "Check the game configuration.")
222 else if (!applicationDir.exists())
224 d->joinError.setType(JoinError::ConfigurationError);
225 d->joinError.setError(tr(
"This path cannot be used as the working directory for %1:\n%2.")
226 .arg(pluginName(), paths.workingDir));
230 setExecutable(paths.clientExe);
231 setWorkingDir(applicationDir.path());
234 void GameClientRunner::addInGamePassword_default()
242 gLog << tr(
"BUG: Plugin doesn't specify argument for in-game "
243 "password, but the server requires such password.");
247 void GameClientRunner::addExtra_default()
251 void GameClientRunner::addIwad_default()
261 if (!d->incompatiblePwads.isEmpty())
263 d->joinError.setIncompatibleWads(d->incompatiblePwads);
264 d->joinError.setType(JoinError::MissingWads);
266 if (!isIwadFound() || !d->missingPwads.isEmpty())
270 d->joinError.setMissingIwad(d->server->iwad());
271 d->joinError.setType(JoinError::MissingWads);
273 d->joinError.setMissingWads(d->missingPwads);
274 for (
const PWad &wad : d->missingPwads)
279 d->joinError.setType(JoinError::MissingWads);
286 void GameClientRunner::addPassword_default()
294 gLog << tr(
"BUG: Plugin doesn't specify argument for connect "
295 "password, but the server is passworded.");
302 checkWadsDlg->addWads(d->server->wads());
303 const CheckResult checkResults = checkWadsDlg->checkWads();
304 for (
const PWad &wad : checkResults.missingWads)
308 for (
const PWad &wad : checkResults.incompatibleWads)
313 for (
const PWad &wad : checkResults.foundWads)
320 void GameClientRunner::addModFiles_default(
const QStringList &files)
322 for (
const QString &file : files)
324 args() << fileLoadingPrefix(file) << QFileInfo(file).absoluteFilePath();
330 QMap<QString, QStringList> groups;
331 for (
const QString &file : files)
333 QString prefix = fileLoadingPrefix(file);
334 groups[prefix] << file;
336 for (
const QString &prefix : groups.keys())
339 for (
const QString &file : groups[prefix])
346 QString GameClientRunner::fileLoadingPrefix(
const QString &file)
const
348 if (file.toLower().endsWith(
".deh"))
352 else if (file.toLower().endsWith(
".bex"))
354 return argForBexLoading();
364 const QString &GameClientRunner::argForBexLoading()
const
366 return d->argBexLoading;
371 return d->argConnect;
376 return d->argConnectPassword;
381 return d->argDehLoading;
386 return d->argInGamePassword;
391 return d->argIwadLoading;
396 return d->argOptionalWadLoading;
406 return d->argPwadLoading;
411 return d->argDemoRecord;
414 bool GameClientRunner::canDownloadWadsInGame()
const
416 return d->server->plugin()->data()->inGameFileDownloads;
421 return d->connectParams.connectPassword();
424 void GameClientRunner::createCommandLineArguments_default()
428 if (d->server->isLocked())
432 if (d->server->isLockedInGame())
449 d->cli->args.clear();
450 d->connectParams = params;
454 if (d->joinError.isError())
465 return d->connectParams.demoName();
468 QString GameClientRunner::findIwad()
const
470 return findWad(d->server->iwad().toLower());
478 GameClientRunner::GamePaths GameClientRunner::gamePaths()
483 QScopedPointer<ExeFile> exeFile(d->server->clientExe());
484 result.clientExe = exeFile->pathToExe(msg);
485 if (result.clientExe.isEmpty())
492 d->joinError.setError(msg.
contents());
496 d->joinError.setError(tr(
"The game can be installed by Doomseeker."));
501 d->joinError.setType(JoinError::ConfigurationError);
504 d->joinError.setError(msg.
contents());
508 d->joinError.setError(tr(
"Couldn't find game %1."));
513 result.workingDir = exeFile->workingDirectory(msg);
519 return d->connectParams.inGamePassword();
522 bool GameClientRunner::isFatalError()
const
524 if (d->joinError.isError())
526 if (d->joinError.isMissingWadsError() && canDownloadWadsInGame())
535 bool GameClientRunner::isIwadFound()
const
537 return !d->cachedIwadPath.isEmpty();
540 const QString &GameClientRunner::iwadPath()
const
544 d->cachedIwadPath = findIwad();
546 return d->cachedIwadPath;
551 d->missingPwads << pwadName;
556 d->incompatiblePwads << pwadName;
561 return d->pathFinder;
564 const QString &GameClientRunner::pluginName()
const
566 return d->server->plugin()->data()->name;
571 return d->connectParams;
574 void GameClientRunner::setArgForBexLoading(
const QString &arg)
576 d->argBexLoading = arg;
579 void GameClientRunner::setArgForConnect(
const QString &arg)
584 void GameClientRunner::setArgForConnectPassword(
const QString &arg)
586 d->argConnectPassword = arg;
589 void GameClientRunner::setArgForDehLoading(
const QString &arg)
591 d->argDehLoading = arg;
594 void GameClientRunner::setArgForInGamePassword(
const QString &arg)
596 d->argInGamePassword = arg;
599 void GameClientRunner::setArgForIwadLoading(
const QString &arg)
601 d->argIwadLoading = arg;
604 void GameClientRunner::setArgForOptionalWadLoading(
const QString &arg)
606 d->argOptionalWadLoading = arg;
609 void GameClientRunner::setArgForPort(
const QString &arg)
614 void GameClientRunner::setArgForPwadLoading(
const QString &arg)
616 d->argPwadLoading = arg;
619 void GameClientRunner::setArgForDemoRecord(
const QString &arg)
621 d->argDemoRecord = arg;
624 void GameClientRunner::setExecutable(
const QString &path)
629 void GameClientRunner::setWorkingDir(
const QString &path)
644 void GameClientRunner::setupPathFinder()
646 d->pathFinder = d->server->wadPathFinder();