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 }
Disables specifying amount of player slots in create game box.
Definition: engineplugin.h:197
IniVariable createSetting(const QString &name, const QVariant &data)
Inits specified variable with specified data.
Definition: inisection.cpp:57
bool createDMFlagsPagesAutomatic
Controls behavior of "Create Game" dialog.
Definition: engineplugin.h:309
Creates GameCVar set.
Informs that the game has no notion of an IWAD.
Definition: engineplugin.h:179
QPixmap * icon
icon of the engine
Definition: engineplugin.h:281
(const char*) Author of the plugin.
Definition: engineplugin.h:88
virtual QList< DMFlagsSection > dmFlags() const
Game settings flags.
static void translateServerAddress(const QString &addressString, QString &hostname, unsigned short &port, const QString &defaultAddress)
Translates string in format "hostname:port" to atomic values.
Definition: strings.cpp:393
QScopedPointer< TextProvider > aboutProvider
Description of the plugin, intended to be displayed in the "About" dialog.
Definition: engineplugin.h:298
virtual void start()
Start services, init data structures.
virtual void setupConfig(IniSection &config)
Reimplement if you want to perform some ini initialization manually.
QSharedPointer< GameExeFactory > gameExeFactory
Factory of executable retrievers ExeFile objects.
Definition: engineplugin.h:321
Allows the player to join a server without downloading files through Wadseeker.
Definition: engineplugin.h:99
virtual ConfigPage * configuration(QWidget *parent)
Engine&#39;s configuration widget.
virtual ServerPtr mkServer(const QHostAddress &address, unsigned short port) const =0
Create an instance of local Server subclass and return a ServerPtr.
Tells the create game box that this game allows UPnP.
Definition: engineplugin.h:204
MasterClient object.
Definition: engineplugin.h:123
Signifies that servers can be created with a join password.
Definition: engineplugin.h:94
void init(const char *name, const char *const icon[],...)
virtual GameHost * gameHost()
Creates an instance of GameHost derivative class.
Signifies that a server can be created with a random map rotation.
Definition: engineplugin.h:101
const QString & configName() const
Setting name where path will be stored in plugin&#39;s IniSection.
Definition: gamefile.cpp:60
const QStringList & autojoinChannels() const
List of channels to which a /join command will be issued automatically when a connection with this ne...
File name for game&#39;s server executable if game has any.
Definition: engineplugin.h:143
void masterHost(QString &host, unsigned short &port) const
LAN Broadcast object.
Definition: engineplugin.h:119
Returns executable file retrievers from plugins to Doomseeker.
(const char*) Default ip address and port ("address:port") for master server. Requires EP_HasMasterSe...
Definition: engineplugin.h:97
(bool)auto, (const char*)extension Sets the extension that will be used for demos (default is true an...
Definition: engineplugin.h:104
bool hasSetting(const QString &name) const
true if setting of given name exists within the section.
Definition: inisection.cpp:78
GameCVarProvider that returns difficulty levels ordered from easiest to hardest.
Definition: engineplugin.h:168
Signifies that servers can be created for remote console access.
Definition: engineplugin.h:95
IniVariable retrieveSetting(const QString &name)
Gets a variable but only if it already exists.
Definition: inisection.cpp:109
virtual ServerPtr server(const QHostAddress &address, unsigned short port) const
Creates an instance of server object from this plugin.
Provides a description to be shown in the "About" menu.
Definition: engineplugin.h:222
File name for game&#39;s client (main) executable.
Definition: engineplugin.h:132
Tells the create game box that this game allows to modify UPnP port.
Definition: engineplugin.h:218
Signifies that servers can have a message of the day.
Definition: engineplugin.h:96
Signifies that servers can provide a URL for potential wad downloads.
Definition: engineplugin.h:93
Signals the end of init parameters.
Definition: engineplugin.h:86
(quint8) The amount of time (in seconds) that must pass before a server can be requeried.
Definition: engineplugin.h:102
Signifies that servers can be created with a connection password.
Definition: engineplugin.h:91
Disables map list in create game box.
Definition: engineplugin.h:172
virtual QList< GameMode > gameModes() const
Game modes (cooperative, deathmatch, ctf).
enables logging info (like console output) into a file. This will show the Logging section in the gen...
Definition: engineplugin.h:255
Signifies that servers can have an administrative contact email attached.
Definition: engineplugin.h:92
Data structure that describes and defines a connection to an IRC network or server.
virtual QList< GameCVar > gameModifiers() const
Modifier that apply to all game modes (ex. instagib).
INI section representation.
Definition: inisection.h:40
Indicates that client binary serves the purpose of the client and server.
Definition: engineplugin.h:115
Creates game servers, offline games or demo playbacks.
Definition: gamehost.h:69
Game file definition allows to browse this file in configuration box.
Definition: gamefile.h:72
(unsigned int) Single version number for plugin.
Definition: engineplugin.h:89
(quint16) Default port for custom server creation.
Definition: engineplugin.h:98
QString nameCanonical() const
Either specified explicitly by plugin or derived from the actual plugin name.
Abstract base for all MasterClients.
Definition: masterclient.h:49
Default search suffixes used to automatically find game files.
Definition: engineplugin.h:160
(const char*)server, (const char*)channel - Can be repeated. Default IRC channels.
Definition: engineplugin.h:100
(const char*) Overrides the URL scheme which Doomseeker sets for this plugin. By default it is the po...
Definition: engineplugin.h:103
Base for configuration pages for plugins; provides some default behavior.
Plugin canonical name; should match filenames of the library and translation files.
Definition: engineplugin.h:249
QString defaultMaster
Default port on which servers for given engine are hosted.
Definition: engineplugin.h:278
Base class for configuration pages.
Definition: configpage.h:44
Disables specifying amount of client slots in create game box.
Definition: engineplugin.h:188