generalgamesetuppanel.cpp
1 //------------------------------------------------------------------------------
2 // generalgamesetuppanel.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) 2014 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "generalgamesetuppanel.h"
24 #include "ui_generalgamesetuppanel.h"
25 
26 #include "configuration/doomseekerconfig.h"
27 #include "ini/ini.h"
28 #include "plugins/engineplugin.h"
29 #include "serverapi/exefile.h"
30 #include "serverapi/gamecreateparams.h"
31 #include "serverapi/gameexeretriever.h"
32 #include "serverapi/message.h"
34 #include "serverapi/server.h"
35 #include <QFileDialog>
36 #include <QFileInfo>
37 #include <QHostAddress>
38 #include <QMessageBox>
39 
40 DClass<GeneralGameSetupPanel> : public Ui::GeneralGameSetupPanel
41 {
42 public:
43  EnginePlugin *currentEngine;
44  bool iwadSetExplicitly;
45  bool suppressMissingExeErrors;
46  bool remoteGameSetup;
47 };
48 
49 DPointered(GeneralGameSetupPanel)
50 
51 
53 : QWidget(parent)
54 {
55  d->setupUi(this);
56  d->iwadSetExplicitly = false;
57  d->remoteGameSetup = false;
58  d->suppressMissingExeErrors = false;
59 
60  this->connect(d->cboEngine, SIGNAL(currentPluginChanged(EnginePlugin*)),
61  SIGNAL(pluginChanged(EnginePlugin*)));
62 }
63 
64 GeneralGameSetupPanel::~GeneralGameSetupPanel()
65 {
66 }
67 
68 void GeneralGameSetupPanel::fillInParams(GameCreateParams &params, bool offline)
69 {
70  params.setExecutablePath(pathToExe(offline));
71  params.setHostMode(offline ? GameCreateParams::Offline : GameCreateParams::Host);
72  params.setIwadPath(d->iwadPicker->currentIwad());
73  params.setPwadsPaths(d->wadsPicker->filePaths());
74  params.setPwadsOptional(d->wadsPicker->fileOptional());
75  params.setBroadcastToLan(d->cbBroadcastToLAN->isChecked());
76  params.setBroadcastToMaster(d->cbBroadcastToMaster->isChecked());
77  params.setMap(d->leMap->text());
78  params.setName(d->leServername->text());
79  params.setPort(d->spinPort->isEnabled() ? d->spinPort->value() : 0);
80  params.setGameMode(currentGameMode());
81 }
82 
83 void GeneralGameSetupPanel::loadConfig(Ini &config, bool loadingPrevious)
84 {
85  IniSection general = config.section("General");
86 
87  // General
88  if (!d->remoteGameSetup)
89  {
90  QString engineName = general["engine"];
91  const EnginePlugin* prevEngine = d->currentEngine;
92  if(!setEngine(engineName))
93  return;
94 
95  bool bChangeExecutable = (prevEngine != d->currentEngine || !d->cbLockExecutable->isChecked());
96 
97  // First let's check if we can use executable stored in the server's config.
98  // We will save the path to this executable in a local variable.
99  QString executablePath = "";
100  if (bChangeExecutable)
101  {
102  executablePath = *general["executable"];
103  QFileInfo fileInfo(executablePath);
104  if (!fileInfo.exists())
105  {
106  // Executable cannot be found, display error message and reset
107  // the local variable.
108  QMessageBox::warning(this, tr("Doomseeker - load server config"),
109  tr("Game executable saved in config cannot be found.\n"
110  "Default executable will be used."));
111  Message message;
112  executablePath = pathToServerExe(message);
113  }
114  }
115 
116  // If we successfuly retrieved path from the config we shall
117  // set this path in the line edit control.
118  if (!executablePath.isEmpty())
119  {
120  d->leExecutable->setText(executablePath);
121  }
122  }
123 
124  d->leServername->setText(general["name"]);
125  d->spinPort->setValue(general["port"]);
126  d->cboGamemode->setCurrentIndex(general["gamemode"]);
127  d->leMap->setText(general["map"]);
128 
129  if (!(loadingPrevious && d->iwadSetExplicitly))
130  {
131  d->iwadPicker->addIwad(general["iwad"]);
132  }
133 
134  QList<bool> optionalWads;
135  foreach(QString value, general["pwadsOptional"].valueString().split(";"))
136  {
137  optionalWads << (value != "0");
138  }
139  d->wadsPicker->setFilePaths(general["pwads"].valueString().split(";"), optionalWads);
140 
141  d->cbBroadcastToLAN->setChecked(general["broadcastToLAN"]);
142  d->cbBroadcastToMaster->setChecked(general["broadcastToMaster"]);
143 }
144 
145 void GeneralGameSetupPanel::saveConfig(Ini &config)
146 {
147  IniSection general = config.section("General");
148  general["engine"] = d->cboEngine->currentText();
149  general["executable"] = d->leExecutable->text();
150  general["name"] = d->leServername->text();
151  general["port"] = d->spinPort->value();
152  general["gamemode"] = d->cboGamemode->currentIndex();
153  general["map"] = d->leMap->text();
154  general["iwad"] = d->iwadPicker->currentIwad();
155 
156  general["pwads"] = d->wadsPicker->filePaths().join(";");
157  QList<bool> optionalWads = d->wadsPicker->fileOptional();
158  QStringList optionalList;
159  foreach(bool optional, optionalWads)
160  optionalList << (optional ? "1" : "0");
161  general["pwadsOptional"] = optionalList.join(";");
162 
163  general["broadcastToLAN"] = d->cbBroadcastToLAN->isChecked();
164  general["broadcastToMaster"] = d->cbBroadcastToMaster->isChecked();
165 }
166 
167 void GeneralGameSetupPanel::setupForEngine(EnginePlugin *engine)
168 {
169  d->currentEngine = engine;
170  // Executable path
171  Message message;
172 
173  if (d->remoteGameSetup)
174  {
175  // When we setup a remote game, we want to use a client
176  // executable to connect to it.
177  ServerPtr server = engine->server(QHostAddress("127.0.0.1"), 1);
178  d->leExecutable->setText(pathToClientExe(server.data(), message));
179  }
180  else
181  {
182  d->leExecutable->setText(pathToServerExe(message));
183  }
184 
185  if (message.isError() && !d->suppressMissingExeErrors)
186  {
187  QString caption = tr("Doomseeker - error obtaining server binary");
188  QString error = tr("Server binary for engine \"%1\" cannot be obtained.\n"
189  "Following error has occured:\n%2")
190  .arg(d->currentEngine->data()->name, message.contents());
191 
192  QMessageBox::warning(this, caption, error);
193  }
194 
195  d->spinPort->setValue(d->currentEngine->data()->defaultServerPort);
196 
197  d->cboGamemode->clear();
198  const QList<GameMode> &gameModes = d->currentEngine->data()->gameModes;
199  if (!gameModes.isEmpty())
200  {
201  for (int i = 0; i < gameModes.count(); ++i)
202  {
203  d->cboGamemode->addItem(gameModes[i].name(), i);
204  }
205  }
206 }
207 
208 void GeneralGameSetupPanel::setupForRemoteGame()
209 {
210  d->suppressMissingExeErrors = true;
211  d->remoteGameSetup = true;
212  d->cbAllowTheGameToChoosePort->hide();
213  QWidget *disableControls[] =
214  {
215  d->cboEngine, d->leExecutable, d->btnBrowseExecutable, d->btnDefaultExecutable,
216  d->cbLockExecutable, d->leServername, d->spinPort, d->cbBroadcastToLAN,
217  d->cbBroadcastToMaster,
218 
219  NULL
220  };
221  for(int i = 0;disableControls[i] != NULL;++i)
222  disableControls[i]->setDisabled(true);
223 }
224 
225 void GeneralGameSetupPanel::setIwadByName(const QString &iwad)
226 {
227  d->iwadSetExplicitly = true;
228  d->iwadPicker->setIwadByName(iwad);
229 }
230 
231 QString GeneralGameSetupPanel::pathToExe(bool offline)
232 {
233  // Since some operating systems have different offline and server binaries
234  // We will see if they are playing offline and switch to the client
235  // binary if the specified executable is the same as what is provided
236  // as the server.
237  Message message;
238  QString offlineExePath = pathToOfflineExe(message);
239  QString serverExePath = pathToServerExe(message);
240  bool bIsLineEditPotiningToServerBinary = (d->leExecutable->text() == serverExePath);
241  bool bShouldUseClientBinary = (offline || d->remoteGameSetup) && message.isIgnore() && bIsLineEditPotiningToServerBinary;
242 
243  if (bShouldUseClientBinary)
244  {
245  return offlineExePath;
246  }
247  else
248  {
249  return d->leExecutable->text();
250  }
251 }
252 
253 QString GeneralGameSetupPanel::pathToClientExe(Server* server, Message& message)
254 {
255  QScopedPointer<ExeFile> f(server->clientExe());
256  return f->pathToExe(message);
257 }
258 
259 QString GeneralGameSetupPanel::pathToOfflineExe(Message& message)
260 {
261  return GameExeRetriever(*d->currentEngine->gameExe()).pathToOfflineExe(message);
262 }
263 
264 QString GeneralGameSetupPanel::pathToServerExe(Message& message)
265 {
266  return GameExeRetriever(*d->currentEngine->gameExe()).pathToServerExe(message);
267 }
268 
269 void GeneralGameSetupPanel::browseExecutable()
270 {
271  QString dialogDir = gConfig.doomseeker.previousCreateServerExecDir;
272  QString strFile = QFileDialog::getOpenFileName(this, tr("Doomseeker - Add file"), dialogDir);
273 
274  if (!strFile.isEmpty())
275  {
276  QFileInfo fi(strFile);
277  gConfig.doomseeker.previousCreateServerExecDir = fi.absolutePath();
278 
279  d->leExecutable->setText(fi.absoluteFilePath());
280  }
281 }
282 
283 void GeneralGameSetupPanel::setExecutableToDefault()
284 {
285  Message message;
286  d->leExecutable->setText(pathToServerExe(message));
287 
288  if (!message.isIgnore())
289  {
290  QMessageBox::critical(this, tr("Obtaining default server binary path."),
291  message.contents(),QMessageBox::Ok, QMessageBox::Ok);
292  }
293 }
294 
295 void GeneralGameSetupPanel::onGameModeChanged(int index)
296 {
297  if (index >= 0)
298  {
299  const QList<GameMode> &gameModes = d->currentEngine->data()->gameModes;
300  emit gameModeChanged(gameModes[index]);
301  }
302 }
303 
304 GameMode GeneralGameSetupPanel::currentGameMode() const
305 {
306  const QList<GameMode> &gameModes = d->currentEngine->data()->gameModes;
307  foreach (const GameMode& mode, gameModes)
308  {
309  if (mode.name().compare(d->cboGamemode->currentText()) == 0)
310  {
311  return mode;
312  }
313  }
314  return GameMode();
315 }
316 
317 EnginePlugin *GeneralGameSetupPanel::currentPlugin() const
318 {
319  return d->cboEngine->currentPlugin();
320 }
321 
322 bool GeneralGameSetupPanel::setEngine(const QString &engineName)
323 {
324  if (!d->cboEngine->setPluginByName(engineName))
325  {
326  QMessageBox::critical(this, tr("Doomseeker - load server config"),
327  tr("Plugin for engine \"%1\" is not present!").arg(engineName));
328  return false;
329  }
330  return true;
331 }
const QString & name() const
User-friendly name to display for game mode.
Game parametrization data used when creating new games.
Message object used to pass messages throughout the Doomseeker's system.
Definition: message.h:62
A convenience wrapper class for GameExeFactory.
bool isError() const
True if type() is equal to or greater than CUSTOM_ERROR.
Definition: message.cpp:104
A representation of a server for a given game.
Definition: server.h:93
virtual ExeFile * clientExe()
Client executable retriever.
Definition: server.cpp:252
bool isIgnore() const
True for 'Null' messages.
Definition: message.cpp:109
virtual ServerPtr server(const QHostAddress &address, unsigned short port) const
Creates an instance of server object from this plugin.
Game mode representation.
Configuration handler.
Definition: ini.h:69
INI section representation.
Definition: inisection.h:40
IniSection section(const QString &name)
Access configuration file section.
Definition: ini.cpp:91
QString contents() const
Customized displayable contents of this Message.
Definition: message.cpp:87