xoreos  0.0.5
xoreos.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #define SDL_MAIN_HANDLED
26 
27 #include <cassert>
28 #include <cstdio>
29 
30 #include <vector>
31 
32 #include "src/cline.h"
33 #include "src/engines.h"
34 
35 #include "src/common/ustring.h"
36 #include "src/common/util.h"
37 #include "src/common/error.h"
38 #include "src/common/platform.h"
39 #include "src/common/filepath.h"
40 #include "src/common/threads.h"
41 #include "src/common/debugman.h"
42 #include "src/common/configman.h"
43 #include "src/common/xml.h"
44 
45 #include "src/aurora/resman.h"
46 #include "src/aurora/2dareg.h"
47 #include "src/aurora/language.h"
48 #include "src/aurora/talkman.h"
49 #include "src/aurora/util.h"
50 
51 #include "src/graphics/queueman.h"
52 #include "src/graphics/graphics.h"
53 
54 #include "src/sound/sound.h"
55 
56 #include "src/events/requests.h"
57 #include "src/events/events.h"
58 #include "src/events/timerman.h"
59 
61 #include "src/engines/gamethread.h"
62 
66 
67 static void initPlatform();
68 static void initConfig();
69 
70 static void init();
71 static void deinit();
72 
73 static void listDebug();
74 
75 static bool configFileIsBroken = false;
76 
77 int main(int argc, char **argv) {
78  initPlatform();
79  initConfig();
80 
81  std::vector<Common::UString> args;
82  Common::UString target;
83 
84  try {
85  Common::Platform::getParameters(argc, argv, args);
86 
87  int code;
88  if (!parseCommandline(args, target, code))
89  return code;
90 
91  } catch (...) {
93 
94  return 1;
95  }
96 
97  // Check the requested target
98  if (target.empty() || !ConfigMan.hasGame(target)) {
99  Common::UString path = ConfigMan.getString("path", "");
100  if (path.empty()) {
101  if (ConfigMan.getBool("listdebug", false)) {
102  listDebug();
103  return 0;
104  }
105 
106  error("Neither an existing target, nor a path specified");
107  }
108 
109  bool useExisting = false;
110  if (target.empty()) {
111  target = ConfigMan.findGame(path);
112  if (!target.empty()) {
113  warning("No target specified, but found a target with a matching path");
114  useExisting = true;
115  }
116  }
117 
118  target = ConfigMan.createGame(path, target);
119  if (target.empty())
120  error("Failed creating a new config target for the game");
121 
122  if (!useExisting)
123  warning("Creating a new target for this game");
124  }
125 
126  if (!ConfigMan.setGame(target) || !ConfigMan.isInGame())
127  error("No target \"%s\" in the config file", target.c_str());
128 
129  /* Open the log file.
130  *
131  * NOTE: A log is opened by default, unless the logfile config value
132  * is set to an empty string or nologfile is set to true.
133  */
134  Common::UString logFile = DebugMan.getDefaultLogFile();
135  if (ConfigMan.hasKey("logfile"))
136  logFile = ConfigMan.getString("logfile", "");
137  if (ConfigMan.getBool("nologfile", false))
138  logFile.clear();
139 
140  if (!logFile.empty())
141  if (!DebugMan.openLogFile(logFile))
142  warning("Failed to open log file \"%s\" for writing", logFile.c_str());
143 
144  DebugMan.logCommandLine(args);
145 
146  status("Target \"%s\"", target.c_str());
147 
148  Common::UString dirArg = ConfigMan.getString("path", "");
149  if (dirArg.empty())
150  error("Target \"%s\" is missing a path", target.c_str());
151 
152  Common::UString baseDir;
153  try {
154  baseDir = Common::FilePath::canonicalize(dirArg);
155  } catch (...) {
156  error("Invalid path \"%s\"", dirArg.c_str());
157  }
158 
160  error("No such file or directory \"%s\"", baseDir.c_str());
161 
162  std::list<const Engines::EngineProbe *> probes;
163 
164  Engines::GameThread *gameThread = new Engines::GameThread;
165  try {
166  // Enable requested debug channels
167  DebugMan.setVerbosityLevelsFromConfig();
168 
169  // Initialize all necessary subsystems
170  init();
171 
172  // Create all our engine probes
173  createEngineProbes(probes);
174 
175  // Probe and create the game engine
176  gameThread->init(baseDir, probes);
177 
178  if (ConfigMan.getBool("listdebug", false)) {
179  // List debug channels
180  listDebug();
181  } else {
182  // Run the game
183  gameThread->run();
184  EventMan.runMainLoop();
185  }
186 
187  } catch (...) {
189  }
190 
191  if (EventMan.fatalErrorRaised())
192  std::exit(1);
193 
194  status("Shutting down");
195 
196  try {
197  delete gameThread;
198  } catch (...) {
199  }
200 
201  destroyEngineProbes(probes);
202 
203  try {
204  // Sync changed debug channel settings
205  DebugMan.setConfigToVerbosityLevels();
206 
207  // Configs changed, we should save them
208  if (ConfigMan.changed()) {
209  // But don't clobber a broken save
210  if (!configFileIsBroken)
211  ConfigMan.save();
212  }
213  } catch (...) {
215  }
216 
217  deinit();
218  return 0;
219 }
220 
221 static void initPlatform() {
222  try {
224  } catch (...) {
225  Common::exceptionDispatcherError("Failed to initialize the low-level platform-specific subsytem");
226  std::exit(1);
227  }
228 }
229 
230 static void initConfig() {
231  bool newConfig = false;
232  if (!ConfigMan.load()) {
233  // Loading failed, create an empty config file
234 
235  ConfigMan.create();
236 
237  // Mark the config as either broken or new
238  if (ConfigMan.fileExists())
239  configFileIsBroken = true;
240  else
241  newConfig = true;
242  }
243 
244  ConfigMan.setInt (Common::kConfigRealmDefault, "width" , 800);
245  ConfigMan.setInt (Common::kConfigRealmDefault, "height", 600);
246  ConfigMan.setBool (Common::kConfigRealmDefault, "fullscreen", false);
247  ConfigMan.setInt (Common::kConfigRealmDefault, "fsaa", 0);
248 
249  ConfigMan.setDouble(Common::kConfigRealmDefault, "volume" , 1.0);
250  ConfigMan.setDouble(Common::kConfigRealmDefault, "volume_music", 1.0);
251  ConfigMan.setDouble(Common::kConfigRealmDefault, "volume_sfx" , 1.0);
252  ConfigMan.setDouble(Common::kConfigRealmDefault, "volume_voice", 1.0);
253  ConfigMan.setDouble(Common::kConfigRealmDefault, "volume_video", 1.0);
254 
255  ConfigMan.setBool(Common::kConfigRealmDefault, "showfps", false);
256 
257  ConfigMan.setBool(Common::kConfigRealmDefault, "skipvideos", false);
258 
259  ConfigMan.setBool(Common::kConfigRealmDefault, "saveconf", true);
260 
261  // Populate the new config with the defaults
262  if (newConfig) {
263  ConfigMan.setDefaults();
264  ConfigMan.save();
265  }
266 }
267 
268 static void listDebug() {
269  std::vector<Common::UString> names, descriptions;
270  DebugMan.getDebugChannels(names, descriptions);
271 
272  assert(names.size() == descriptions.size());
273 
274  size_t maxNameLength = 0;
275  for (std::vector<Common::UString>::const_iterator n = names.begin(); n != names.end(); n++)
276  maxNameLength = MAX(maxNameLength, n->size());
277 
278  assert(maxNameLength < INT_MAX);
279 
280  for (size_t i = 0; i < names.size(); i++)
281  std::printf("%-*s - %s\n", (int) maxNameLength, names[i].c_str(), descriptions[i].c_str());
282 }
283 
284 static void init() {
285  // Init threading system
287 
288  // Init libxml2
289  Common::initXML();
290 
291  // Init subsystems
292  GfxMan.init();
293  status("Graphics subsystem initialized");
294  SoundMan.init();
295  status("Sound subsystem initialized");
296  EventMan.init();
297  status("Event subsystem initialized");
298 }
299 
300 static void deinit() {
301  // Deinit subsystems
302  try {
303  if (Common::initedThreads()) {
304  EventMan.deinit();
305  SoundMan.deinit();
306  GfxMan.deinit();
307  }
308  } catch (...) {
309  }
310 
311  // Deinit libxml2
313 
314  // Destroy global singletons
318 
324 
326 
330 
332 
335 
338 }
Inter-thread request events.
The thread the game logic runs in.
bool parseCommandline(const std::vector< Common::UString > &argv, Common::UString &target, int &code)
Definition: cline.cpp:189
The global graphics manager.
void init(const Common::UString &baseDir, const std::list< const EngineProbe *> &probes)
Definition: gamethread.cpp:50
A class holding an UTF-8 string.
Definition: ustring.h:48
The global config manager.
static void initConfig()
Definition: xoreos.cpp:230
int main(int argc, char **argv)
Definition: xoreos.cpp:77
The Aurora texture manager.
static bool isDirectory(const UString &p)
Does specified path exist and is it a directory?
Definition: filepath.cpp:56
Utility functions to handle files used in BioWare&#39;s Aurora engine.
Command line arguments parser.
static void getParameters(int argc, char **argv, std::vector< UString > &args)
Read the command line parameters into UTF-8 strings.
Definition: platform.cpp:87
Platform-dependant functions, mostly for internal use in the Common namespace.
static bool configFileIsBroken
Definition: xoreos.cpp:75
The Aurora font manager.
Basic exceptions to throw.
Threading system helpers.
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
The debug manager, managing debug channels.
#define ConfigMan
Shortcut for accessing the config manager.
Definition: configman.h:176
static bool isRegularFile(const UString &p)
Does specified path exist and is it a regular file?
Definition: filepath.cpp:52
Utility templates and functions.
void initThreads()
Initialize the global threading system.
Definition: threads.cpp:43
The global events manager.
Types and functions related to language.
static UString canonicalize(const UString &p, bool resolveSymLinks=true)
Return the canonical, absolutized and normalized path.
Definition: filepath.cpp:230
XML parsing helpers, using libxml2.
The global sound manager, handling all sound output.
bool empty() const
Is the string empty?
Definition: ustring.cpp:245
#define SoundMan
Shortcut for accessing the sound manager.
Definition: sound.h:293
The global 2DA registry.
The graphics queue manager.
static void destroy()
Definition: requests.cpp:183
void warning(const char *s,...)
Definition: util.cpp:33
#define DebugMan
Shortcut for accessing the debug manager.
Definition: debugman.h:195
#define EventMan
Shortcut for accessing the events manager.
Definition: events.h:210
The game thread, running all game logic.
Definition: gamethread.h:39
The Aurora cursor manager.
bool initedThreads()
Was the global threading system initialized?
Definition: threads.cpp:50
Unicode string handling.
void exceptionDispatcherError(const char *s,...)
Exception dispatcher that prints the exception as an error, and adds another reason on top...
Definition: error.cpp:143
void deinitXML()
Deinitialize the XML subsystem.
Definition: xml.cpp:71
Application or game defaults.
Definition: configman.h:46
static void listDebug()
Definition: xoreos.cpp:268
static void init()
Definition: xoreos.cpp:284
The global talk manager for Aurora strings.
void createEngineProbes(std::list< const ::Engines::EngineProbe *> &probes)
Definition: probes.cpp:98
The global timer manager.
void status(const char *s,...)
Definition: util.cpp:52
void initXML()
Initialize the XML subsystem.
Definition: xml.cpp:66
The global engine manager, omniscient about all engines.
static void initPlatform()
Definition: xoreos.cpp:221
void destroyEngineProbes(std::list< const Engines::EngineProbe *> &probes)
Destroy all the probes again.
Definition: engines.cpp:51
static void deinit()
Definition: xoreos.cpp:300
void NORETURN_PRE error(const char *s,...)
Definition: util.cpp:86
static void init()
Initialize platform-dependant things.
Definition: platform.cpp:53
T MAX(T a, T b)
Definition: util.h:71
void clear()
Clear the string&#39;s contents.
Definition: ustring.cpp:236
#define GfxMan
Shortcut for accessing the graphics manager.
Definition: graphics.h:299
The global resource manager for Aurora resources.
Utility class for manipulating file paths.
Utility functions to handle the engines.