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"
40 #include <QScopedPointer>
41 #include <QStringList>
43 DClass<ServerConnectParams>
46 QString connectPassword;
48 QString inGamePassword;
68 ServerConnectParams::~ServerConnectParams()
74 return d->connectPassword;
84 return d->inGamePassword;
87 void ServerConnectParams::setConnectPassword(
const QString &val)
89 d->connectPassword = val;
92 void ServerConnectParams::setDemoName(
const QString &val)
97 void ServerConnectParams::setInGamePassword(
const QString &val)
99 d->inGamePassword = val;
102 #define BAIL_ON_ERROR(method) \
105 if (isFatalError()) \
112 DClass<GameClientRunner>
115 QString argBexLoading;
117 QString argConnectPassword;
118 QString argDehLoading;
119 QString argInGamePassword;
120 QString argIwadLoading;
121 QString argOptionalWadLoading;
123 QString argPwadLoading;
124 QString argDemoRecord;
127 mutable QString cachedIwadPath;
131 QList<PWad> missingPwads;
132 QList<PWad> incompatiblePwads;
149 POLYMORPHIC_DEFINE(
void, GameClientRunner, addExtra, (), ())
150 POLYMORPHIC_DEFINE(
void, GameClientRunner, addGamePaths, (), ())
151 POLYMORPHIC_DEFINE(
void, GameClientRunner, addInGamePassword, (), ())
152 POLYMORPHIC_DEFINE(
void, GameClientRunner, addIwad, (), ())
153 POLYMORPHIC_DEFINE(
void, GameClientRunner, addModFiles, (const QStringList &files), (files))
154 POLYMORPHIC_DEFINE(
void, GameClientRunner, addPassword, (), ())
155 POLYMORPHIC_DEFINE(
void, GameClientRunner, createCommandLineArguments, (), ())
157 GameClientRunner::GameClientRunner(ServerPtr server)
159 set_addConnectCommand(&GameClientRunner::addConnectCommand_default);
160 set_addGamePaths(&GameClientRunner::addGamePaths_default);
161 set_addExtra(&GameClientRunner::addExtra_default);
162 set_addInGamePassword(&GameClientRunner::addInGamePassword_default);
163 set_addIwad(&GameClientRunner::addIwad_default);
164 set_addModFiles(&GameClientRunner::addModFiles_default);
165 set_addPassword(&GameClientRunner::addPassword_default);
166 set_createCommandLineArguments(&GameClientRunner::createCommandLineArguments_default);
167 d->argBexLoading =
"-deh";
168 d->argConnect =
"-connect";
169 d->argDehLoading =
"-deh";
170 d->argIwadLoading =
"-iwad";
171 d->argOptionalWadLoading =
"-file";
172 d->argPort =
"-port";
173 d->argPwadLoading =
"-file";
174 d->argDemoRecord =
"-record";
179 GameClientRunner::~GameClientRunner()
183 void GameClientRunner::addConnectCommand_default()
185 QString address = QString(
"%1:%2").arg(d->server->address().toString()).arg(d->server->port());
191 IniSection config = gConfig.iniSectionForPlugin(d->server->plugin());
192 QString customParameters = config[
"CustomParameters"];
194 args() << tokenizer.tokenize(customParameters);
202 void GameClientRunner::addGamePaths_default()
204 GamePaths paths = gamePaths();
205 if (!paths.isValid())
211 QDir applicationDir = paths.workingDir;
212 if (paths.workingDir.isEmpty())
214 d->joinError.setType(JoinError::ConfigurationError);
215 d->joinError.setError(tr(
"Path to working directory for game \"%1\" is empty.\n\n"
216 "Make sure the configuration for the client executable is set properly.")
220 else if (!applicationDir.exists())
222 d->joinError.setType(JoinError::ConfigurationError);
223 d->joinError.setError(tr(
"%1\n\nThis directory cannot be used as working "
224 "directory for game: %2\n\nExecutable: %3")
225 .arg(paths.workingDir, pluginName(), paths.clientExe));
229 setExecutable(paths.clientExe);
230 setWorkingDir(applicationDir.path());
233 void GameClientRunner::addInGamePassword_default()
241 gLog << tr(
"BUG: Plugin doesn't specify argument for in-game "
242 "password, but the server requires such password.");
246 void GameClientRunner::addExtra_default()
250 void GameClientRunner::addIwad_default()
260 if (!d->incompatiblePwads.isEmpty())
262 d->joinError.setIncompatibleWads(d->incompatiblePwads);
263 d->joinError.setType(JoinError::MissingWads);
265 if (!isIwadFound() || !d->missingPwads.isEmpty())
269 d->joinError.setMissingIwad(d->server->iwad());
270 d->joinError.setType(JoinError::MissingWads);
272 d->joinError.setMissingWads(d->missingPwads);
273 for (
const PWad &wad : d->missingPwads)
278 d->joinError.setType(JoinError::MissingWads);
285 void GameClientRunner::addPassword_default()
293 gLog << tr(
"BUG: Plugin doesn't specify argument for connect "
294 "password, but the server is passworded.");
301 checkWadsDlg->addWads(d->server->wads());
302 const CheckResult checkResults = checkWadsDlg->checkWads();
303 for (
const PWad &wad : checkResults.missingWads)
307 for (
const PWad &wad : checkResults.incompatibleWads)
312 for (
const PWad &wad : checkResults.foundWads)
319 void GameClientRunner::addModFiles_default(
const QStringList &files)
321 for (
const QString &file : files)
323 args() << fileLoadingPrefix(file) << file;
329 QMap<QString, QStringList> groups;
330 for (
const QString &file : files)
332 QString prefix = fileLoadingPrefix(file);
333 groups[prefix] << file;
335 for (
const QString &prefix : groups.keys())
338 for (
const QString &file : groups[prefix])
345 QString GameClientRunner::fileLoadingPrefix(
const QString &file)
const
347 if (file.toLower().endsWith(
".deh"))
351 else if (file.toLower().endsWith(
".bex"))
353 return argForBexLoading();
363 const QString &GameClientRunner::argForBexLoading()
const
365 return d->argBexLoading;
370 return d->argConnect;
375 return d->argConnectPassword;
380 return d->argDehLoading;
385 return d->argInGamePassword;
390 return d->argIwadLoading;
395 return d->argOptionalWadLoading;
405 return d->argPwadLoading;
410 return d->argDemoRecord;
413 bool GameClientRunner::canDownloadWadsInGame()
const
415 return d->server->plugin()->data()->inGameFileDownloads;
420 return d->connectParams.connectPassword();
423 void GameClientRunner::createCommandLineArguments_default()
427 if (d->server->isLocked())
431 if (d->server->isLockedInGame())
448 d->cli->args.clear();
449 d->connectParams = params;
453 if (d->joinError.isError())
464 return d->connectParams.demoName();
467 QString GameClientRunner::findIwad()
const
469 return findWad(d->server->iwad().toLower());
477 GameClientRunner::GamePaths GameClientRunner::gamePaths()
482 QScopedPointer<ExeFile> exeFile(d->server->clientExe());
483 result.clientExe = exeFile->pathToExe(msg);
484 if (result.clientExe.isEmpty())
491 d->joinError.setError(msg.
contents());
495 d->joinError.setError(tr(
"Game can be installed by Doomseeker"));
500 d->joinError.setType(JoinError::ConfigurationError);
501 QString error = tr(
"Game %1 cannot be found.").arg(pluginName());
506 d->joinError.setError(error);
510 result.workingDir = exeFile->workingDirectory(msg);
516 return d->connectParams.inGamePassword();
519 bool GameClientRunner::isFatalError()
const
521 if (d->joinError.isError())
523 if (d->joinError.isMissingWadsError() && canDownloadWadsInGame())
532 bool GameClientRunner::isIwadFound()
const
534 return !d->cachedIwadPath.isEmpty();
537 const QString &GameClientRunner::iwadPath()
const
541 d->cachedIwadPath = findIwad();
543 return d->cachedIwadPath;
548 d->missingPwads << pwadName;
553 d->incompatiblePwads << pwadName;
558 return d->pathFinder;
561 const QString &GameClientRunner::pluginName()
const
563 return d->server->plugin()->data()->name;
568 return d->connectParams;
571 void GameClientRunner::setArgForBexLoading(
const QString &arg)
573 d->argBexLoading = arg;
576 void GameClientRunner::setArgForConnect(
const QString &arg)
581 void GameClientRunner::setArgForConnectPassword(
const QString &arg)
583 d->argConnectPassword = arg;
586 void GameClientRunner::setArgForDehLoading(
const QString &arg)
588 d->argDehLoading = arg;
591 void GameClientRunner::setArgForInGamePassword(
const QString &arg)
593 d->argInGamePassword = arg;
596 void GameClientRunner::setArgForIwadLoading(
const QString &arg)
598 d->argIwadLoading = arg;
601 void GameClientRunner::setArgForOptionalWadLoading(
const QString &arg)
603 d->argOptionalWadLoading = arg;
606 void GameClientRunner::setArgForPort(
const QString &arg)
611 void GameClientRunner::setArgForPwadLoading(
const QString &arg)
613 d->argPwadLoading = arg;
616 void GameClientRunner::setArgForDemoRecord(
const QString &arg)
618 d->argDemoRecord = arg;
621 void GameClientRunner::setExecutable(
const QString &path)
623 d->cli->executable = QFileInfo(path);
626 void GameClientRunner::setWorkingDir(
const QString &path)
628 d->cli->applicationDir.setPath(path);
641 void GameClientRunner::setupPathFinder()
643 d->pathFinder = d->server->wadPathFinder();