23 #include "generalgamesetuppanel.h"
24 #include "ui_generalgamesetuppanel.h"
26 #include "configuration/doomseekerconfig.h"
27 #include "gui/createserver/hostmodetraits.h"
28 #include "gui/createserver/maplistpanel.h"
29 #include "gui/createserverdialog.h"
31 #include "plugins/engineplugin.h"
32 #include "plugins/pluginloader.h"
33 #include "serverapi/gamecreateparams.h"
34 #include "serverapi/gameexefactory.h"
35 #include "serverapi/gamefile.h"
36 #include "templatedpathresolver.h"
38 #include <QFileDialog>
40 #include <QMessageBox>
43 DClass<GeneralGameSetupPanel> :
public Ui::GeneralGameSetupPanel
48 bool iwadSetExplicitly;
49 bool pwadsSetExplicitly;
55 int hostModeSpacerRow;
60 bool isValidExecutable(
const QString &executablePath)
62 QFileInfo fileInfo(executablePath);
63 return !executablePath.isEmpty() && fileInfo.isFile();
74 d->iwadSetExplicitly =
false;
75 d->pwadsSetExplicitly =
false;
76 d->parentDialog =
nullptr;
78 d->demoPlayerExecutableInput->setAllowedExecutables(GameFile::Offline);
79 d->hostExecutableInput->setAllowedExecutables(GameFile::Server);
80 d->offlineExecutableInput->setAllowedExecutables(GameFile::Offline);
81 d->remoteExecutableInput->setAllowedExecutables(GameFile::Client);
83 d->demoPicker->setTitleVisible(
false);
85 d->formLayout->getWidgetPosition(d->demoPicker, &d->demoRow,
nullptr);
86 d->formLayout->getWidgetPosition(d->leServerName, &d->serverNameRow,
nullptr);
87 d->formLayout->getWidgetPosition(d->portArea, &d->portRow,
nullptr);
88 d->formLayout->getWidgetPosition(d->hostModeSpacer, &d->hostModeSpacerRow,
nullptr);
89 d->formLayout->getWidgetPosition(d->cboGamemode, &d->gamemodeRow,
nullptr);
90 d->formLayout->getWidgetPosition(d->cboDifficulty, &d->difficultyRow,
nullptr);
91 d->formLayout->getWidgetPosition(d->mapPanel, &d->mapRow,
nullptr);
93 this->connect(d->cboEngine, SIGNAL(currentPluginChanged(
EnginePlugin*)),
97 GeneralGameSetupPanel::~GeneralGameSetupPanel()
101 QStringList GeneralGameSetupPanel::getAllWadPaths()
const
104 paths << d->iwadPicker->currentIwad();
118 QStringList filePaths;
119 QList<bool> optionalFiles;
122 filePaths << file.path;
123 optionalFiles << file.optional;
126 params.setPwadsOptional(optionalFiles);
127 params.setBroadcastToLan(d->cbBroadcastToLAN->isChecked());
128 params.setBroadcastToMaster(d->cbBroadcastToMaster->isChecked());
129 params.setMap(d->leMap->text());
130 params.setName(d->leServerName->text());
131 params.setPort(d->spinPort->isEnabled() ? d->spinPort->value() : 0);
132 params.setGameMode(currentGameMode());
133 params.setSkill(d->cboDifficulty->itemData(d->cboDifficulty->currentIndex()).toInt());
134 params.setUpnp(d->cbUpnp->isChecked());
135 params.setUpnpPort(d->spinUpnpPort->value());
138 void GeneralGameSetupPanel::loadConfig(
Ini &config,
bool loadingPrevious)
144 QString configEngineName = general[
"engine"];
145 bool engineChanged =
false;
146 if (d->hostMode.canChangeGame())
148 if (!setEngine(configEngineName))
150 engineChanged = (prevEngine != d->currentEngine);
154 bool changeExecutable = engineChanged || !d->cbLockExecutable->isChecked();
155 if (!d->hostMode.canChangeGame())
159 auto *plugin = gPlugins->plugin(gPlugins->pluginIndexFromName(configEngineName));
160 if (plugin ==
nullptr || d->currentEngine != plugin->info())
161 changeExecutable =
false;
164 if (changeExecutable)
166 QString demoPlayerExecutablePath = *general[
"demoPlayerExecutable"];
167 if (d->isValidExecutable(demoPlayerExecutablePath))
168 d->demoPlayerExecutableInput->setPath(demoPlayerExecutablePath);
170 QString hostExecutablePath = *general[
"hostExecutable"];
171 if (d->isValidExecutable(hostExecutablePath))
172 d->hostExecutableInput->setPath(hostExecutablePath);
174 QString offlineExecutablePath = *general[
"offlineExecutable"];
175 if (d->isValidExecutable(offlineExecutablePath))
176 d->offlineExecutableInput->setPath(offlineExecutablePath);
178 QString remoteExecutablePath = *general[
"remoteExecutable"];
179 if (d->isValidExecutable(remoteExecutablePath))
180 d->remoteExecutableInput->setPath(remoteExecutablePath);
184 d->leServerName->setText(general[
"name"]);
185 d->spinPort->setValue(general[
"port"]);
187 int gameModeIndex = d->cboGamemode->findData(static_cast<gamemode_id>(general[
"gamemode"]));
188 if (gameModeIndex >= 0)
189 d->cboGamemode->setCurrentIndex(gameModeIndex);
191 int difficultyIndex = d->cboDifficulty->findData(static_cast<int>(general[
"difficulty"]));
192 d->cboDifficulty->setCurrentIndex(qMax(0, difficultyIndex));
194 d->leMap->setText(general[
"map"]);
196 if (!(loadingPrevious && d->iwadSetExplicitly))
197 d->iwadPicker->addIwad(general[
"iwad"]);
199 d->logDirectoryPicker->setLoggingEnabled(general[
"logEnabled"]);
200 d->logDirectoryPicker->setPathAndUpdate(general[
"logDir"]);
202 if (!(loadingPrevious && d->pwadsSetExplicitly))
204 QList<PickedGameFile> files;
205 QStringList filesPaths = general[
"pwads"].valueString().split(
";");
206 QList<QString> optionalFilesTokens = general[
"pwadsOptional"].valueString().split(
";");
207 for (
int i = 0; i < filesPaths.length(); ++i)
210 file.path = filesPaths[i];
211 if (i < optionalFilesTokens.length())
213 file.optional = (optionalFilesTokens[i] !=
"0");
217 d->wadsPicker->setFiles(files);
220 d->cbBroadcastToLAN->setChecked(general[
"broadcastToLAN"]);
221 d->cbBroadcastToMaster->setChecked(general[
"broadcastToMaster"]);
222 d->cbUpnp->setChecked(general[
"upnp"]);
223 d->spinUpnpPort->setValue(general[
"upnpPort"]);
226 QTimer::singleShot(0,
this, SLOT(updateMapWarningVisibility()));
229 void GeneralGameSetupPanel::saveConfig(
Ini &config)
232 general[
"engine"] = d->cboEngine->currentText();
233 general[
"demoPlayerExecutable"] = d->demoPlayerExecutableInput->path();
234 general[
"hostExecutable"] = d->hostExecutableInput->path();
235 general[
"offlineExecutable"] = d->offlineExecutableInput->path();
236 general[
"remoteExecutable"] = d->remoteExecutableInput->path();
237 general[
"name"] = d->leServerName->text();
238 general[
"port"] = d->spinPort->value();
239 general[
"logDir"] = d->logDirectoryPicker->currentPath();
240 general[
"logEnabled"] = d->logDirectoryPicker->isLoggingEnabled();
241 general[
"gamemode"] = d->cboGamemode->itemData(d->cboGamemode->currentIndex()).toInt();
242 general[
"map"] = d->leMap->text();
243 general[
"difficulty"] = d->cboDifficulty->itemData(d->cboDifficulty->currentIndex()).toInt();
244 general[
"iwad"] = d->iwadPicker->currentIwad();
246 QList<PickedGameFile> files = d->wadsPicker->files();
247 QStringList filePaths;
248 QStringList optionalFiles;
249 for (
const auto &file : files)
251 filePaths << file.path;
252 optionalFiles << (file.optional ?
"1" :
"0");
254 general[
"pwads"] = filePaths.join(
";");
255 general[
"pwadsOptional"] = optionalFiles.join(
";");
257 general[
"broadcastToLAN"] = d->cbBroadcastToLAN->isChecked();
258 general[
"broadcastToMaster"] = d->cbBroadcastToMaster->isChecked();
259 general[
"upnp"] = d->cbUpnp->isChecked();
260 general[
"upnpPort"] = d->spinUpnpPort->value();
263 void GeneralGameSetupPanel::reloadAppConfig()
265 d->demoPlayerExecutableInput->reloadExecutables();
266 d->hostExecutableInput->reloadExecutables();
267 d->offlineExecutableInput->reloadExecutables();
268 d->remoteExecutableInput->reloadExecutables();
269 d->iwadPicker->loadIwads();
272 void GeneralGameSetupPanel::setupDifficulty(
const EnginePlugin *engine)
274 QVariant oldDifficulty = d->cboDifficulty->itemData(d->cboDifficulty->currentIndex());
275 d->cboDifficulty->clear();
277 QList<GameCVar> levels = engine->data()->
difficulty->get(QVariant());
278 d->labelDifficulty->setVisible(!levels.isEmpty());
279 d->cboDifficulty->setVisible(!levels.isEmpty());
281 for (
const GameCVar &level : levels)
283 d->cboDifficulty->addItem(level.name(), level.value());
285 int memorizedIndex = d->cboDifficulty->findData(oldDifficulty);
286 if (memorizedIndex >= 0)
287 d->cboDifficulty->setCurrentIndex(memorizedIndex);
290 void GeneralGameSetupPanel::setupForEngine(
EnginePlugin *engine)
292 d->currentEngine = engine;
294 d->cboEngine->setPluginByName(engine->data()->name);
295 d->labelIwad->setVisible(engine->data()->hasIwad);
296 d->iwadPicker->setVisible(engine->data()->hasIwad);
297 d->labelLogging->setVisible(engine->data()->allowsLogging);
298 d->logDirectoryPicker->setVisible(engine->data()->allowsLogging);
299 d->upnpArea->setVisible(engine->data()->allowsUpnp);
300 d->spinUpnpPort->setVisible(engine->data()->allowsUpnpPort);
302 d->demoPlayerExecutableInput->setPlugin(engine);
303 d->hostExecutableInput->setPlugin(engine);
304 d->offlineExecutableInput->setPlugin(engine);
305 d->remoteExecutableInput->setPlugin(engine);
307 d->spinPort->setValue(d->currentEngine->data()->defaultServerPort);
309 d->cboGamemode->clear();
312 QList<GameMode> gameModes = d->currentEngine->gameModes();
313 for (
int i = 0; i < gameModes.count(); ++i)
314 d->cboGamemode->addItem(gameModes[i].name(), gameModes[i].index());
315 setupDifficulty(engine);
318 void GeneralGameSetupPanel::setupForHostMode(GameCreateParams::HostMode hostMode)
320 d->hostMode = hostMode;
322 d->cboEngine->setDisabled(!d->hostMode.canChangeGame());
324 d->demoPlayerExecutableInput->hide();
325 d->hostExecutableInput->hide();
326 d->offlineExecutableInput->hide();
327 d->remoteExecutableInput->hide();
330 case GameCreateParams::Demo: d->demoPlayerExecutableInput->show();
break;
332 case GameCreateParams::Host: d->hostExecutableInput->show();
break;
333 case GameCreateParams::Offline: d->offlineExecutableInput->show();
break;
334 case GameCreateParams::Remote: d->remoteExecutableInput->show();
break;
337 const bool canSetupServer = d->hostMode.isCreatingServer() && d->hostMode.canChangeAnyGameRules();
338 d->labelServerName->setVisible(canSetupServer);
339 d->leServerName->setVisible(canSetupServer);
340 d->labelPort->setVisible(canSetupServer);
341 d->portArea->setVisible(canSetupServer);
342 d->hostModeSpacer->setVisible(canSetupServer);
343 d->broadcastOptionsArea->setVisible(canSetupServer);
349 d->formLayout->insertRow(d->serverNameRow, d->labelServerName, d->leServerName);
350 d->formLayout->insertRow(d->portRow, d->labelPort, d->portArea);
351 d->formLayout->insertRow(d->hostModeSpacerRow, d->hostModeSpacer,
352 static_cast<QWidget *>(
nullptr));
356 d->formLayout->removeWidget(d->labelServerName);
357 d->formLayout->removeWidget(d->leServerName);
358 d->formLayout->removeWidget(d->labelPort);
359 d->formLayout->removeWidget(d->portArea);
360 d->formLayout->removeWidget(d->hostModeSpacer);
363 d->labelDemo->setVisible(d->hostMode == GameCreateParams::Demo);
364 d->demoPicker->setVisible(d->hostMode == GameCreateParams::Demo);
366 if (d->hostMode == GameCreateParams::Demo)
368 d->formLayout->insertRow(d->demoRow, d->labelDemo, d->demoPicker);
372 d->formLayout->removeWidget(d->labelDemo);
373 d->formLayout->removeWidget(d->demoPicker);
376 d->labelGamemode->setVisible(d->hostMode.canChangeAnyGameRules());
377 d->cboGamemode->setVisible(d->hostMode.canChangeAnyGameRules());
378 d->labelDifficulty->setVisible(d->hostMode.canChangeAnyGameRules());;
379 d->cboDifficulty->setVisible(d->hostMode.canChangeAnyGameRules());
380 d->labelMap->setVisible(d->hostMode.canChangeAnyGameRules());
381 d->mapPanel->setVisible(d->hostMode.canChangeAnyGameRules());
383 if (d->hostMode.canChangeAnyGameRules())
385 d->formLayout->insertRow(d->gamemodeRow, d->labelGamemode, d->cboGamemode);
386 d->formLayout->insertRow(d->difficultyRow, d->labelDifficulty, d->cboDifficulty);
387 d->formLayout->insertRow(d->mapRow, d->labelMap, d->mapPanel);
391 d->formLayout->removeWidget(d->labelGamemode);
392 d->formLayout->removeWidget(d->cboGamemode);
393 d->formLayout->removeWidget(d->labelDifficulty);
394 d->formLayout->removeWidget(d->cboDifficulty);
395 d->formLayout->removeWidget(d->labelMap);
396 d->formLayout->removeWidget(d->mapPanel);
402 d->parentDialog = dialog;
405 void GeneralGameSetupPanel::setDemoPath(
const QString &demoPath)
407 d->demoPicker->setPath(demoPath);
410 void GeneralGameSetupPanel::setIwadByName(
const QString &iwad)
412 d->iwadSetExplicitly =
true;
413 d->iwadPicker->setIwadByName(iwad);
416 void GeneralGameSetupPanel::setIwadByPath(
const QString &iwadPath)
418 d->iwadSetExplicitly =
true;
419 d->iwadPicker->setIwadByPath(iwadPath);
422 void GeneralGameSetupPanel::setPwads(
const QList<PickedGameFile> &pwads)
424 d->pwadsSetExplicitly =
true;
425 d->wadsPicker->setFiles(pwads);
428 void GeneralGameSetupPanel::showEvent(QShowEvent *event)
431 updateMapWarningVisibility();
434 QString GeneralGameSetupPanel::mapName()
const
436 return d->leMap->text();
439 QString GeneralGameSetupPanel::pathToExe()
441 switch (d->hostMode.mode)
443 case GameCreateParams::Demo:
return d->demoPlayerExecutableInput->path();
445 case GameCreateParams::Host:
return d->hostExecutableInput->path();
446 case GameCreateParams::Offline:
return d->offlineExecutableInput->path();
447 case GameCreateParams::Remote:
return d->remoteExecutableInput->path();
451 void GeneralGameSetupPanel::onGameModeChanged(
int index)
454 emit gameModeChanged(currentGameMode());
457 GameMode GeneralGameSetupPanel::currentGameMode()
const
459 QList<GameMode> gameModes = d->currentEngine->gameModes();
460 for (
const GameMode &mode : gameModes)
462 if (mode.index() == d->cboGamemode->itemData(d->cboGamemode->currentIndex()).toInt())
465 return GameMode::mkUnknown();
468 EnginePlugin *GeneralGameSetupPanel::currentPlugin()
const
470 return d->cboEngine->currentPlugin();
473 bool GeneralGameSetupPanel::setEngine(
const QString &engineName)
475 if (!d->cboEngine->setPluginByName(engineName))
477 QMessageBox::critical(
this, tr(
"Doomseeker - load server config"),
478 tr(
"Plugin for engine \"%1\" is not present!").arg(engineName));
484 void GeneralGameSetupPanel::updateMapWarningVisibility()
486 assert(d->parentDialog !=
nullptr);
487 MapListPanel *mapList = d->parentDialog->mapListPanel();
488 d->lblMapWarning->setVisible(mapList->hasMaps() && !mapList->isMapOnList(mapName()));