gamerulespanel.cpp
1 //------------------------------------------------------------------------------
2 // gamerulespanel.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library 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 GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; 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 "gamerulespanel.h"
24 #include "ui_gamerulespanel.h"
25 
26 #include "gui/createserver/gamecvaredit.h"
27 #include "ini/ini.h"
28 #include "plugins/engineplugin.h"
29 #include "serverapi/gamecreateparams.h"
31 
32 #include <QVariant>
33 #include <memory>
34 
35 namespace
36 {
37 struct CVarUi
38 {
39  std::shared_ptr<QLabel> label;
40  std::shared_ptr<GameCVarEdit> edit;
41 
42  QString command() const { return cvar().command(); }
43  GameCVar cvar() const { return edit->cvar(); }
44  QVariant value() const { return edit->value(); }
45  void setValue(const QVariant &value) { edit->setValue(value); }
46 };
47 }
48 
49 DClass<GameRulesPanel> : public Ui::GameRulesPanel
50 {
51 public:
52  bool anythingAvailable;
53  const EnginePlugin *engine;
54  GameCreateParams::HostMode hostMode;
55  GameMode gameMode;
56  QList<GameCVar> gameModifiers;
57  QList<std::shared_ptr<CVarUi> > cvarWidgets;
58  QMap<QString, QMap<QString, QVariant> > memorizedCVars;
59 };
60 
61 DPointered(GameRulesPanel)
62 
63 GameRulesPanel::GameRulesPanel(QWidget *parent)
64  : QWidget(parent)
65 {
66  d->setupUi(this);
67  d->anythingAvailable = true;
68  d->engine = nullptr;
69  d->hostMode = GameCreateParams::Host;
70 }
71 
72 GameRulesPanel::~GameRulesPanel()
73 {
74  d->cvarWidgets.clear();
75 }
76 
77 void GameRulesPanel::applyModeToUi()
78 {
79  bool engineAllowsSlotsLimits = false;
80  bool engineHasModifiers = false;
81  bool engineHasMapList = false;
82 
83  if (d->engine != nullptr)
84  {
85  setupModifiers(d->engine);
86  d->mapListPanel->setupForEngine(d->engine);
87  setupCVarWidgets(d->engine, d->gameMode);
88 
89  auto ecfg = d->engine->data();
90 
91  d->labelMaxClients->setVisible(ecfg->allowsClientSlots);
92  d->spinMaxClients->setVisible(ecfg->allowsClientSlots);
93  d->labelMaxPlayers->setVisible(ecfg->allowsPlayerSlots);
94  d->spinMaxPlayers->setVisible(ecfg->allowsPlayerSlots);
95 
96  // Remove hidden widgets to prevent creating extra spacing
97  // in the form layout.
98  d->hostingLimitsLayout->removeWidget(d->labelMaxClients);
99  d->hostingLimitsLayout->removeWidget(d->spinMaxClients);
100  d->hostingLimitsLayout->removeWidget(d->labelMaxPlayers);
101  d->hostingLimitsLayout->removeWidget(d->spinMaxPlayers);
102 
103  if (ecfg->allowsClientSlots)
104  d->hostingLimitsLayout->addRow(d->labelMaxClients, d->spinMaxClients);
105  if (ecfg->allowsPlayerSlots)
106  d->hostingLimitsLayout->addRow(d->labelMaxPlayers, d->spinMaxPlayers);
107 
108  engineAllowsSlotsLimits = ecfg->allowsClientSlots || ecfg->allowsPlayerSlots;
109  engineHasMapList = ecfg->hasMapList;
110  engineHasModifiers = !d->engine->gameModifiers().isEmpty();
111  }
112 
113  d->extraSettingsBox->setVisible(!d->cvarWidgets.isEmpty());
114 
115  bool slotLimitsBoxAvailable = d->hostMode == GameCreateParams::Host && engineAllowsSlotsLimits;
116  d->hostLimitsBox->setVisible(slotLimitsBoxAvailable);
117  d->mapListBox->setVisible(engineHasMapList);
118 
119  d->anythingAvailable = !d->cvarWidgets.isEmpty()
120  || engineHasModifiers
121  || engineHasMapList
122  || slotLimitsBoxAvailable;
123 }
124 
125 void GameRulesPanel::fillInParams(GameCreateParams &params)
126 {
127  params.setMaxClients(d->spinMaxClients->value());
128  params.setMaxPlayers(d->spinMaxPlayers->value());
129 
130  fillInCVars(params);
131  fillInModifiers(params);
132 
133  d->mapListPanel->fillInParams(params);
134 }
135 
136 void GameRulesPanel::fillInCVars(GameCreateParams &params)
137 {
138  for (auto &cvarUi : d->cvarWidgets)
139  {
140  params.cvars() << cvarUi->cvar();
141  }
142 }
143 
144 void GameRulesPanel::fillInModifiers(GameCreateParams &params)
145 {
146  int modIndex = d->cboModifier->currentIndex();
147  if (modIndex > 0) // Index zero is always "< NONE >"
148  {
149  --modIndex;
150  d->gameModifiers[modIndex].setValue(1);
151  params.cvars() << d->gameModifiers[modIndex];
152  }
153 }
154 
155 bool GameRulesPanel::isAnythingAvailable() const
156 {
157  return d->anythingAvailable;
158 }
159 
160 MapListPanel *GameRulesPanel::mapListPanel()
161 {
162  return d->mapListPanel;
163 }
164 
165 void GameRulesPanel::memorizeCVars()
166 {
167  if (d->engine != nullptr)
168  {
169  const QString &engineName = d->engine->nameCanonical();
170  QMap<QString, QVariant> &cvars = d->memorizedCVars[engineName];
171  for (auto &cvarUi : d->cvarWidgets)
172  cvars[cvarUi->command()] = cvarUi->value();
173  }
174 }
175 
176 void GameRulesPanel::loadMemorizedCVars(const EnginePlugin *engine)
177 {
178  if (d->memorizedCVars.contains(engine->nameCanonical()))
179  {
180  const QMap<QString, QVariant> &cvars = d->memorizedCVars[engine->nameCanonical()];
181  for (auto &cvarUi : d->cvarWidgets)
182  {
183  if (cvars.contains(cvarUi->command()))
184  cvarUi->setValue(cvars[cvarUi->command()]);
185  }
186  }
187 }
188 
189 void GameRulesPanel::loadConfig(Ini &config)
190 {
191  IniSection section = config.section("Rules");
192 
193  d->cboModifier->setCurrentIndex(section["modifier"]);
194  d->spinMaxClients->setValue(section["maxClients"]);
195  d->spinMaxPlayers->setValue(section["maxPlayers"]);
196  for (auto &cvarUi : d->cvarWidgets)
197  {
198  cvarUi->setValue(section[cvarUi->command()].value());
199  }
200 
201  d->mapListPanel->loadConfig(config);
202 }
203 
204 void GameRulesPanel::saveConfig(Ini &config)
205 {
206  IniSection section = config.section("Rules");
207 
208  section["modifier"] = d->cboModifier->currentIndex();
209  section["maxClients"] = d->spinMaxClients->value();
210  section["maxPlayers"] = d->spinMaxPlayers->value();
211  for (auto &cvarUi : d->cvarWidgets)
212  {
213  section[cvarUi->command()].setValue(cvarUi->value());
214  }
215 
216  d->mapListPanel->saveConfig(config);
217 }
218 
219 void GameRulesPanel::setCreateServerDialog(CreateServerDialog *dialog)
220 {
221  d->mapListPanel->setCreateServerDialog(dialog);
222 }
223 
224 void GameRulesPanel::setupForEngine(const EnginePlugin *engine, const GameMode &gameMode)
225 {
226  d->engine = engine;
227  d->gameMode = gameMode;
228  applyModeToUi();
229 }
230 
231 void GameRulesPanel::setupForHostMode(GameCreateParams::HostMode hostMode)
232 {
233  d->hostMode = hostMode;
234  applyModeToUi();
235 }
236 
237 void GameRulesPanel::setupModifiers(const EnginePlugin *engine)
238 {
239  QString selectedModifier = d->cboModifier->currentText();
240  d->cboModifier->clear();
241  d->gameModifiers.clear();
242 
243  QList<GameCVar> modifiers = engine->gameModifiers();
244 
245  if (!modifiers.isEmpty())
246  {
247  d->modifierBox->show();
248 
249  d->cboModifier->addItem(tr("< NONE >"));
250 
251  for (const GameCVar &cvar : modifiers)
252  {
253  d->cboModifier->addItem(cvar.name());
254  d->gameModifiers << cvar;
255  }
256  if (!selectedModifier.isEmpty())
257  {
258  int modifierIndex = d->cboModifier->findText(selectedModifier);
259  if (modifierIndex >= 0)
260  d->cboModifier->setCurrentIndex(modifierIndex);
261  }
262  }
263  else
264  {
265  d->modifierBox->hide();
266  }
267 }
268 
269 void GameRulesPanel::setupCVarWidgets(const EnginePlugin *engine, const GameMode &gameMode)
270 {
271  memorizeCVars();
272 
273  d->cvarWidgets.clear();
274  QList<GameCVar> cvars = engine->limits(gameMode);
275 
276  for (const GameCVar &cvar : cvars)
277  {
278  std::shared_ptr<CVarUi> cvarUi(new CVarUi);
279  cvarUi->edit.reset(new GameCVarEdit(cvar, this));
280  if (cvarUi->edit->externalLabel())
281  {
282  cvarUi->label.reset(new QLabel(this));
283  cvarUi->label->setText(tr("%1:").arg(cvar.name()));
284  }
285 
286  d->extraSettingsLayout->addRow(cvarUi->label.get(), cvarUi->edit.get());
287  d->cvarWidgets << std::move(cvarUi);
288  }
289 
290  loadMemorizedCVars(engine);
291 }