engineplugin.cpp
1 //------------------------------------------------------------------------------
2 // engineplugin.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) 2011 Braden "Blzut3" Obrzut <admin@maniacsvault.net>
22 //------------------------------------------------------------------------------
23 
24 #include "gui/configuration/engineconfigpage.h"
25 #include "ini/ini.h"
26 #include "irc/entities/ircnetworkentity.h"
27 #include "log.h"
28 #include "pathfinder/pathfind.h"
29 #include "plugins/enginedefaults.h"
30 #include "plugins/engineplugin.h"
31 #include "serverapi/gameexefactory.h"
32 #include "serverapi/gamefile.h"
33 #include "serverapi/gamehost.h"
34 #include "serverapi/server.h"
35 #include "strings.hpp"
36 
37 #include <cstdarg>
38 #include <QPixmap>
39 
40 EnginePlugin::Data::Data()
41 {
42  // Init the defaults.
43  allowsConnectPassword = false;
44  allowsClientSlots = true;
45  allowsPlayerSlots = true;
46  allowsEmail = false;
47  allowsJoinPassword = false;
48  allowsMOTD = false;
49  allowsRConPassword = false;
50  allowsURL = false;
51  allowsUpnp = false;
52  allowsUpnpPort = false;
53  allowsLogging = false;
54  broadcast = nullptr;
55  clientOnly = false;
57  defaultServerPort = 10666;
58  demoExtensionAutomatic = true;
59  demoExtension = "lmp";
60  hasIwad = true;
61  hasMapList = true;
62  icon = nullptr;
63  inGameFileDownloads = false;
64  masterClient = nullptr;
65  pConfig = nullptr;
66  refreshThreshold = 2;
67  supportsRandomMapRotation = false;
68  valid = true;
69  version = 0;
70  aboutProvider.reset();
71 }
72 
74 
75 EnginePlugin::EnginePlugin()
76 {
77  d = new Data;
78 
79  d->gameExeFactory = QSharedPointer<GameExeFactory>(new GameExeFactory(this));
80  d->difficulty = QSharedPointer<DefaultDifficultyProvider>(new DefaultDifficultyProvider());
81 
82  // At the moment I can't think of how we would support any ABI other than
83  // the current, but I suppose we might as well keep track of it?
84  d->abiVersion = DOOMSEEKER_ABI_VERSION;
85 }
86 
87 EnginePlugin::~EnginePlugin()
88 {
89  delete d->icon;
90  delete d->pConfig;
91  delete d;
92 }
93 
95 {
96  return new EngineConfigPage(this, *d->pConfig, parent);
97 }
98 
99 QList<DMFlagsSection> EnginePlugin::dmFlags() const
100 {
101  return QList<DMFlagsSection>();
102 }
103 
104 GameExeFactory *EnginePlugin::gameExe()
105 {
106  return data()->gameExeFactory.data();
107 }
108 
110 {
111  return new GameHost(this);
112 }
113 
114 QList<GameMode> EnginePlugin::gameModes() const
115 {
116  return QList<GameMode>();
117 }
118 
119 QList<GameCVar> EnginePlugin::gameModifiers() const
120 {
121  return QList<GameCVar>();
122 }
123 
124 void EnginePlugin::init(const char *name, const char *const icon[], ...)
125 {
126  d->name = name;
127  d->icon = new QPixmap(icon);
128  d->scheme = QString(d->name).replace(' ', "");
129 
130  va_list va;
131  va_start(va, icon);
132 
133  int feature;
134  while ((feature = va_arg(va, int)) != EP_Done)
135  {
136  switch (feature)
137  {
138  default:
139  // Since we don't know if the feature has arguments we must abort.
140  gLog << QString("%1 plugin attempted to use unknown feature.").arg(name);
141  d->valid = false;
142  return;
143 
144  case EP_Author:
145  d->author = va_arg(va, const char *);
146  break;
147  case EP_Version:
148  d->version = va_arg(va, unsigned int);
149  break;
150  case EP_AboutProvider:
151  d->aboutProvider.reset(va_arg(va, TextProvider *));
152  break;
153 
155  d->allowsConnectPassword = true;
156  break;
157  case EP_AllowsEmail:
158  d->allowsEmail = true;
159  break;
160  case EP_AllowsURL:
161  d->allowsURL = true;
162  break;
164  d->allowsJoinPassword = true;
165  break;
166  case EP_AllowsLogging:
167  d->allowsLogging = true;
168  break;
170  d->allowsRConPassword = true;
171  break;
172  case EP_AllowsMOTD:
173  d->allowsMOTD = true;
174  break;
175  case EP_AllowsUpnp:
176  d->allowsUpnp = true;
177  break;
178  case EP_AllowsUpnpPort:
179  d->allowsUpnpPort = true;
180  break;
181  case EP_Broadcast:
182  d->broadcast = va_arg(va, Broadcast *);
183  break;
184  case EP_CanonicalName:
185  d->canonicalName = va_arg(va, const char *);
186  break;
187  case EP_ClientOnly:
188  d->clientOnly = true;
189  break;
190  case EP_DefaultMaster:
191  d->defaultMaster = va_arg(va, const char *);
192  break;
194  d->defaultServerPort = va_arg(va, unsigned int);
195  break;
196  case EP_DemoExtension:
197  d->demoExtensionAutomatic = va_arg(va, unsigned int);
198  d->demoExtension = va_arg(va, const char *);
199  break;
201  d->difficulty = QSharedPointer<GameCVarProvider>(va_arg(va, GameCVarProvider *));
202  break;
204  d->createDMFlagsPagesAutomatic = false;
205  break;
207  d->inGameFileDownloads = true;
208  break;
209  case EP_IRCChannel:
210  {
211  // Either create an entity or put the channel in an existing one.
212  IRCNetworkEntity entity;
213  entity.setDescription(va_arg(va, const char *));
214  entity.setAddress(va_arg(va, const char *));
215  entity.autojoinChannels() << va_arg(va, const char *);
216 
217  if (d->ircChannels.contains(entity))
218  {
219  IRCNetworkEntity &existingEntity = d->ircChannels[d->ircChannels.indexOf(entity)];
220  existingEntity.autojoinChannels() << entity.autojoinChannels()[0];
221  }
222  else
223  d->ircChannels << entity;
224  break;
225  }
226  case EP_MasterClient:
227  d->masterClient = va_arg(va, MasterClient *);
228  break;
229  case EP_NoClientSlots:
230  d->allowsClientSlots = false;
231  break;
232  case EP_NoPlayerSlots:
233  d->allowsPlayerSlots = false;
234  break;
235  case EP_NoIwad:
236  d->hasIwad = false;
237  break;
238  case EP_NoMapList:
239  d->hasMapList = false;
240  break;
242  d->supportsRandomMapRotation = true;
243  break;
244  case EP_URLScheme:
245  d->scheme = va_arg(va, const char *);
246  break;
247  case EP_RefreshThreshold:
248  d->refreshThreshold = va_arg(va, unsigned int);
249  break;
250  case EP_ClientExeName:
251  d->clientExeName = va_arg(va, const char *);
252  break;
253  case EP_ServerExeName:
254  d->serverExeName = va_arg(va, const char *);
255  break;
257  {
258  QString suffixes = va_arg(va, const char *);
259  d->gameFileSearchSuffixes = suffixes.split(";", QString::SkipEmptyParts);
260  break;
261  }
262  }
263  }
264 
265  va_end(va);
266 }
267 
268 void EnginePlugin::masterHost(QString &host, unsigned short &port) const
269 {
270  QString str = d->pConfig->setting("Masterserver");
271  Strings::translateServerAddress(str, host, port, d->defaultMaster);
272 }
273 
275 {
276  if (!d->canonicalName.isEmpty())
277  {
278  return d->canonicalName;
279  }
280  else
281  {
282  // Derive.
283  QString name = data()->name;
284  name = name.toLower();
285  name = name.replace(QRegExp("\\s"), "_");
286  return name;
287  }
288 }
289 
290 ServerPtr EnginePlugin::server(const QHostAddress &address, unsigned short port) const
291 {
292  ServerPtr server = mkServer(address, port);
293  if (server != nullptr)
294  server->setSelf(server.toWeakRef());
295  return server;
296 }
297 
298 void EnginePlugin::setConfig(IniSection &ini)
299 {
300  d->pConfig = new IniSection(ini);
301 
302  ini.createSetting("Masterserver", data()->defaultMaster);
303  findGameFiles(ini);
304 
305  setupConfig(ini);
306 }
307 
309 {
310  Q_UNUSED(config);
311 }
312 
313 void EnginePlugin::setGameExeFactory(QSharedPointer<GameExeFactory> factory)
314 {
315  d->gameExeFactory = factory;
316 }
317 
318 void EnginePlugin::findGameFiles(IniSection &ini)
319 {
320  for (const GameFile &file : gameExe()->gameFiles().asQList())
321  {
322  if (!ini.hasSetting(file.configName()))
323  {
324  QString path = PathFind::findGameFile(collectKnownPaths(ini), file);
325  ini[file.configName()] = path;
326  }
327  }
328 }
329 
330 QStringList EnginePlugin::collectKnownPaths(const IniSection &ini) const
331 {
332  QStringList paths;
333  for (const GameFile &file : data()->gameExeFactory->gameFiles().asQList())
334  {
335  QString path = ini.retrieveSetting(file.configName()).valueString();
336  if (!path.isEmpty())
337  {
338  paths << path;
339  }
340  }
341  return paths;
342 }
343 
345 {
346 }