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