~widelands-dev/widelands/trunk

6172 by Holger Rapp
stray character broke building in last commit. sorry
1
/*
11165 by The Widelands Bunnybot
Update copyright end year to 2025
2
 * Copyright (C) 2006-2025 by the Widelands Development Team
1164 by bedouin
- WLApplication patch 1/12
3
 *
4
 * This program is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU General Public License
6
 * as published by the Free Software Foundation; either version 2
7
 * of the License, or (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
10152 by The Widelands Bunnybot
Add check for missing copyright headers (#5223)
15
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
1164 by bedouin
- WLApplication patch 1/12
16
 *
17
 */
18
2233 by sigra
Fix parameter type of split_string. Get rid of util.h. Everything declared there was also declared in helper.h since at least revision 1756. Try to have includes ordered in groups and sorted within the groups. Add some missing includes revealed by that change. Simplify visibility specifications. Fix overlong lines.
19
#include "wlapplication.h"
20
9204 by The Widelands Bunnybot
Noordfrees: Launchpad mirror (#3766)\n\nMirrors all changes at widelands:master to lp:widelands (1d6b62c7619a182081e1c942ae533a95d6112044)
21
#include <cassert>
6667.1.1 by Holger Rapp
Added new codecheck rule that complains about wrong include order. This adds tons of codecheck errors.
22
#ifndef _WIN32
23
#include <csignal>
24
#endif
9532 by The Widelands Bunnybot
Add Codecheck rule for <cstdlib> to make libc++ happy (#4223)
25
#include <cstdlib>
10305 by The Widelands Bunnybot
Workaround for inverted horizontal scrolling bug in SDL (#5394)
26
#include <cstring>
6667.1.1 by Holger Rapp
Added new codecheck rule that complains about wrong include order. This adds tons of codecheck errors.
27
#include <iostream>
6969.1.48 by Holger Rapp
Fixed style issues.
28
#include <memory>
9516 by The Widelands Bunnybot
Allow sparse IDs in plot area data (#4179)
29
#include <regex>
6667.1.1 by Holger Rapp
Added new codecheck rule that complains about wrong include order. This adds tons of codecheck errors.
30
9275 by The Widelands Bunnybot
Cleanup SDL headers (#3743)
31
#include <SDL.h>
10997 by The Widelands Bunnybot
Show splash screen earlier and reintroduce intro music (GH #6412 / CB #4773)
32
#include <SDL_mouse.h>
8307.3.1 by GunChleoc
Split graphics into multiple libraries. This includes some changes to wordwrap (used by the old font renderer and the edit boxes). Shifted some functions from align to text_layout. Moved TextStyle from text_layout to font.
33
#include <SDL_ttf.h>
6667.1.1 by Holger Rapp
Added new codecheck rule that complains about wrong include order. This adds tons of codecheck errors.
34
#ifdef __APPLE__
35
#include <mach-o/dyld.h>
7296 by Holger Rapp
Emergency fix: Repair mac os X nightlies.
36
#include <unistd.h>
6667.1.1 by Holger Rapp
Added new codecheck rule that complains about wrong include order. This adds tons of codecheck errors.
37
#endif
38
#include <sys/stat.h>
39
#include <sys/types.h>
40
6969.1.39 by Holger Rapp
Broke cyclic dependency between i18n and profile and made i18n a stand alone library.
41
#include "base/i18n.h"
6969.1.6 by Holger Rapp
- Added a wl_library cmake function to define a common way of building widelands.
42
#include "base/log.h"
9971 by The Widelands Bunnybot
Improved exception reporting (#5003)
43
#include "base/macros.h"
9921 by The Widelands Bunnybot
Multithreading (#4319)
44
#include "base/multithreading.h"
9204 by The Widelands Bunnybot
Noordfrees: Launchpad mirror (#3766)\n\nMirrors all changes at widelands:master to lp:widelands (1d6b62c7619a182081e1c942ae533a95d6112044)
45
#include "base/random.h"
10060 by The Widelands Bunnybot
Deprecate Boost (#5101)
46
#include "base/string.h"
7047 by Holger Rapp
Gave scoped_timer and time_string their own base libraries.
47
#include "base/time_string.h"
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
48
#include "base/warning.h"
6969.1.6 by Holger Rapp
- Added a wl_library cmake function to define a common way of building widelands.
49
#include "base/wexception.h"
3959 by bedouin
- Implement feature request #2782462: "Add buildtype and OS reminder to crash
50
#include "build_info.h"
6969.1.61 by Holger Rapp
refactored how warnings are defined and increased the warning verbosity for clang.
51
#include "config.h"
4004 by sirver
Removed all modifications to include paths in SConcscripts. All files must now be included with their complete paths 'include ui_panel.h' -> 'include ui/ui_basic/ui_panel.h'. I will rename a lot of files in the next commit, so be prepared (ui/ui_basic/ui_panel.h will become ui_basic/panel.h)
52
#include "editor/editorinteractive.h"
9593 by The Widelands Bunnybot
Random matches & Editor launching convenience (#4289)
53
#include "editor/ui_menus/main_menu_random_map.h"
7051 by Holger Rapp
Separate constants.h into a few more specialized files.
54
#include "graphic/default_resolution.h"
8710.4.4 by GunChleoc
Renamed font_handler1 to font_handler
55
#include "graphic/font_handler.h"
9484 by The Widelands Bunnybot
Reduce graphic.h includes (#4159)
56
#include "graphic/graphic.h"
10997 by The Widelands Bunnybot
Show splash screen earlier and reintroduce intro music (GH #6412 / CB #4773)
57
#include "graphic/graphic_functions.h"
9251 by The Widelands Bunnybot
Add numpad hotkeys (#3840)
58
#include "graphic/mouse_cursor.h"
10525 by The Widelands Bunnybot
Make richtext.lua styleable and allow partial theme addons (#5748)
59
#include "graphic/style_manager.h"
7211.3.36 by fios at foramnagaidhlig
Moved FontSet into own class in grapic/text. It now also parses itself.
60
#include "graphic/text/font_set.h"
6557.1.1 by Holger Rapp
Parts of the richtext tests run again.
61
#include "io/filesystem/disk_filesystem.h"
8895.5.1 by artydent
Added a GenericSaveHandler class to handle saving:
62
#include "io/filesystem/filesystem_exceptions.h"
6557.1.1 by Holger Rapp
Parts of the richtext tests run again.
63
#include "io/filesystem/layered_filesystem.h"
9682 by The Widelands Bunnybot
Add-Ons (#4464)
64
#include "logic/addons.h"
8074.1.86 by GunChleoc
Refactored logic/constants.h
65
#include "logic/filesystem_constants.h"
6557.1.1 by Holger Rapp
Parts of the richtext tests run again.
66
#include "logic/game.h"
67
#include "logic/game_data_error.h"
7027 by Holger Rapp
Renamed src files that contain capital letters.
68
#include "logic/game_settings.h"
6557.1.1 by Holger Rapp
Parts of the richtext tests run again.
69
#include "logic/map.h"
70
#include "logic/replay.h"
7044 by Holger Rapp
Move more stuff out of the base directory.
71
#include "logic/single_player_game_controller.h"
72
#include "logic/single_player_game_settings_provider.h"
6557.1.1 by Holger Rapp
Parts of the richtext tests run again.
73
#include "map_io/map_loader.h"
8349.2.1 by Notabilis
Renamed NetHost/NetClient to GameHost/GameClient.
74
#include "network/gameclient.h"
75
#include "network/gamehost.h"
9916 by The Widelands Bunnybot
6 files were automatically formatted.
76
#include "network/host_game_settings_provider.h"
6557.1.1 by Holger Rapp
Parts of the richtext tests run again.
77
#include "network/internet_gaming.h"
78
#include "sound/sound_handler.h"
10752 by The Widelands Bunnybot
Further enhancements for ship construction (#6129)
79
#include "ui_basic/color_chooser.h"
6557.1.1 by Holger Rapp
Parts of the richtext tests run again.
80
#include "ui_basic/messagebox.h"
81
#include "ui_basic/progresswindow.h"
7877.1.1 by fios at foramnagaidhlig
Moved Readme, License and Authors in ui_fsmenu into a tabbed panel. wui no longer depends on ui_fsmenu.
82
#include "ui_fsmenu/about.h"
10738 by The Widelands Bunnybot
Self-diagnose crashes (#6100)
83
#include "ui_fsmenu/crash_report.h"
7027 by Holger Rapp
Renamed src files that contain capital letters.
84
#include "ui_fsmenu/launch_spg.h"
4013 by sirver
Moved fullscreen menus from ui to ui_fsmenu
85
#include "ui_fsmenu/loadgame.h"
86
#include "ui_fsmenu/main.h"
4397 by sigra
Remove the redundant and dangerous Encyclopedia_Window::interactivePlayer. Fix includes, especially the regression that #include "graphic/picture.h" was added to widelands_geometry.h in revision 4261. It has no right to be there.
87
#include "ui_fsmenu/mapselect.h"
4013 by sirver
Moved fullscreen menus from ui to ui_fsmenu
88
#include "ui_fsmenu/options.h"
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
89
#include "wlapplication_messages.h"
10028 by The Widelands Bunnybot
Fix race condition when resizing game window (#5067)
90
#include "wlapplication_mousewheel_options.h"
8729.1.25 by Lucki
Refactor g_options
91
#include "wlapplication_options.h"
10744 by The Widelands Bunnybot
'src/ui_fsmenu/main.cc' was automatically formatted.
92
#include "wui/game_chat_panel.h"
4001 by sirver
Moved more UserInterface classes to WUI. Started logic sublibrary (with currently only one member file).
93
#include "wui/interactive_player.h"
94
#include "wui/interactive_spectator.h"
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
95
#include "wui/maptable.h"
2233 by sigra
Fix parameter type of split_string. Get rid of util.h. Everything declared there was also declared in helper.h since at least revision 1756. Try to have includes ordered in groups and sorted within the groups. Add some missing includes revealed by that change. Simplify visibility specifications. Fix overlong lines.
96
10027 by The Widelands Bunnybot
Speed up add-on remote interaction window (#5076)
97
std::string get_executable_directory(const bool logdir) {
7212 by Holger Rapp
Emergency fix for paths in Mac OS X to unbreak nightly builds.
98
	std::string executabledir;
99
#ifdef __APPLE__
100
	uint32_t buffersize = 0;
101
	_NSGetExecutablePath(nullptr, &buffersize);
8048 by GunChleoc
Ran clang-format.
102
	std::unique_ptr<char[]> buffer(new char[buffersize]);
7212 by Holger Rapp
Emergency fix for paths in Mac OS X to unbreak nightly builds.
103
	int32_t check = _NSGetExecutablePath(buffer.get(), &buffersize);
104
	if (check != 0) {
8048 by GunChleoc
Ran clang-format.
105
		throw wexception("could not find the path of the main executable");
7212 by Holger Rapp
Emergency fix for paths in Mac OS X to unbreak nightly builds.
106
	}
107
	executabledir = std::string(buffer.get());
108
	executabledir.resize(executabledir.rfind('/') + 1);
109
#endif
110
#ifdef __linux__
111
	char buffer[PATH_MAX];
112
	size_t size = readlink("/proc/self/exe", buffer, PATH_MAX);
113
	if (size <= 0) {
8048 by GunChleoc
Ran clang-format.
114
		throw wexception("could not find the path of the main executable");
7212 by Holger Rapp
Emergency fix for paths in Mac OS X to unbreak nightly builds.
115
	}
116
	executabledir = std::string(buffer, size);
117
	executabledir.resize(executabledir.rfind('/') + 1);
118
#endif
119
#ifdef _WIN32
120
	char filename[_MAX_PATH + 1] = {0};
121
	GetModuleFileName(nullptr, filename, MAX_PATH);
122
	executabledir = filename;
123
	executabledir = executabledir.substr(0, executabledir.rfind('\\'));
124
#endif
10027 by The Widelands Bunnybot
Speed up add-on remote interaction window (#5076)
125
	if (logdir) {
126
		log_info("Widelands executable directory: %s\n", executabledir.c_str());
127
	}
7212 by Holger Rapp
Emergency fix for paths in Mac OS X to unbreak nightly builds.
128
	return executabledir;
129
}
130
10027 by The Widelands Bunnybot
Speed up add-on remote interaction window (#5076)
131
namespace {
132
133
/**
134
 * Shut the hardware down: stop graphics mode, stop sound handler
135
 */
136
#ifndef _WIN32
10194 by The Widelands Bunnybot
Fix misc clang-tidy checks in remaining files (#5289)
137
void terminate(int /*unused*/) {
10027 by The Widelands Bunnybot
Speed up add-on remote interaction window (#5076)
138
	// The logger can already be shut down, so we use cout
139
	std::cout
140
	   << "Waited 5 seconds to close audio. There are some problems here, so killing Widelands."
141
	      " Update your sound driver and/or SDL to fix this problem\n";
142
	raise(SIGKILL);
143
}
144
#endif
145
10688 by The Widelands Bunnybot
Resolve compiler warnings (#6021)
146
#ifdef SIGUSR1
10612 by The Widelands Bunnybot
Make Main Menu Dropdown Entries a Bigger Click Target (#5902)
147
void toggle_verbose(int /*unused*/) {
148
	g_verbose = !g_verbose;
149
}
10688 by The Widelands Bunnybot
Resolve compiler warnings (#6021)
150
#endif
10612 by The Widelands Bunnybot
Make Main Menu Dropdown Entries a Bigger Click Target (#5902)
151
7224.1.9 by Holger Rapp
One more go. Removed one configuration variable and made the code simpler.
152
bool is_absolute_path(const std::string& path) {
9516 by The Widelands Bunnybot
Allow sparse IDs in plot area data (#4179)
153
	std::regex re("^/|\\w:");
154
	return std::regex_search(path.c_str(), re);
7224.1.9 by Holger Rapp
One more go. Removed one configuration variable and made the code simpler.
155
}
7212 by Holger Rapp
Emergency fix for paths in Mac OS X to unbreak nightly builds.
156
7296 by Holger Rapp
Emergency fix: Repair mac os X nightlies.
157
// Returns the absolute path of 'path' which might be relative.
8048 by GunChleoc
Ran clang-format.
158
std::string absolute_path_if_not_windows(const std::string& path) {
7212 by Holger Rapp
Emergency fix for paths in Mac OS X to unbreak nightly builds.
159
#ifndef _WIN32
160
	char buffer[PATH_MAX];
9204 by The Widelands Bunnybot
Noordfrees: Launchpad mirror (#3766)\n\nMirrors all changes at widelands:master to lp:widelands (1d6b62c7619a182081e1c942ae533a95d6112044)
161
	// https://pubs.opengroup.org/onlinepubs/009695399/functions/realpath.html
8182.2.9 by GunChleoc
Fixed compiler warning with realpath in absolute_path_if_not_windows.
162
	char* rp = realpath(path.c_str(), buffer);
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
163
	log_info("Realpath: %s\n", rp);
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
164
	if (rp == nullptr) {
8751.3.1 by GunChleoc
Exit gracefully if user specifies a datadir that doesn't exist
165
		throw wexception("Unable to get absolute path for %s", path.c_str());
166
	}
8182.2.9 by GunChleoc
Fixed compiler warning with realpath in absolute_path_if_not_windows.
167
	return std::string(rp);
7212 by Holger Rapp
Emergency fix for paths in Mac OS X to unbreak nightly builds.
168
#else
169
	return path;
170
#endif
171
}
172
7296 by Holger Rapp
Emergency fix: Repair mac os X nightlies.
173
// On Mac OS, we bundle the shared libraries that Widelands needs directly in
174
// the executable directory. This is so that SDL_Image and SDL_Mixer can load
175
// them dynamically. Unfortunately, linking them statically has led to problems
176
// in the past.
177
//
178
// Changing LD_LIBRARY_PATH does not work, so we resort to the hack of chdir()
179
// in the directory so that dlopen() finds the library.
180
void changedir_on_mac() {
181
#ifdef __APPLE__
182
	chdir(get_executable_directory().c_str());
183
#endif
184
}
7828.1.1 by Holger Rapp
- Remove --remove-replays and --remove-syncstreams. We now always delete them if they were autogenerated and older than 4 weeks.
185
8400.1.13 by tiborb95 at gmail
code polis, training
186
// Extracts a long from 'text' into 'val' returning true if all of the string
187
// was valid. If not, the content of 'val' is undefined.
9436 by The Widelands Bunnybot
Move 32-bit MS-Windows integration for PRs to the action (#4098)
188
bool to_long(const std::string& text, int64_t* val) {
8400.1.14 by tiborb95 at gmail
review comments incorporated
189
	const char* start = text.c_str();
190
	char* end;
191
	*val = strtol(start, &end, 10);
192
	return *end == '\0';
8400.1.13 by tiborb95 at gmail
code polis, training
193
}
7828.1.1 by Holger Rapp
- Remove --remove-replays and --remove-syncstreams. We now always delete them if they were autogenerated and older than 4 weeks.
194
195
// Extracts the creation date from 'path' which is expected to
196
// match "YYYY-MM-DD*". Returns false if no date could be extracted.
197
bool extract_creation_day(const std::string& path, tm* tfile) {
198
	const std::string filename = FileSystem::fs_filename(path.c_str());
199
	memset(tfile, 0, sizeof(tm));
200
10194 by The Widelands Bunnybot
Fix misc clang-tidy checks in remaining files (#5289)
201
	int64_t day;
202
	int64_t month;
203
	int64_t year;
7828.1.1 by Holger Rapp
- Remove --remove-replays and --remove-syncstreams. We now always delete them if they were autogenerated and older than 4 weeks.
204
	if (!to_long(filename.substr(8, 2), &day)) {
205
		return false;
206
	}
207
	if (!to_long(filename.substr(5, 2), &month)) {
208
		return false;
209
	}
210
	if (!to_long(filename.substr(0, 4), &year)) {
211
		return false;
212
	}
213
214
	tfile->tm_mday = day;
215
	tfile->tm_mon = month - 1;
216
	tfile->tm_year = year - 1900;
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
217
	return tfile != nullptr;
7828.1.1 by Holger Rapp
- Remove --remove-replays and --remove-syncstreams. We now always delete them if they were autogenerated and older than 4 weeks.
218
}
219
8895.5.2 by artydent
compliance to style guide
220
// Returns true if 'filename' was autogenerated, i.e. if 'extract_creation_day'
221
// can return a date and it is old enough to be deleted.
10473 by The Widelands Bunnybot
Replays: Single-File, Optional Writing, Autodeleting (#5645)
222
bool is_autogenerated_and_expired(const std::string& filename, const double keep_time) {
7828.1.1 by Holger Rapp
- Remove --remove-replays and --remove-syncstreams. We now always delete them if they were autogenerated and older than 4 weeks.
223
	tm tfile;
224
	if (!extract_creation_day(filename, &tfile)) {
225
		return false;
226
	}
8400.1.7 by tiborb95 at gmail
changes mainly in regard to wells
227
	return std::difftime(time(nullptr), mktime(&tfile)) > keep_time;
7828.1.1 by Holger Rapp
- Remove --remove-replays and --remove-syncstreams. We now always delete them if they were autogenerated and older than 4 weeks.
228
}
229
9971 by The Widelands Bunnybot
Improved exception reporting (#5003)
230
// A simple wrapper around the game logic thread. It ensures the thread is
231
// always joined when this class goes out of scope. This is important when an
232
// exception is thrown within the game anywhere, because without this, we will
233
// not join the thread and this means the exception will never be caught and
234
// printed, making debugging hard.
235
// See
236
// https://stackoverflow.com/questions/25397874/deleting-stdthread-pointer-raises-exception-libcabi-dylib-terminating
237
// TODO(klaus-halfman/Noordfrees): move this to base/multithreading.h as generic concept.
238
class GameLogicThread {
239
public:
10070 by The Widelands Bunnybot
Resolve thread sanitizer issues (#5114)
240
	explicit GameLogicThread(std::atomic_bool* should_die)
9971 by The Widelands Bunnybot
Improved exception reporting (#5003)
241
	   : should_die_(should_die), thread_(&UI::Panel::logic_thread) {
242
	}
243
244
	DISALLOW_COPY_AND_ASSIGN(GameLogicThread);
245
246
	~GameLogicThread() {
247
		*should_die_ = true;
248
		thread_.join();
249
	}
250
251
private:
10070 by The Widelands Bunnybot
Resolve thread sanitizer issues (#5114)
252
	std::atomic_bool* should_die_;  // signals using object that thread is dead.
9971 by The Widelands Bunnybot
Improved exception reporting (#5003)
253
	std::thread thread_;
254
};
255
7025 by Holger Rapp
Remove untested and unused military configuration (retreat options).
256
}  // namespace
257
10738 by The Widelands Bunnybot
Self-diagnose crashes (#6100)
258
std::string WLApplication::segfault_backtrace_dir;
259
8816 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/windows-logging:
260
// Set up the homedir. Exit 1 if the homedir is illegal or the logger couldn't be initialized for
261
// Windows.
9190.1.2 by GunChleoc
Fix compiler warning in read/write config.
262
// Also sets the config directory. This defaults to $XDG_CONFIG_HOME/widelands/config on Unix.
263
// Defaults to homedir/config everywhere else, if homedir is set manually or if
264
// built without XDG-support.
4121 by dwarik
'home directory' (place for savegames e.d.) is now handled seperately
265
void WLApplication::setup_homedir() {
9105 by GunChleoc
Fixed logging for homedir.
266
	// Check if we have a command line override
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
267
	if (commandline_.count("homedir") != 0u) {
9105 by GunChleoc
Fixed logging for homedir.
268
		// We don't have a destination dir for the logger yet
269
		std::cout << "Adding home directory: " << commandline_["homedir"].c_str() << std::endl;
270
		homedir_ = commandline_["homedir"];
8729.1.23 by Lucki
Merge branch master
271
#ifdef USE_XDG
272
		// This commandline option should probably also affect the
273
		// configuration file.
274
		userconfigdir_ = commandline_["homedir"];
275
#endif
9105 by GunChleoc
Fixed logging for homedir.
276
		commandline_.erase("homedir");
277
	}
278
279
#ifdef REDIRECT_OUTPUT
280
	if (!redirect_output())
281
		redirect_output(homedir_);
282
#endif
283
8808.1.1 by GunChleoc
Write Windows stdout.txt to homedir.
284
	// If we don't have a home directory, we exit with an error
285
	if (homedir_.empty()) {
8808.1.2 by GunChleoc
g_fs needs to be initialized before the logger, in case .widelands doesn't exist yet.
286
		std::cout << "Unable to start Widelands, because the given homedir is empty" << std::endl;
8808.1.1 by GunChleoc
Write Windows stdout.txt to homedir.
287
		delete g_fs;
288
		exit(1);
289
	} else {
8808.1.2 by GunChleoc
g_fs needs to be initialized before the logger, in case .widelands doesn't exist yet.
290
		try {
291
			std::unique_ptr<FileSystem> home(new RealFSImpl(homedir_));
292
			home->ensure_directory_exists(".");
293
			g_fs->set_home_file_system(home.release());
294
		} catch (const std::exception& e) {
8816 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/windows-logging:
295
			std::cout
296
			   << "Unable to start Widelands, because we were unable to add the home directory: "
297
			   << e.what() << std::endl;
8808.1.2 by GunChleoc
g_fs needs to be initialized before the logger, in case .widelands doesn't exist yet.
298
			delete g_fs;
299
			exit(1);
300
		}
8808.1.1 by GunChleoc
Write Windows stdout.txt to homedir.
301
#ifdef _WIN32
302
		// Initialize the logger for Windows. Exit on failure.
303
		if (!set_logging_dir(homedir_)) {
8808.1.2 by GunChleoc
g_fs needs to be initialized before the logger, in case .widelands doesn't exist yet.
304
			delete g_fs;
8808.1.1 by GunChleoc
Write Windows stdout.txt to homedir.
305
			exit(1);
306
		}
307
#endif
9105 by GunChleoc
Fixed logging for homedir.
308
		// Homedir is ready, so we can log normally from now on
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
309
		log_info("Set home directory: %s\n", homedir_.c_str());
9496 by The Widelands Bunnybot
Only show .wgf files in load/save menu (#4192)
310
311
		// Create directory structure
312
		g_fs->ensure_directory_exists("save");
313
		g_fs->ensure_directory_exists("replays");
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
314
		g_fs->ensure_directory_exists(kMyMapsDirFull);
315
		g_fs->ensure_directory_exists(kDownloadedMapsDirFull);
10738 by The Widelands Bunnybot
Self-diagnose crashes (#6100)
316
317
		g_fs->ensure_directory_exists(kCrashDir);
318
		segfault_backtrace_dir = homedir_;
319
		segfault_backtrace_dir += "/";
320
		segfault_backtrace_dir += kCrashDir;
1744 by bedouin
- move setup_searchpaths() and getexename() into WLApplication
321
	}
9190.1.2 by GunChleoc
Fix compiler warning in read/write config.
322
323
#ifdef USE_XDG
9199 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/compiler-warnings-201908-2:
324
	set_config_directory(userconfigdir_);
9190.1.2 by GunChleoc
Fix compiler warning in read/write config.
325
#else
9199 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/compiler-warnings-201908-2:
326
	set_config_directory(homedir_);
9190.1.2 by GunChleoc
Fix compiler warning in read/write config.
327
#endif
9682 by The Widelands Bunnybot
Add-Ons (#4464)
328
329
	i18n::set_homedir(homedir_);
1744 by bedouin
- move setup_searchpaths() and getexename() into WLApplication
330
}
331
1177 by bedouin
- WLApplication patch #6/12
332
/**
1176 by bedouin
- WLApplication patch #5/12
333
 * The main entry point for the WLApplication singleton.
334
 *
335
 * Regardless of circumstances, this will return the one and only valid
2917 by sigra
Fix errors found by [http://websvn.kde.org/trunk/quality/krazy2/plugins/general/spelling]. We could just run that script once in a while and submit our own errors for inclusion. Then we do not have to maintain our own version.
336
 * WLApplication object when called. If necessary, a new WLApplication instance
1176 by bedouin
- WLApplication patch #5/12
337
 * is created.
338
 *
1181 by bedouin
- WLApplication path #11/12
339
 * While you \e can do the first call to this method without parameters, it does
340
 * not make much sense.
1176 by bedouin
- WLApplication patch #5/12
341
 *
342
 * \param argc The number of command line arguments
343
 * \param argv Array of command line arguments
10611 by The Widelands Bunnybot
'src/ui_basic/panel.cc' was automatically formatted.
344
 * \return A reference to the WLApplication singleton
1176 by bedouin
- WLApplication patch #5/12
345
 */
10611 by The Widelands Bunnybot
'src/ui_basic/panel.cc' was automatically formatted.
346
WLApplication& WLApplication::get(int const argc, char const** argv) {
347
	static WLApplication the_singleton{argc, argv};
1176 by bedouin
- WLApplication patch #5/12
348
	return the_singleton;
349
}
350
351
/**
352
 * Initialize an instance of WLApplication.
353
 *
9204 by The Widelands Bunnybot
Noordfrees: Launchpad mirror (#3766)\n\nMirrors all changes at widelands:master to lp:widelands (1d6b62c7619a182081e1c942ae533a95d6112044)
354
 * Exits with code 2 if the SDL/TTF system is not available.
355
 *
1176 by bedouin
- WLApplication patch #5/12
356
 * This constructor is protected \e on \e purpose !
2617 by bedouin
- extract method parse_commandline
357
 * Use WLApplication::get() instead and look at the class description.
1181 by bedouin
- WLApplication path #11/12
358
 *
3943 by bedouin
Shorten many long lines
359
 * For easier access, we repackage argc/argv into an STL map here.
360
 * If you specify the same option more than once, only the last occurrence
361
 * is effective.
1176 by bedouin
- WLApplication patch #5/12
362
 *
1175 by bedouin
- WLApplication patch #4/12:
363
 * \param argc The number of command line arguments
364
 * \param argv Array of command line arguments
365
 */
8048 by GunChleoc
Ran clang-format.
366
WLApplication::WLApplication(int const argc, char const* const* const argv)
10465 by The Widelands Bunnybot
Create .clang-tidy config file and sanitize headers (#5681)
367
   :
6640 by Holger Rapp
Use _WIN32 everywhere to check for windows compilation.
368
#ifdef _WIN32
10465 by The Widelands Bunnybot
Create .clang-tidy config file and sanitize headers (#5681)
369
     homedir_(FileSystem::get_homedir() + "\\.widelands")
8729.1.14 by Lucki
Resolve -Wundef warning
370
#elif defined USE_XDG
8729.1.1 by Lucki
Add basic XDG support.
371
     // To enable backwards compatibility, the program name is passed with the
372
     // path.
8729.1.11 by Lucki
Support $XDG_CONFIG_HOME
373
     homedir_(FileSystem::get_userdatadir()),
10465 by The Widelands Bunnybot
Create .clang-tidy config file and sanitize headers (#5681)
374
     userconfigdir_(FileSystem::get_userconfigdir())
6299 by Tino
path seperator \\ on windows
375
#else
10465 by The Widelands Bunnybot
Create .clang-tidy config file and sanitize headers (#5681)
376
     homedir_(FileSystem::get_homedir() + "/.widelands")
6299 by Tino
path seperator \\ on windows
377
#endif
10465 by The Widelands Bunnybot
Create .clang-tidy config file and sanitize headers (#5681)
378
{
3697 by sigra
General cleanups:
379
	g_fs = new LayeredFileSystem();
2617 by bedouin
- extract method parse_commandline
380
8048 by GunChleoc
Ran clang-format.
381
	parse_commandline(argc, argv);  // throws ParameterError, handled by main.cc
5470 by Nasenbaer
Fix commandline parameter "homedir" and "datadir" parsing - thanks go to Stefan Karpinski for the patch
382
4121 by dwarik
'home directory' (place for savegames e.d.) is now handled seperately
383
	setup_homedir();
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
384
385
	init_settings();  // Also sets up the filesystems and language support.
7193.1.1 by Holger Rapp
Remove setup_searchpaths and only search --datadir and the files configured through WL_INSTALL_*
386
9921 by The Widelands Bunnybot
Multithreading (#4319)
387
	set_initializer_thread();
388
10612 by The Widelands Bunnybot
Make Main Menu Dropdown Entries a Bigger Click Target (#5902)
389
#ifdef SIGUSR1
390
	signal(SIGUSR1, toggle_verbose);
391
#endif
392
7296 by Holger Rapp
Emergency fix: Repair mac os X nightlies.
393
	changedir_on_mac();
5840.1.1 by Nasenbaer
No GUI until start...
394
10039 by The Widelands Bunnybot
Fix Clang 13 Warnings (#5088)
395
#ifndef SDL_BYTEORDER
396
	log_info("Byte order: unknown, assuming little-endian\n");
397
#elif SDL_BYTEORDER == SDL_LIL_ENDIAN
9827 by The Widelands Bunnybot
Clean up superfluous log output (#4755)
398
	log_info("Byte order: little-endian\n");
9288 by The Widelands Bunnybot
Print endianness on startup
399
#else
9827 by The Widelands Bunnybot
Clean up superfluous log output (#4755)
400
	log_info("Byte order: big-endian\n");
9288 by The Widelands Bunnybot
Print endianness on startup
401
#endif
402
7839.10.2 by fios at foramnagaidhlig
Fixed the code. Also, removed a bit of dead code.
403
	// Start the SDL core
9204 by The Widelands Bunnybot
Noordfrees: Launchpad mirror (#3766)\n\nMirrors all changes at widelands:master to lp:widelands (1d6b62c7619a182081e1c942ae533a95d6112044)
404
	if (SDL_Init(SDL_INIT_VIDEO) == -1) {
405
		// We sometimes run into a missing video driver in our CI environment, so we exit 0 to prevent
406
		// too frequent failures
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
407
		log_err("Failed to initialize SDL, no valid video driver: %s", SDL_GetError());
9204 by The Widelands Bunnybot
Noordfrees: Launchpad mirror (#3766)\n\nMirrors all changes at widelands:master to lp:widelands (1d6b62c7619a182081e1c942ae533a95d6112044)
408
		exit(2);
409
	}
7692.2.6 by Holger Rapp
Further reduced OpenGL state calls and display preload update messages.
410
10997 by The Widelands Bunnybot
Show splash screen earlier and reintroduce intro music (GH #6412 / CB #4773)
411
	// Start intro music before splashscreen: it takes slightly less time,
412
	// and the music starts with some delay
413
	g_sh = new SoundHandler();
414
	g_sh->register_songs("music", Songset::kIntro);
415
	g_sh->register_songs("music", Songset::kMenu);
416
	g_sh->change_music(get_config_bool("play_intro_music", true) ? Songset::kIntro : Songset::kMenu);
417
418
	g_gr = new Graphic();
419
	g_gr->initialize(
420
	   get_config_bool("debug_gl_trace", false) ? Graphic::TraceGl::kYes : Graphic::TraceGl::kNo,
11198 by The Widelands Bunnybot
Add display selection to graphics options (GH #6342 / CB #4705)
421
	   get_config_int("display", -1), get_config_int("xres", kDefaultResolutionW),
422
	   get_config_int("yres", kDefaultResolutionH), get_config_bool("fullscreen", false),
423
	   get_config_bool("maximized", false));
10997 by The Widelands Bunnybot
Show splash screen earlier and reintroduce intro music (GH #6412 / CB #4773)
424
425
	{
426
		// The window manager may resize the window on creation, so we have to handle resize events
427
		// first to be able to draw the splash screen in the right size. This also creates mousemove
428
		// events that we may mess up when we set the cursor.
429
		// We throw away everything else, hopefully we don't have much yet...
430
		// Window event and mouse cursor handling needs g_gr.
431
432
		SDL_PumpEvents();
433
434
		// Known harmless events we'd drop anyway
435
		SDL_FlushEvent(SDL_AUDIODEVICEADDED);
436
		SDL_FlushEvent(SDL_TEXTEDITING);  // reported on windows
437
		// end of ignored events
438
439
		SDL_Event ev;
440
		int ignored = 0;
441
		int handled = 0;
442
443
		while (SDL_PollEvent(&ev) != 0) {
444
			if (ev.type == SDL_WINDOWEVENT) {
445
				handle_window_event(ev);
446
				++handled;
447
			} else if (ev.type == SDL_MOUSEMOTION) {
448
				mouse_position_ = Vector2i(ev.motion.x, ev.motion.y);
449
			} else {
450
				verb_log_dbg("Ignoring SDL event 0x%04x", ev.type);
451
				++ignored;
452
			}
453
		}
454
		if (ignored > 0) {
455
			log_warn("Ignored %d non-mousemove SDL events at start up", ignored);
456
		}
457
		if (handled > 0) {
458
			// Initial creation already creates some events
459
			verb_log_info("Handled %d SDL window events at start up", handled);
460
		}
461
	}
462
463
	init_mouse_cursor();
464
465
	// Prepare for drawing splash screen
466
467
	/*****
468
	 * These could be moved later if we decide to show some graphic (an hourglass?) instead
469
	 * of the text label in the initial splash screen to draw it faster.
470
	 */
471
	if (TTF_Init() == -1) {
472
		log_err("True Type library did not initialize: %s\n", TTF_GetError());
473
		exit(2);
474
	}
475
476
	UI::g_fh = UI::create_fonthandler(
477
	   g_image_cache, i18n::get_locale());  // This will create the fontset, so loading it first.
478
	verb_log_info("Font handler created");
479
480
	set_template_dir("");
481
	verb_log_info("Loaded default styles");
482
	/*
483
	 * End of text rendering dependencies
484
	 *****/
485
486
	// The initital splash screen is only drawn once, it doesn't get updates until the main menu
487
	// overrides it. Normally it shouldn't take more than a few seconds.
488
	RenderTarget* r = g_gr->get_render_target();
489
	draw_splashscreen(*r, _("Loading…"), 1.0f);
490
	g_gr->refresh();
491
	verb_log_info("Splash screen shown");
492
493
	// This was taken out of Graphic::initialize() to allow showing the splashscreen earlier.
494
	// This is one of the slowest parts of the start up.
495
	g_gr->rebuild_texture_atlas();
496
10305 by The Widelands Bunnybot
Workaround for inverted horizontal scrolling bug in SDL (#5394)
497
	// Try to detect configurations with inverted horizontal scroll
10997 by The Widelands Bunnybot
Show splash screen earlier and reintroduce intro music (GH #6412 / CB #4773)
498
	SDL_version sdl_ver = {SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL};
499
	SDL_GetVersion(&sdl_ver);
10305 by The Widelands Bunnybot
Workaround for inverted horizontal scrolling bug in SDL (#5394)
500
	const char* sdl_video = SDL_GetCurrentVideoDriver();
501
	assert(sdl_video != nullptr);
502
	bool sdl_scroll_x_bug = false;
503
504
	// SDL version < 2.0 is not supported, >= 2.1 will have the changes
505
	if (sdl_ver.major == 2 && sdl_ver.minor == 0) {
506
		if (std::strcmp(sdl_video, "x11") == 0) {
507
			sdl_scroll_x_bug = sdl_ver.patch < 18;
508
		} else if (std::strcmp(sdl_video, "wayland") == 0) {
509
			sdl_scroll_x_bug = sdl_ver.patch < 20;
510
		}
511
	}
512
	if (sdl_scroll_x_bug) {
513
		log_info("Inverting horizontal mousewheel scrolling for SDL %d.%d.%d with %s\n",
514
		         sdl_ver.major, sdl_ver.minor, sdl_ver.patch, sdl_video);
515
		set_mousewheel_option_bool(MousewheelOptionID::kInvertedXDetected, true);
516
		update_mousewheel_settings();
517
	}
518
10997 by The Widelands Bunnybot
Show splash screen earlier and reintroduce intro music (GH #6412 / CB #4773)
519
	// Keep cursor in window while dragging
520
	SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1");
521
522
	verb_log_info("Cleaning up temporary files");
523
	cleanup_replays();
524
	cleanup_ai_files();
525
	cleanup_temp_files();
526
	cleanup_temp_backups();
527
528
	verb_log_info("Loading songsets");
10087 by The Widelands Bunnybot
Enable custom in-game music (#5138)
529
	g_sh->register_songs("music", Songset::kIngame);
530
	g_sh->register_songs("music", Songset::kCustom);
9015.2.31 by GunChleoc
Make SoundHandler Widelands-agnostic.
531
10752 by The Widelands Bunnybot
Further enhancements for ship construction (#6129)
532
	UI::ColorChooser::read_favorites_settings();
533
10997 by The Widelands Bunnybot
Show splash screen earlier and reintroduce intro music (GH #6412 / CB #4773)
534
	verb_log_info("Initializing Add-Ons");
9755 by The Widelands Bunnybot
Fix statistics string cache (#4653)
535
	initialize_g_addons();
10997 by The Widelands Bunnybot
Show splash screen earlier and reintroduce intro music (GH #6412 / CB #4773)
536
	verb_log_info("Done initializing Add-Ons");
9682 by The Widelands Bunnybot
Add-Ons (#4464)
537
9015.2.44 by GunChleoc
Tweaked 2 comments
538
	// Register the click sound for UI::Panel.
9068 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/cleanup-soundhandler:
539
	// We do it here to ensure that the sound handler has been created first, and we only want to
540
	// register it once.
9015.2.38 by GunChleoc
Reference sounds by numbered rather than string IDs.
541
	UI::Panel::register_click();
9015.2.31 by GunChleoc
Make SoundHandler Widelands-agnostic.
542
7839.10.2 by fios at foramnagaidhlig
Fixed the code. Also, removed a bit of dead code.
543
	// Make sure we didn't forget to read any global option
8729.1.25 by Lucki
Refactor g_options
544
	check_config_used();
9922 by The Widelands Bunnybot
Write config after sound initialization (#4940)
545
546
	// Save configuration now. Otherwise, the UUID and sound options
547
	// are not saved, when the game crashes
548
	write_config();
10744 by The Widelands Bunnybot
'src/ui_fsmenu/main.cc' was automatically formatted.
549
550
	if (get_config_bool("save_chat_history", false)) {
551
		g_chat_sent_history.load(kChatSentHistoryFile);
552
	}
553
	if (g_allow_script_console) {
554
		log_info("Developer tools are enabled.");
555
		g_script_console_history.load(kScriptConsoleHistoryFile);
556
	}
10997 by The Widelands Bunnybot
Show splash screen earlier and reintroduce intro music (GH #6412 / CB #4773)
557
558
	verb_log_info("WLApplication created");
1185 by bedouin
- fold WLApplication init/shutdown int ctor/dtor
559
}
560
561
/**
562
 * Shut down all subsystems in an orderly manner
563
 */
7125.1.2 by fios at foramnagaidhlig
Made sure TODO-comments don't show up in documentation
564
// TODO(unknown): Handle errors that happen here!
8048 by GunChleoc
Ran clang-format.
565
WLApplication::~WLApplication() {
7839.10.2 by fios at foramnagaidhlig
Fixed the code. Also, removed a bit of dead code.
566
	// Do use the opposite order of WLApplication::init()
1185 by bedouin
- fold WLApplication init/shutdown int ctor/dtor
567
9522 by The Widelands Bunnybot
Map preview on selection screen (#4201)
568
	if (!g_gr->fullscreen() && !g_gr->maximized()) {
569
		set_config_int("xres", g_gr->get_xres());
570
		set_config_int("yres", g_gr->get_yres());
571
	}
572
	set_config_bool("maximized", g_gr->maximized());
573
1185 by bedouin
- fold WLApplication init/shutdown int ctor/dtor
574
	shutdown_hardware();
575
	shutdown_settings();
576
10744 by The Widelands Bunnybot
'src/ui_fsmenu/main.cc' was automatically formatted.
577
	if (get_config_bool("save_chat_history", false)) {
578
		g_chat_sent_history.save(kChatSentHistoryFile);
579
	}
580
	if (g_allow_script_console) {
581
		g_script_console_history.save(kScriptConsoleHistoryFile);
582
	}
583
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
584
	// To be proper, release our textdomain
585
	i18n::release_textdomain();
586
8710.4.4 by GunChleoc
Renamed font_handler1 to font_handler
587
	assert(UI::g_fh);
588
	delete UI::g_fh;
589
	UI::g_fh = nullptr;
6405.1.23 by Holger Rapp
Reenabled new rich text renderer. Still crashes the game though
590
8048 by GunChleoc
Ran clang-format.
591
	TTF_Quit();  // TODO(unknown): not here
6405.1.26 by Holger Rapp
Removed some debug output. Moved TTF initialization into wlapplication (temporary). Reordered some class definitions
592
9633 by The Widelands Bunnybot
Clear readability-delete-null-pointer (#4452)
593
	delete g_fs;
6838 by Holger Rapp
Add override in functions that are overridden (c++11 feature)
594
	g_fs = nullptr;
5502 by Jari Hautio
Implemented support for redirecting stdio from widelands to files. Redirection is enabled if REDIRECT_STDIO is defined at compile time (enabled for MSVC builds). This allows windows version to write logs to home folder if executable folder is not writable (program files folder under Vista nd Win7). Fixes bug #625979.
595
8048 by GunChleoc
Ran clang-format.
596
	if (redirected_stdio_) {
5502 by Jari Hautio
Implemented support for redirecting stdio from widelands to files. Redirection is enabled if REDIRECT_STDIO is defined at compile time (enabled for MSVC builds). This allows windows version to write logs to home folder if executable folder is not writable (program files folder under Vista nd Win7). Fixes bug #625979.
597
		std::cout.flush();
598
		fclose(stdout);
599
		std::cerr.flush();
600
		fclose(stderr);
601
	}
6512.2.2 by Andras Eisenberger
Small fixes
602
603
	SDL_Quit();
1181 by bedouin
- WLApplication path #11/12
604
}
1175 by bedouin
- WLApplication patch #4/12:
605
10997 by The Widelands Bunnybot
Show splash screen earlier and reintroduce intro music (GH #6412 / CB #4773)
606
void WLApplication::init_mouse_cursor() {
607
	// Fix mouse_position_ initialisation when we don't have mousemove events at startup.
608
	// This is actually only needed by soft mode, but we do it for SDL mode too to make the
609
	// cursor appear at the right position if the user has to use the keyboard to turn SDL
610
	// mode off.
611
	if (mouse_position_ == Vector2i::zero()) {
612
		// Initialize the mouse position to the current one.
613
		// Unfortunately we have to do it the hard way, because SDL_GetMouseState() doesn't work
614
		// right until we had a mousemove event.
615
		int mouse_global_x;
616
		int mouse_global_y;
617
		int window_x;
618
		int window_y;
619
		SDL_Window* sdl_window = g_gr->get_sdlwindow();
620
		SDL_GetWindowPosition(sdl_window, &window_x, &window_y);
621
		SDL_GetGlobalMouseState(&mouse_global_x, &mouse_global_y);
622
		mouse_position_.x = mouse_global_x - window_x;
623
		mouse_position_.y = mouse_global_y - window_y;
624
625
		// Fix SDL's internal notion of the relative cursor position too by generating some motion
626
		// events. Must be done before g_mouse_cursor->initialize().
627
		// TODO(tothxa): I don't know why, but all these steps seem to be necessary on my system to
628
		//               fix the case in soft mode when the mouse is first moved while it is hidden.
629
		//               Without these, it is resumed at the position where it was hidden.
630
		SDL_PumpEvents();
631
		SDL_WarpMouseInWindow(sdl_window, mouse_position_.x - 1, mouse_position_.y - 1);
632
		SDL_PumpEvents();
633
		SDL_Delay(2);  // 1 tick doesn't work
634
		SDL_WarpMouseInWindow(sdl_window, mouse_position_.x, mouse_position_.y);
635
		SDL_PumpEvents();
636
	}
637
638
	if (!get_config_bool("sdl_cursor", true)) {
639
		// Set system's "waiting" mouse cursor in case setting our own cursor in
640
		// g_mouse_cursor->initialize() fails. Maybe it works, maybe not.
641
		SDL_Cursor* tmp_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT);
642
		SDL_SetCursor(tmp_cursor);
643
		SDL_FreeCursor(tmp_cursor);
644
	}
645
646
	// The cursor initialization itself
647
	// We always init it in SDL mode to have a chance of a working cursor in the splash screen,
648
	// before we start refreshing the screen ourselves.
649
	// TODO(tothxa): May not work if the system doesn't support color cursors? What happens then?
650
	//               No cursor, default system cursor or error?
651
	//               Remove argument if this works out. And move initialize() into the constructor?
652
	g_mouse_cursor = new MouseCursor();
653
	g_mouse_cursor->initialize(true);
654
655
	// TODO(tothxa): Do this in g_mouse_cursor->initialize() or the constructor too?
656
	g_mouse_cursor->change_wait(true);
657
}
658
9755 by The Widelands Bunnybot
Fix statistics string cache (#4653)
659
void WLApplication::initialize_g_addons() {
11111 by The Widelands Bunnybot
Keyboard shortcuts for add-ons (CB #4889 / GH #6528)
660
	init_plugin_shortcuts();
661
9755 by The Widelands Bunnybot
Fix statistics string cache (#4653)
662
	AddOns::g_addons.clear();
663
	if (g_fs->is_directory(kAddOnDir)) {
664
		std::set<std::string> found;
665
		for (std::string desired_addons = get_config_string("addons", ""); !desired_addons.empty();) {
666
			const size_t commapos = desired_addons.find(',');
667
			const std::string substring = desired_addons.substr(0, commapos);
668
			const size_t colonpos = desired_addons.find(':');
669
			if (colonpos == std::string::npos) {
670
				log_warn("Ignoring malformed add-ons config substring '%s'\n", substring.c_str());
671
			} else {
672
				const std::string name = substring.substr(0, colonpos);
673
				if (name.find(kAddOnExtension) != name.length() - kAddOnExtension.length()) {
674
					log_warn("Not loading add-on '%s' (wrong file name extension)\n", name.c_str());
675
				} else {
676
					std::string path(kAddOnDir);
677
					path += FileSystem::file_separator();
678
					path += name;
679
					if (g_fs->file_exists(path)) {
9869 by The Widelands Bunnybot
Skip preloading invalid add-ons (#4840)
680
						try {
681
							found.insert(name);
10194 by The Widelands Bunnybot
Fix misc clang-tidy checks in remaining files (#5289)
682
							AddOns::g_addons.emplace_back(
683
							   AddOns::preload_addon(name), substring.substr(colonpos) == ":true");
9869 by The Widelands Bunnybot
Skip preloading invalid add-ons (#4840)
684
						} catch (const std::exception& e) {
685
							log_warn("Not loading add-on '%s' (%s)", name.c_str(), e.what());
686
						}
9755 by The Widelands Bunnybot
Fix statistics string cache (#4653)
687
					} else {
688
						log_warn("Not loading add-on '%s' (not found)\n", name.c_str());
689
					}
690
				}
691
			}
692
			if (commapos == std::string::npos) {
693
				break;
694
			}
695
			desired_addons = desired_addons.substr(commapos + 1);
696
		}
697
		for (const std::string& name : g_fs->list_directory(kAddOnDir)) {
698
			std::string addon_name(FileSystem::fs_filename(name.c_str()));
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
699
			if ((found.count(addon_name) == 0u) &&
9755 by The Widelands Bunnybot
Fix statistics string cache (#4653)
700
			    addon_name.find(kAddOnExtension) == addon_name.length() - kAddOnExtension.length()) {
9869 by The Widelands Bunnybot
Skip preloading invalid add-ons (#4840)
701
				try {
10194 by The Widelands Bunnybot
Fix misc clang-tidy checks in remaining files (#5289)
702
					AddOns::g_addons.emplace_back(AddOns::preload_addon(addon_name), false);
9869 by The Widelands Bunnybot
Skip preloading invalid add-ons (#4840)
703
				} catch (const std::exception& e) {
704
					log_warn("Not loading add-on '%s' (%s)", addon_name.c_str(), e.what());
705
				}
9755 by The Widelands Bunnybot
Fix statistics string cache (#4653)
706
			}
707
		}
708
	}
10525 by The Widelands Bunnybot
Make richtext.lua styleable and allow partial theme addons (#5748)
709
	try {
710
		AddOns::update_ui_theme(AddOns::UpdateThemeAction::kLoadFromConfig);
711
	} catch (const std::exception& e) {
712
		log_err("Failed to load add-on theme: %s", e.what());
713
	}
9755 by The Widelands Bunnybot
Fix statistics string cache (#4653)
714
}
715
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
716
static void init_one_player_from_template(unsigned p,
9916 by The Widelands Bunnybot
6 files were automatically formatted.
717
                                          bool human,
718
                                          std::unique_ptr<GameSettingsProvider>& settings,
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
719
                                          Section& player_section,
720
                                          const Widelands::Map& map) {
9916 by The Widelands Bunnybot
6 files were automatically formatted.
721
	if (player_section.get_bool("closed", false)) {
722
		if (human) {
723
			throw wexception("Cannot close interactive player slot.");
724
		}
725
		settings->set_player_state(p, PlayerSettings::State::kClosed);
726
		return;  // No need to configure closed player
10194 by The Widelands Bunnybot
Fix misc clang-tidy checks in remaining files (#5289)
727
	}
728
	if (human) {
9916 by The Widelands Bunnybot
6 files were automatically formatted.
729
		settings->set_player_state(p, PlayerSettings::State::kHuman);
730
	} else {
731
		std::string ai = player_section.get_string("ai", "normal");
732
		bool random = ai == "random";
733
		settings->set_player_ai(p, ai, random);
734
		settings->set_player_state(p, PlayerSettings::State::kComputer);
735
	}
736
737
	settings->set_player_team(p, player_section.get_natural("team", 0));
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
738
	if (player_section.has_val("playercolor")) {
739
		std::string colorstr = player_section.get_safe_string("playercolor");
740
		char* color;
741
		RGBColor result;
742
		result.r = std::strtol(colorstr.c_str(), &color, 10);
743
		++color;
744
		result.g = std::strtol(color, &color, 10);
745
		++color;
746
		result.b = std::strtol(color, &color, 10);
9916 by The Widelands Bunnybot
6 files were automatically formatted.
747
		settings->set_player_color(p, result);
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
748
	} else {
9916 by The Widelands Bunnybot
6 files were automatically formatted.
749
		settings->set_player_color(p, kPlayerColors[p]);
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
750
	}
751
752
	std::string tribe =
753
	   player_section.get_string("tribe", map.get_scenario_player_tribe(p + 1).c_str());
9916 by The Widelands Bunnybot
6 files were automatically formatted.
754
	settings->set_player_tribe(p, tribe, tribe.empty());
755
	tribe = settings->settings().players[p].tribe;
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
756
757
	const std::string& init_script_name = player_section.get_string("init", "headquarters.lua");
758
	std::string addon;
759
	if (FileSystem::filename_ext(init_script_name) == kAddOnExtension) {
760
		addon = kAddOnDir;
761
		addon += FileSystem::file_separator();
762
		addon += init_script_name;
763
		addon += FileSystem::file_separator();
764
		addon += tribe;
765
		addon += ".lua";
766
	}
767
	bool found_init = false;
9916 by The Widelands Bunnybot
6 files were automatically formatted.
768
	const Widelands::TribeBasicInfo t = settings->settings().get_tribeinfo(tribe);
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
769
	for (unsigned i = 0; i < t.initializations.size(); ++i) {
770
		if (addon.empty() ?
11093 by The Widelands Bunnybot
170 files were automatically formatted.
771
		       init_script_name == FileSystem::fs_filename(t.initializations[i].script.c_str()) :
772
		       addon == t.initializations[i].script) {
9916 by The Widelands Bunnybot
6 files were automatically formatted.
773
			settings->set_player_init(p, i);
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
774
			found_init = true;
775
			break;
776
		}
777
	}
778
	if (!found_init) {
779
		throw wexception(
11142 by The Widelands Bunnybot
Compiler fixes for clang-19 (GH #6546 / CB #4907)
780
		   "Invalid starting condition '%s' for player %u", init_script_name.c_str(), p + 1);
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
781
	}
782
}
783
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
784
void WLApplication::init_and_run_game_from_template(FsMenu::MainMenu& mainmenu) {
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
785
	AddOns::AddOnsGuard ag;
786
787
	Profile profile(filename_.c_str());
788
	Section& section = profile.get_safe_section("global");
9916 by The Widelands Bunnybot
6 files were automatically formatted.
789
	const bool multiplayer = section.get_bool("multiplayer", false);
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
790
791
	std::vector<AddOns::AddOnState> new_g_addons;
792
	for (std::string addons = section.get_string("addons", ""); !addons.empty();) {
793
		const size_t commapos = addons.find(',');
794
		std::string name;
795
		if (commapos == std::string::npos) {
796
			name = addons;
797
			addons = "";
798
		} else {
799
			name = addons.substr(0, commapos);
800
			addons = addons.substr(commapos + 1);
801
		}
802
		bool found = false;
803
		for (const auto& pair : AddOns::g_addons) {
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
804
			if (pair.first->internal_name == name) {
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
805
				found = true;
10194 by The Widelands Bunnybot
Fix misc clang-tidy checks in remaining files (#5289)
806
				new_g_addons.emplace_back(pair.first, true);
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
807
				break;
808
			}
809
		}
810
		if (!found) {
9916 by The Widelands Bunnybot
6 files were automatically formatted.
811
			log_err("Add-on '%s' not found", name.c_str());
812
			return;
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
813
		}
814
	}
815
	AddOns::g_addons = new_g_addons;
816
9916 by The Widelands Bunnybot
6 files were automatically formatted.
817
	const int playernumber = section.get_natural("interactive_player", 1);
818
	if (playernumber == 0 && !multiplayer) {
819
		log_err("interactive_player must be > 0 for singleplayer games.");
820
		return;
821
	}
822
823
	std::unique_ptr<GameSettingsProvider> settings;
10075 by The Widelands Bunnybot
Keep GameController pointer alive for template game (#5128)
824
	std::shared_ptr<GameController> ctrl;
825
	GameHost* host = nullptr;  // will be deleted by ctrl
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
826
	FsMenu::MenuCapsule capsule(mainmenu);
9916 by The Widelands Bunnybot
6 files were automatically formatted.
827
	if (multiplayer) {
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
828
		host = new GameHost(&capsule, ctrl, get_config_string("nickname", _("nobody")),
10075 by The Widelands Bunnybot
Keep GameController pointer alive for template game (#5128)
829
		                    Widelands::get_all_tribeinfos(nullptr), false);
830
		ctrl.reset(host);
831
		settings.reset(new HostGameSettingsProvider(host));
10103 by The Widelands Bunnybot
Allow using `--script` with `--new_game_from_template` (#5153)
832
		host->set_script_to_run(script_to_run_);
9916 by The Widelands Bunnybot
6 files were automatically formatted.
833
	} else {
834
		settings.reset(new SinglePlayerGameSettingsProvider());
835
	}
836
10589 by The Widelands Bunnybot
Refactor Game Configuration Flags (#5863)
837
	settings->set_flag(GameSettings::Flags::kPeaceful, section.get_bool("peaceful", false));
838
	settings->set_flag(GameSettings::Flags::kFogless, section.get_bool("fogless", false));
839
	settings->set_flag(GameSettings::Flags::kCustomStartingPositions,
840
	                   section.get_bool("custom_starting_positions", false));
841
	settings->set_flag(
842
	   GameSettings::Flags::kForbidDiplomacy, section.get_bool("forbid_diplomacy", false));
10885 by The Widelands Bunnybot
Correct naval warfare rebasing artifacts (closes CB#4699)
843
	settings->set_flag(
844
	   GameSettings::Flags::kAllowNavalWarfare, section.get_bool("allow_naval_warfare", false));
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
845
846
	{
847
		std::string wc_name = section.get_string("win_condition", "endless_game.lua");
848
		std::string script;
849
		if (FileSystem::filename_ext(wc_name) == kAddOnExtension) {
850
			script = kAddOnDir;
851
			script += FileSystem::file_separator();
852
			script += wc_name;
853
			script += FileSystem::file_separator();
854
			script += "init.lua";
855
		} else {
856
			script = "scripting/win_conditions/";
857
			script += wc_name;
858
		}
9916 by The Widelands Bunnybot
6 files were automatically formatted.
859
		settings->set_win_condition_script(script);
10413 by The Widelands Bunnybot
Show coming and absent soldiers in building soldier list (#5437)
860
		settings->set_win_condition_duration(
861
		   section.get_int("win_condition_duration", Widelands::kDefaultWinConditionDuration));
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
862
	}
863
864
	{
865
		const std::string mapfile = section.get_safe_string("map");
866
		Widelands::Map map;
867
		std::unique_ptr<Widelands::MapLoader> ml = map.get_correct_loader(mapfile);
868
		if (!ml) {
9916 by The Widelands Bunnybot
6 files were automatically formatted.
869
			log_err("Invalid map file '%s'", mapfile.c_str());
870
			return;
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
871
		}
872
		ml->preload_map(true, nullptr);
873
		const int nr_players = map.get_nrplayers();
9916 by The Widelands Bunnybot
6 files were automatically formatted.
874
		settings->set_scenario((map.scenario_types() & Widelands::Map::SP_SCENARIO) != 0);
875
		settings->set_map(map.get_name(), mapfile, map.get_background_theme(), map.get_background(),
876
		                  nr_players, false);
877
		settings->set_player_number(playernumber == 0 ? UserSettings::none() : playernumber - 1);
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
878
		for (int p = 0; p < nr_players; ++p) {
879
			std::string key = "player_";
880
			key += std::to_string(p + 1);
9916 by The Widelands Bunnybot
6 files were automatically formatted.
881
			bool human = p == playernumber - 1;
882
			try {
883
				init_one_player_from_template(
884
				   p, human, settings, profile.pull_section(key.c_str()), map);
885
			} catch (const WException& e) {
886
				log_err("%s", e.what());
887
				return;
888
			}
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
889
		}
890
	}
891
9916 by The Widelands Bunnybot
6 files were automatically formatted.
892
	if (!settings->can_launch()) {
893
		log_err("Inconsistent game setup configuration. Cannot launch.");
894
		return;
895
	}
896
897
	if (multiplayer) {
898
		host->run_direct();
899
		return;
900
	}
901
902
	Widelands::Game game;
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
903
	std::vector<std::string> tipstexts{"general_game", "singleplayer"};
9916 by The Widelands Bunnybot
6 files were automatically formatted.
904
	if (settings->has_players_tribe()) {
905
		tipstexts.push_back(settings->get_players_tribe());
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
906
	}
907
	game.create_loader_ui(
10417 by The Widelands Bunnybot
Fix Clang15 Compiler Warnings (#5629)
908
	   tipstexts, true, settings->settings().map_theme, settings->settings().map_background, true);
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
909
	Notifications::publish(UI::NoteLoadingMessage(_("Preparing game…")));
910
911
	game.set_ibase(new InteractivePlayer(game, get_config_section(), playernumber, false));
912
9923 by The Widelands Bunnybot
Fetched translations and updated catalogs.
913
	game.set_game_controller(std::make_shared<SinglePlayerGameController>(game, true, playernumber));
9916 by The Widelands Bunnybot
6 files were automatically formatted.
914
	game.init_newgame(settings->settings());
10727 by The Widelands Bunnybot
Custom Ship & Warehouse Naming Lists (#6056)
915
916
	auto custom_names = Widelands::read_custom_warehouse_ship_names();
917
	Widelands::Player* player = game.get_safe_player(playernumber);
918
	player->set_shipnames(custom_names.first);
919
	player->set_warehousenames(custom_names.second);
920
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
921
	try {
10409 by The Widelands Bunnybot
Allow loading another replay in replay mode (#5611)
922
		game.run(Widelands::Game::StartGameType::kMap, script_to_run_, "single_player");
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
923
	} catch (const std::exception& e) {
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
924
		emergency_save(&mainmenu, game, e.what());
9788 by The Widelands Bunnybot
Allow starting game from template (#4702)
925
	}
926
}
927
1172 by bedouin
- Move conffile and commandline parsing into WLApplication
928
/**
1173 by bedouin
- WLApplication patch #3/12:
929
 * The main loop. Plain and Simple.
930
 */
7125.1.2 by fios at foramnagaidhlig
Made sure TODO-comments don't show up in documentation
931
// TODO(unknown): Refactor the whole mainloop out of class \ref UI::Panel into here.
932
// In the future: push the first event on the event queue, then keep
933
// dispatching events until it is time to quit.
8048 by GunChleoc
Ran clang-format.
934
void WLApplication::run() {
9971 by The Widelands Bunnybot
Improved exception reporting (#5003)
935
	GameLogicThread game_logic_thread(&should_die_);
9921 by The Widelands Bunnybot
Multithreading (#4319)
936
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
937
	FsMenu::MainMenu menu(game_type_ != GameType::kNone);
938
10997 by The Widelands Bunnybot
Show splash screen earlier and reintroduce intro music (GH #6412 / CB #4773)
939
	// This is actually the last step of initialization, postponed from init_mouse_cursor().
940
	// FsMenu::MainMenu() takes a few seconds and we will only start refreshing the screen
941
	// by the chosen option below.
942
	if (!get_config_bool("sdl_cursor", true)) {
943
		g_mouse_cursor->set_use_sdl(false);
944
	}
945
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
946
	check_crash_reports(menu);
947
948
	switch (game_type_) {
949
	case GameType::kEditor: {
950
		bool success = false;
9593 by The Widelands Bunnybot
Random matches & Editor launching convenience (#4289)
951
		if (filename_.empty()) {
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
952
			success = EditorInteractive::run_editor(&menu, EditorInteractive::Init::kDefault);
9593 by The Widelands Bunnybot
Random matches & Editor launching convenience (#4289)
953
		} else {
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
954
			bool have_filename = true;
955
			if (use_last(filename_)) {
956
				if (std::optional<MapData> map = newest_edited_map(); map.has_value()) {
957
					filename_ = map->filenames.at(0);
958
				} else {
959
					const std::string message = _("Widelands could not find the last edited map.");
960
					log_err("%s\n", message.c_str());
11221 by The Widelands Bunnybot
Tools for saveloading compatibility testing (CB #4859 / GH #6497)
961
					if (g_fail_on_errors) {
962
						abort();
963
					}
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
964
					menu.show_messagebox(_("No Last Edited Map"), message);
965
					have_filename = false;
966
				}
967
			}
968
969
			if (have_filename) {
970
				success = EditorInteractive::run_editor(
971
				   &menu, EditorInteractive::Init::kLoadMapDirectly, filename_, script_to_run_);
972
			}
973
		}
974
975
		if (!success) {
976
			menu.main_loop();
977
		}
978
	} break;
979
980
	case GameType::kReplay:
981
	case GameType::kLoadGame: {
9706 by The Widelands Bunnybot
Allow savegames anywhere (#4515)
982
		Widelands::Game game;
10194 by The Widelands Bunnybot
Fix misc clang-tidy checks in remaining files (#5289)
983
		std::string title;
984
		std::string message;
9706 by The Widelands Bunnybot
Allow savegames anywhere (#4515)
985
		try {
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
986
			bool start_replay = (game_type_ == GameType::kReplay);
987
			if (use_last(filename_)) {
988
				std::optional<SavegameData> data = newest_saved_game_or_replay(start_replay);
989
				if (data.has_value()) {
990
					filename_ = data->filename;
991
				} else {
992
					// Parameters will be reordered by FileNotFoundError::what()
993
					if (start_replay) {
994
						throw FileNotFoundError("--replay", _("No last saved replay."), filename_);
995
					}
996
					throw FileNotFoundError("--loadgame", _("No last saved game."), filename_);
997
				}
998
			}
999
			if (start_replay) {
10409 by The Widelands Bunnybot
Allow loading another replay in replay mode (#5611)
1000
				game.run_replay(filename_, "");
9706 by The Widelands Bunnybot
Allow savegames anywhere (#4515)
1001
			} else {
1002
				game.set_ai_training_mode(get_config_bool("ai_training", false));
1003
				game.run_load_game(filename_, script_to_run_);
1004
			}
1005
		} catch (const FileNotFoundError& e) {
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
1006
			message = format(_("Widelands could not find the file \"%s\"."), filename_.c_str());
9706 by The Widelands Bunnybot
Allow savegames anywhere (#4515)
1007
			message = message + "\n\n" + _("Error message:") + "\n" + e.what();
1008
			title = _("File system error");
8048 by GunChleoc
Ran clang-format.
1009
		} catch (const std::exception& e) {
9703 by The Widelands Bunnybot
Main Menu Redesign, Part 4 (#4518)
1010
			emergency_save(nullptr, game, e.what());
9706 by The Widelands Bunnybot
Allow savegames anywhere (#4515)
1011
			message = e.what();
1012
			title = _("Error message:");
1013
		}
1014
		if (!message.empty()) {
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
1015
			log_err("%s\n", message.c_str());
10677 by The Widelands Bunnybot
Cleanup failed game state before entering menu after game error (#6004)
1016
			game.full_cleanup();
11221 by The Widelands Bunnybot
Tools for saveloading compatibility testing (CB #4859 / GH #6497)
1017
			if (g_fail_on_errors) {
1018
				abort();
1019
			}
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
1020
			menu.show_messagebox(title, message);
1021
			menu.main_loop();
2919 by ixprefect
Eliminate lifetime hocus-pocus surrounding WLApplication::m_game.
1022
		}
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
1023
	} break;
1024
1025
	case GameType::kScenario: {
2919 by ixprefect
Eliminate lifetime hocus-pocus surrounding WLApplication::m_game.
1026
		Widelands::Game game;
1027
		try {
11221 by The Widelands Bunnybot
Tools for saveloading compatibility testing (CB #4859 / GH #6497)
1028
			if (scenario_difficulty_ != Widelands::kScenarioDifficultyNotSet) {
1029
				game.set_scenario_difficulty(scenario_difficulty_);
1030
			}
9923 by The Widelands Bunnybot
Fetched translations and updated catalogs.
1031
			game.run_splayer_scenario_direct({filename_}, script_to_run_);
8048 by GunChleoc
Ran clang-format.
1032
		} catch (const std::exception& e) {
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
1033
			emergency_save(&menu, game, e.what());
2919 by ixprefect
Eliminate lifetime hocus-pocus surrounding WLApplication::m_game.
1034
		}
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
1035
	} break;
1036
1037
	case GameType::kFromTemplate: {
1038
		init_and_run_game_from_template(menu);
1039
	} break;
1040
1041
	default:
1042
		menu.main_loop();
1884 by bedouin
- autoindent run
1043
	}
1873 by sigra
Add a script that detects misuse of tabs in sourcecode. Fix the misuses that it found and do a few more cleanups on those lines.
1044
9015.2.45 by GunChleoc
Renamed g_soundhandler to g_sh for consistency with other global objects.
1045
	g_sh->stop_music(500);
9921 by The Widelands Bunnybot
Multithreading (#4319)
1046
1047
	should_die_ = true;
1173 by bedouin
- WLApplication patch #3/12:
1048
}
1049
1050
/**
1178 by bedouin
- WLApplication patch #7/12
1051
 * Get an event from the SDL queue, just like SDL_PollEvent.
1179 by bedouin
- WLApplication patch #8/12:
1052
 *
1053
 * \param ev the retrieved event will be put here
2616 by bedouin
- fix nearly all doxygen warnings
1054
 *
1055
 * \return true if an event was returned inside ev, false otherwise
1178 by bedouin
- WLApplication patch #7/12
1056
 */
10351 by The Widelands Bunnybot
Use SDL Relative Mouse Mode (#5494)
1057
bool WLApplication::poll_event(SDL_Event& ev) const {
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
1058
	if (SDL_PollEvent(&ev) == 0) {
6869.1.4 by Holger Rapp
Addressed all the FIXMEs.
1059
		return false;
1060
	}
1061
6869.1.3 by Hans Joachim Desserud
Fix codecheck issues. Silly editor, replacing my tabs like that
1062
	// We edit mouse motion events in here, so that
6869.1.4 by Holger Rapp
Addressed all the FIXMEs.
1063
	// differences caused by GrabInput or mouse speed
1064
	// settings are invisible to the rest of the code
6869.1.3 by Hans Joachim Desserud
Fix codecheck issues. Silly editor, replacing my tabs like that
1065
	switch (ev.type) {
1066
	case SDL_MOUSEMOTION:
7737.1.1 by Klaus Halfmann \
Migration from m_... to ..._ mostly in wui
1067
		if (mouse_locked_) {
1068
			ev.motion.x = mouse_position_.x;
1069
			ev.motion.y = mouse_position_.y;
6869.1.3 by Hans Joachim Desserud
Fix codecheck issues. Silly editor, replacing my tabs like that
1070
		}
6869.1.4 by Holger Rapp
Addressed all the FIXMEs.
1071
		break;
1072
9015.2.31 by GunChleoc
Make SoundHandler Widelands-agnostic.
1073
	case SDL_USEREVENT: {
1074
		if (ev.user.code == CHANGE_MUSIC) {
10997 by The Widelands Bunnybot
Show splash screen earlier and reintroduce intro music (GH #6412 / CB #4773)
1075
			/* Notification from the SoundHandler that a song has finished playing.
9015.2.31 by GunChleoc
Make SoundHandler Widelands-agnostic.
1076
			 * Usually, another song from the same songset will be started.
10997 by The Widelands Bunnybot
Show splash screen earlier and reintroduce intro music (GH #6412 / CB #4773)
1077
			 * There is a special case for the intro music: it will only be played once.
9015.2.31 by GunChleoc
Make SoundHandler Widelands-agnostic.
1078
			 */
1079
			assert(!SoundHandler::is_backend_disabled());
10997 by The Widelands Bunnybot
Show splash screen earlier and reintroduce intro music (GH #6412 / CB #4773)
1080
			if (g_sh->current_songset() != Songset::kIntro) {
9015.2.45 by GunChleoc
Renamed g_soundhandler to g_sh for consistency with other global objects.
1081
				g_sh->change_music();
9015.2.31 by GunChleoc
Make SoundHandler Widelands-agnostic.
1082
			}
1083
		}
1084
	} break;
6869.1.4 by Holger Rapp
Addressed all the FIXMEs.
1085
6891.1.1 by Shevonar
Moved classes from wlapplication.cc to own files.
1086
	default:
1087
		break;
6869.1.4 by Holger Rapp
Addressed all the FIXMEs.
1088
	}
1089
	return true;
1178 by bedouin
- WLApplication patch #7/12
1090
}
1091
10997 by The Widelands Bunnybot
Show splash screen earlier and reintroduce intro music (GH #6412 / CB #4773)
1092
void WLApplication::handle_window_event(SDL_Event& ev) {
1093
	assert(ev.type == SDL_WINDOWEVENT);
1094
	switch (ev.window.event) {
1095
	case SDL_WINDOWEVENT_RESIZED:
1096
		// Do not save the new size to config at this point to avoid saving sizes that
1097
		// result from maximization etc. Save at shutdown instead.
1098
		if (!g_gr->fullscreen()) {
1099
			g_gr->change_resolution(ev.window.data1, ev.window.data2, false);
1100
		}
1101
		break;
1102
	case SDL_WINDOWEVENT_MAXIMIZED:
1103
		set_config_bool("maximized", true);
1104
		break;
1105
	case SDL_WINDOWEVENT_RESTORED:
1106
		set_config_bool("maximized", g_gr->maximized());
1107
		break;
1108
	default:
1109
		break;
1110
	}
1111
}
1112
9747 by The Widelands Bunnybot
Configurable Keyboard Shortcuts, Part 2 (#4637)
1113
bool WLApplication::handle_key(bool down, const SDL_Keycode& keycode, const int modifiers) {
10017 by The Widelands Bunnybot
Disable keys for fullscreen and screenshot when changing shortcuts (#5066)
1114
	if (!down || !handle_key_enabled_) {
9747 by The Widelands Bunnybot
Configurable Keyboard Shortcuts, Part 2 (#4637)
1115
		return false;
1116
	}
1117
1118
	if (matches_shortcut(KeyboardShortcut::kCommonScreenshot, keycode, modifiers)) {
1119
		if (g_fs->disk_space() < kMinimumDiskSpace) {
9926 by The Widelands Bunnybot
Screenshot notification (#4949)
1120
			log_warn("Omitting screenshot because diskspace is lower than %lluMiB\n",
10476 by The Widelands Bunnybot
Clean more clang-tidy checks (#5709)
1121
			         kMinimumDiskSpace / (1024ULL * 1024));
9747 by The Widelands Bunnybot
Configurable Keyboard Shortcuts, Part 2 (#4637)
1122
		} else {
1123
			g_fs->ensure_directory_exists(kScreenshotsDir);
1124
			for (uint32_t nr = 0; nr < 10000; ++nr) {
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
1125
				const std::string filename = format("%s/shot%04u.png", kScreenshotsDir, nr);
9747 by The Widelands Bunnybot
Configurable Keyboard Shortcuts, Part 2 (#4637)
1126
				if (g_fs->file_exists(filename)) {
1127
					continue;
1128
				}
1129
				g_gr->screenshot(filename);
1130
				return true;
1131
			}
1132
			log_warn("Omitting screenshot because 10000 screenshots are already present");
1133
		}
9926 by The Widelands Bunnybot
Screenshot notification (#4949)
1134
		// Screenshot not taken
1135
		return false;
9747 by The Widelands Bunnybot
Configurable Keyboard Shortcuts, Part 2 (#4637)
1136
	}
1137
1138
	if (matches_shortcut(KeyboardShortcut::kCommonFullscreen, keycode, modifiers)) {
1139
		const uint32_t time = SDL_GetTicks();
1140
		if ((time - last_resolution_change_ > 250)) {
1141
			last_resolution_change_ = time;
1142
			const bool value = !g_gr->fullscreen();
1143
			g_gr->set_fullscreen(value);
1144
			set_config_bool("fullscreen", value);
1145
		}
1146
		return true;
1147
	}
1148
7285.1.1 by Holger Rapp
- Introduce the concept of global hotkeys that are triggered when the UI did not
1149
	return false;
1150
}
1151
8048 by GunChleoc
Ran clang-format.
1152
void WLApplication::handle_input(InputCallback const* cb) {
8077.1.4 by GunChleoc
Filter out the duplicate events in WLApplication::handle_input.
1153
	// Container for keyboard events using the Alt key.
8077.1.7 by GunChleoc
Store event type rather than a bool.
1154
	// <sym, mod>, type.
9436 by The Widelands Bunnybot
Move 32-bit MS-Windows integration for PRs to the action (#4098)
1155
	std::map<std::pair<SDL_Keycode, uint16_t>, unsigned> alt_events;
8077.1.4 by GunChleoc
Filter out the duplicate events in WLApplication::handle_input.
1156
6869.1.4 by Holger Rapp
Addressed all the FIXMEs.
1157
	SDL_Event ev;
6869.1.2 by Hans Joachim Desserud
Remove now unused parameter
1158
	while (poll_event(ev)) {
2450 by sigra
Fix padding around '(' and ')' by doing some automatic replacements: "( " -> "("; " )" -> ")"; "if(" -> "if ("; "switch(" -> "switch ("; "for(" -> "for ("; "while(" -> "while ("; "catch(" -> "catch (".
1159
		switch (ev.type) {
7459.1.1 by fios at foramnagaidhlig
Added handling of SDL_KEYUP event.
1160
		case SDL_KEYUP:
7285.1.1 by Holger Rapp
- Introduce the concept of global hotkeys that are triggered when the UI did not
1161
		case SDL_KEYDOWN: {
10010 by The Widelands Bunnybot
Unify arrow and +/- handling for spinbox and slider (#5054)
1162
			normalize_numpad(ev.key.keysym);
7285.1.1 by Holger Rapp
- Introduce the concept of global hotkeys that are triggered when the UI did not
1163
			bool handled = false;
8077.1.4 by GunChleoc
Filter out the duplicate events in WLApplication::handle_input.
1164
			// Workaround for duplicate triggering of the Alt key in Ubuntu:
1165
			// Don't accept the same key twice, so we use a map to squash them and handle them later.
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
1166
			if ((ev.key.keysym.mod & KMOD_ALT) != 0) {
9421 by The Widelands Bunnybot
Use std::make_pair when inserting elements into maps (#4066)
1167
				alt_events.insert(
9436 by The Widelands Bunnybot
Move 32-bit MS-Windows integration for PRs to the action (#4098)
1168
				   std::make_pair(std::make_pair(ev.key.keysym.sym, ev.key.keysym.mod), ev.type));
8077.1.4 by GunChleoc
Filter out the duplicate events in WLApplication::handle_input.
1169
				handled = true;
1170
			}
9926 by The Widelands Bunnybot
Screenshot notification (#4949)
1171
			if (!handled) {
1172
				handled = handle_key(ev.type == SDL_KEYDOWN, ev.key.keysym.sym, ev.key.keysym.mod);
1173
			}
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
1174
			if (!handled && (cb != nullptr) && (cb->key != nullptr)) {
9926 by The Widelands Bunnybot
Screenshot notification (#4949)
1175
				cb->key(ev.type == SDL_KEYDOWN, ev.key.keysym);
1176
			}
1177
			break;
1178
		}
7208.3.2 by fios at foramnagaidhlig
Copied over Marten's code from http://bazaar.launchpad.net/~widelands-dev/widelands/feature-3d-rendering-open-gl-es-compat/revision/6827 and made it compile again.
1179
		case SDL_TEXTINPUT:
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
1180
			if ((cb != nullptr) && (cb->textinput != nullptr)) {
7208.3.2 by fios at foramnagaidhlig
Copied over Marten's code from http://bazaar.launchpad.net/~widelands-dev/widelands/feature-3d-rendering-open-gl-es-compat/revision/6827 and made it compile again.
1181
				cb->textinput(ev.text.text);
1182
			}
1183
			break;
1179 by bedouin
- WLApplication patch #8/12:
1184
		case SDL_MOUSEBUTTONDOWN:
1185
		case SDL_MOUSEBUTTONUP:
7810.1.1 by fios at foramnagaidhlig
Removed leading underscores from variable and function names.
1186
			handle_mousebutton(ev, cb);
1179 by bedouin
- WLApplication patch #8/12:
1187
			break;
7208.3.2 by fios at foramnagaidhlig
Copied over Marten's code from http://bazaar.launchpad.net/~widelands-dev/widelands/feature-3d-rendering-open-gl-es-compat/revision/6827 and made it compile again.
1188
		case SDL_MOUSEWHEEL:
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
1189
			if ((cb != nullptr) && (cb->mouse_wheel != nullptr)) {
10028 by The Widelands Bunnybot
Fix race condition when resizing game window (#5067)
1190
				cb->mouse_wheel(ev.wheel.x, ev.wheel.y, SDL_GetModState());
7208.3.2 by fios at foramnagaidhlig
Copied over Marten's code from http://bazaar.launchpad.net/~widelands-dev/widelands/feature-3d-rendering-open-gl-es-compat/revision/6827 and made it compile again.
1191
			}
1192
			break;
1686 by sigra
Make scrollbars react to mousewheel.
1193
		case SDL_MOUSEMOTION:
8131.2.13 by Holger Rapp
Renaming Point -> Vector.
1194
			mouse_position_ = Vector2i(ev.motion.x, ev.motion.y);
1179 by bedouin
- WLApplication patch #8/12:
1195
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
1196
			if (((ev.motion.xrel != 0) || (ev.motion.yrel != 0)) && (cb != nullptr) &&
1197
			    (cb->mouse_move != nullptr)) {
8048 by GunChleoc
Ran clang-format.
1198
				cb->mouse_move(
1199
				   ev.motion.state, ev.motion.x, ev.motion.y, ev.motion.xrel, ev.motion.yrel);
9386 by The Widelands Bunnybot
Enfore optional braces (#3808)
1200
			}
1686 by sigra
Make scrollbars react to mousewheel.
1201
			break;
9470 by The Widelands Bunnybot
Make the Widelands window resizable (#4125)
1202
		case SDL_WINDOWEVENT:
10997 by The Widelands Bunnybot
Show splash screen earlier and reintroduce intro music (GH #6412 / CB #4773)
1203
			handle_window_event(ev);
9470 by The Widelands Bunnybot
Make the Widelands window resizable (#4125)
1204
			break;
1179 by bedouin
- WLApplication patch #8/12:
1205
		case SDL_QUIT:
7737.1.1 by Klaus Halfmann \
Migration from m_... to ..._ mostly in wui
1206
			should_die_ = true;
1179 by bedouin
- WLApplication patch #8/12:
1207
			break;
11008 by The Widelands Bunnybot
Fix new compiler warning on clang-18 (CB #4827 / GH #6465)
1208
		default:
1209
			break;
1178 by bedouin
- WLApplication patch #7/12
1210
		}
1211
	}
8077.1.4 by GunChleoc
Filter out the duplicate events in WLApplication::handle_input.
1212
8077.1.5 by GunChleoc
Code cleanup.
1213
	// Now constructing the events for the Alt key from the container and handling them.
8077.1.4 by GunChleoc
Filter out the duplicate events in WLApplication::handle_input.
1214
	for (const auto& event : alt_events) {
8077.1.7 by GunChleoc
Store event type rather than a bool.
1215
		ev.type = event.second;
8077.1.5 by GunChleoc
Code cleanup.
1216
		ev.key.keysym.sym = event.first.first;
1217
		ev.key.keysym.mod = event.first.second;
8077.1.4 by GunChleoc
Filter out the duplicate events in WLApplication::handle_input.
1218
		bool handled = false;
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
1219
		if ((cb != nullptr) && (cb->key != nullptr)) {
8077.1.5 by GunChleoc
Code cleanup.
1220
			handled = cb->key(ev.type == SDL_KEYDOWN, ev.key.keysym);
8077.1.4 by GunChleoc
Filter out the duplicate events in WLApplication::handle_input.
1221
		}
1222
		if (!handled) {
8077.1.5 by GunChleoc
Code cleanup.
1223
			handle_key(ev.type == SDL_KEYDOWN, ev.key.keysym.sym, ev.key.keysym.mod);
8077.1.4 by GunChleoc
Filter out the duplicate events in WLApplication::handle_input.
1224
		}
1225
	}
1178 by bedouin
- WLApplication patch #7/12
1226
}
1227
6568.1.1 by Holger Rapp
Handle with apple mouse quirks in one place only.
1228
/*
1229
 * Capsule repetitive code for mouse buttons
1230
 */
8048 by GunChleoc
Ran clang-format.
1231
void WLApplication::handle_mousebutton(SDL_Event& ev, InputCallback const* cb) {
1232
	if (mouse_swapped_) {
1233
		switch (ev.button.button) {
1234
		case SDL_BUTTON_LEFT:
1235
			ev.button.button = SDL_BUTTON_RIGHT;
1236
			break;
1237
		case SDL_BUTTON_RIGHT:
6568.1.1 by Holger Rapp
Handle with apple mouse quirks in one place only.
1238
			ev.button.button = SDL_BUTTON_LEFT;
8048 by GunChleoc
Ran clang-format.
1239
			break;
1240
		default:
1241
			break;
6568.1.1 by Holger Rapp
Handle with apple mouse quirks in one place only.
1242
		}
8048 by GunChleoc
Ran clang-format.
1243
	}
1244
1245
#ifdef __APPLE__
1246
	//  On Mac, SDL does middle mouse button emulation (alt+left). This
1247
	//  interferes with the editor, which is using alt+left click for
1248
	//  third tool. So if we ever see a middle mouse button on Mac,
1249
	//  check if any ALT Key is pressed and if, treat it like a left
1250
	//  mouse button.
1251
	if (ev.button.button == SDL_BUTTON_MIDDLE &&
1252
	    (get_key_state(SDL_SCANCODE_LALT) || get_key_state(SDL_SCANCODE_RALT))) {
1253
		ev.button.button = SDL_BUTTON_LEFT;
1254
		faking_middle_mouse_button_ = true;
1255
	}
6568.1.1 by Holger Rapp
Handle with apple mouse quirks in one place only.
1256
#endif
1257
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
1258
	if (ev.type == SDL_MOUSEBUTTONDOWN && (cb != nullptr) && (cb->mouse_press != nullptr)) {
8048 by GunChleoc
Ran clang-format.
1259
		cb->mouse_press(ev.button.button, ev.button.x, ev.button.y);
9386 by The Widelands Bunnybot
Enfore optional braces (#3808)
1260
	} else if (ev.type == SDL_MOUSEBUTTONUP) {
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
1261
		if ((cb != nullptr) && (cb->mouse_release != nullptr)) {
8048 by GunChleoc
Ran clang-format.
1262
			if (ev.button.button == SDL_BUTTON_MIDDLE && faking_middle_mouse_button_) {
1263
				cb->mouse_release(SDL_BUTTON_LEFT, ev.button.x, ev.button.y);
1264
				faking_middle_mouse_button_ = false;
6568.1.1 by Holger Rapp
Handle with apple mouse quirks in one place only.
1265
			}
8048 by GunChleoc
Ran clang-format.
1266
			cb->mouse_release(ev.button.button, ev.button.x, ev.button.y);
6568.1.1 by Holger Rapp
Handle with apple mouse quirks in one place only.
1267
		}
8048 by GunChleoc
Ran clang-format.
1268
	}
6568.1.1 by Holger Rapp
Handle with apple mouse quirks in one place only.
1269
}
1270
10351 by The Widelands Bunnybot
Use SDL Relative Mouse Mode (#5494)
1271
/// Instantaneously move the mouse cursor.
4579 by sigra
* Fix const correctness.
1272
///
1273
/// \param position The new mouse position
8131.2.13 by Holger Rapp
Renaming Point -> Vector.
1274
void WLApplication::warp_mouse(const Vector2i position) {
7737.1.1 by Klaus Halfmann \
Migration from m_... to ..._ mostly in wui
1275
	mouse_position_ = position;
8338.1.5 by GunChleoc
Addressed code review.
1276
	Vector2i cur_position = Vector2i::zero();
6869.1.3 by Hans Joachim Desserud
Fix codecheck issues. Silly editor, replacing my tabs like that
1277
	SDL_GetMouseState(&cur_position.x, &cur_position.y);
10351 by The Widelands Bunnybot
Use SDL Relative Mouse Mode (#5494)
1278
6869.1.3 by Hans Joachim Desserud
Fix codecheck issues. Silly editor, replacing my tabs like that
1279
	if (cur_position != position) {
7208.3.2 by fios at foramnagaidhlig
Copied over Marten's code from http://bazaar.launchpad.net/~widelands-dev/widelands/feature-3d-rendering-open-gl-es-compat/revision/6827 and made it compile again.
1280
		SDL_Window* sdl_window = g_gr->get_sdlwindow();
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
1281
		if (sdl_window != nullptr) {
10351 by The Widelands Bunnybot
Use SDL Relative Mouse Mode (#5494)
1282
			if (!mouse_locked_) {
10487 by The Widelands Bunnybot
Call `SDL_PumpEvents` from main thread only (#5656)
1283
				// Fix for #5655 needed for macOS
1284
				NoteThreadSafeFunction::instantiate(
1285
				   [sdl_window, position]() {
1286
					   SDL_PumpEvents();
1287
					   SDL_FlushEvent(SDL_MOUSEMOTION);
1288
					   SDL_WarpMouseInWindow(sdl_window, position.x, position.y);
1289
				   },
1290
				   true);
10351 by The Widelands Bunnybot
Use SDL Relative Mouse Mode (#5494)
1291
				return;
1292
			}
7208.3.2 by fios at foramnagaidhlig
Copied over Marten's code from http://bazaar.launchpad.net/~widelands-dev/widelands/feature-3d-rendering-open-gl-es-compat/revision/6827 and made it compile again.
1293
		}
6869.1.3 by Hans Joachim Desserud
Fix codecheck issues. Silly editor, replacing my tabs like that
1294
	}
1178 by bedouin
- WLApplication patch #7/12
1295
}
1296
9251 by The Widelands Bunnybot
Add numpad hotkeys (#3840)
1297
void WLApplication::set_mouse_lock(const bool locked) {
1298
	mouse_locked_ = locked;
10351 by The Widelands Bunnybot
Use SDL Relative Mouse Mode (#5494)
1299
	if (mouse_locked_) {
1300
		SDL_SetRelativeMouseMode(SDL_TRUE);
1301
	} else {
1302
		SDL_SetRelativeMouseMode(SDL_FALSE);
1303
		warp_mouse(mouse_position_);  // Restore to where we started dragging
1304
	}
9251 by The Widelands Bunnybot
Add numpad hotkeys (#3840)
1305
10351 by The Widelands Bunnybot
Use SDL Relative Mouse Mode (#5494)
1306
	// SDL automatically hides the cursor when in relative mode. This will hide
1307
	// the selection marker as well.
9251 by The Widelands Bunnybot
Add numpad hotkeys (#3840)
1308
	if (g_mouse_cursor->is_using_sdl()) {
1309
		g_mouse_cursor->set_visible(!mouse_locked_);
1310
	}
1311
}
1312
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
1313
/** Register the datadir and the datadir for testing (if any) with the global filesystem wrapper. */
1314
void WLApplication::init_filesystems() {
1315
	datadir_ = g_fs->canonicalize_name(datadir_);
1316
	datadir_for_testing_ = g_fs->canonicalize_name(datadir_for_testing_);
1317
1318
	log_info("Adding data directory: %s\n", datadir_.c_str());
1319
	g_fs->add_file_system(&FileSystem::create(datadir_));
1320
1321
	if (!datadir_for_testing_.empty()) {
1322
		log_info("Adding testing directory: %s\n", datadir_for_testing_.c_str());
1323
		g_fs->add_file_system(&FileSystem::create(datadir_for_testing_));
1324
	}
1325
}
1326
1179 by bedouin
- WLApplication patch #8/12:
1327
/**
1328
 * Read the config file, parse the commandline and give all other internal
1329
 * parameters sensible default values
1330
 */
3166 by sigra
Fix warnings from GCC 4.3.0.
1331
bool WLApplication::init_settings() {
8729.1.12 by Lucki
Catch FileError and restore some accidentally deleted lines
1332
7839.10.2 by fios at foramnagaidhlig
Fixed the code. Also, removed a bit of dead code.
1333
	// Read in the configuration file
9190.1.2 by GunChleoc
Fix compiler warning in read/write config.
1334
	read_config();
1172 by bedouin
- Move conffile and commandline parsing into WLApplication
1335
7839.10.2 by fios at foramnagaidhlig
Fixed the code. Also, removed a bit of dead code.
1336
	// Then parse the commandline - overwrites conffile settings
5164 by Nasenbaer
Fix code style and usability of rev 5161 - now the commandline arguments are saved in .widelands/config, so users do not have to set them up again and again.
1337
	handle_commandline_parameters();
1338
8729.1.25 by Lucki
Refactor g_options
1339
	set_mouse_swap(get_config_bool("swapmouse", false));
1175 by bedouin
- WLApplication patch #4/12:
1340
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
1341
	// Without this the config options get dropped by check_used().
1342
	for (const std::string& conf : get_all_parameters()) {
1343
		get_config_string(conf, "");
1344
	}
8662.2.1 by Notabilis
Documenting metaserver command line options.
1345
9744 by The Widelands Bunnybot
Configurable keyboard shortcuts (#4476)
1346
	// Keyboard shortcuts
1347
	init_shortcuts();
1175 by bedouin
- WLApplication patch #4/12:
1348
10028 by The Widelands Bunnybot
Fix race condition when resizing game window (#5067)
1349
	// Mousewheel options
10373 by The Widelands Bunnybot
Fix initialisation of inverted horizontal scrolling compensation (#5543)
1350
	// we store this in the config for reference, but need to reset it for the detection to work
1351
	set_mousewheel_option_bool(MousewheelOptionID::kInvertedXDetected, false);
10028 by The Widelands Bunnybot
Fix race condition when resizing game window (#5067)
1352
	update_mousewheel_settings();
1353
9436 by The Widelands Bunnybot
Move 32-bit MS-Windows integration for PRs to the action (#4098)
1354
	int64_t last_start = get_config_int("last_start", 0);
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
1355
	int64_t now = time(nullptr);
10476 by The Widelands Bunnybot
Clean more clang-tidy checks (#5709)
1356
	if (last_start + 12LL * 60LL * 60LL < now || get_config_string("uuid", "").empty()) {
8501.1.1 by Notabilis
All changes in one clean diff on master.
1357
		// First start of the game or not started for 12 hours. Create a (new) UUID.
1358
		// For the use of the UUID, see network/internet_gaming_protocol.h
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
1359
		set_config_string("uuid", generate_random_uuid());
8501.1.1 by Notabilis
All changes in one clean diff on master.
1360
	}
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
1361
	set_config_int("last_start", now);
8501.1.1 by Notabilis
All changes in one clean diff on master.
1362
1172 by bedouin
- Move conffile and commandline parsing into WLApplication
1363
	return true;
1164 by bedouin
- WLApplication patch 1/12
1364
}
1365
1179 by bedouin
- WLApplication patch #8/12:
1366
/**
5826.1.1 by Martin
Fixed usage of uninstalled languages in Ubuntu
1367
 * Initialize language settings
1368
 */
1369
void WLApplication::init_language() {
9267 by The Widelands Bunnybot
Handle missing locale dir on Windows (#3757)
1370
	// Set the locale dir
9444 by The Widelands Bunnybot
Add localedir parameter (#4112)
1371
	if (!localedir_.empty()) {
1372
		i18n::set_localedir(g_fs->canonicalize_name(localedir_));
1373
	} else {
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
1374
		i18n::set_localedir(g_fs->canonicalize_name(datadir_ + "/i18n/translations"));
9444 by The Widelands Bunnybot
Add localedir parameter (#4112)
1375
	}
9267 by The Widelands Bunnybot
Handle missing locale dir on Windows (#3757)
1376
1377
	// If locale dir is not a directory, barf. We can handle it not being there tough.
1378
	if (g_fs->file_exists(i18n::get_localedir()) && !g_fs->is_directory(i18n::get_localedir())) {
1379
		SDL_ShowSimpleMessageBox(
1380
		   SDL_MESSAGEBOX_ERROR, "'locale' directory not valid",
1381
		   std::string(i18n::get_localedir() + "\nis not a directory. Please fix this.").c_str(),
9617 by The Widelands Bunnybot
Change clang-tidy to exclusion list and clear some more checks (#4407)
1382
		   nullptr);
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
1383
		log_err("%s is not a directory. Please fix this.\n", i18n::get_localedir().c_str());
9267 by The Widelands Bunnybot
Handle missing locale dir on Windows (#3757)
1384
		exit(1);
1385
	}
1386
1387
	if (!g_fs->is_directory(i18n::get_localedir()) ||
1388
	    g_fs->list_directory(i18n::get_localedir()).empty()) {
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
1389
		log_warn("No locale translations found in %s\n", i18n::get_localedir().c_str());
9267 by The Widelands Bunnybot
Handle missing locale dir on Windows (#3757)
1390
	}
1391
5826.1.1 by Martin
Fixed usage of uninstalled languages in Ubuntu
1392
	// Initialize locale and grab "widelands" textdomain
1393
	i18n::init_locale();
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
1394
	i18n::grab_textdomain("widelands", i18n::get_localedir());
5826.1.1 by Martin
Fixed usage of uninstalled languages in Ubuntu
1395
1396
	// Set locale corresponding to selected language
8729.1.25 by Lucki
Refactor g_options
1397
	std::string language = get_config_string("language", "");
7211.3.3 by fios at foramnagaidhlig
Widelands now reads and sets the font information on program start.
1398
	i18n::set_locale(language);
7211.3.28 by fios at foramnagaidhlig
Moved locale fontset definitions from WLApplication to i18n.
1399
}
5826.1.1 by Martin
Fixed usage of uninstalled languages in Ubuntu
1400
11111 by The Widelands Bunnybot
Keyboard shortcuts for add-ons (CB #4889 / GH #6528)
1401
void WLApplication::init_plugin_shortcuts() {
1402
	LuaInterface lua;
1403
	for (const std::string& name : g_fs->list_directory(kAddOnDir)) {
1404
		std::string path = name;
1405
		path += FileSystem::file_separator();
1406
		path += kAddOnKeyboardShortcutsFile;
1407
		if (g_fs->file_exists(path)) {
1408
			try {
1409
				std::unique_ptr<LuaTable> all_definitions(lua.run_script(path));
1410
				for (const auto& table : all_definitions->array_entries<std::unique_ptr<LuaTable>>()) {
1411
					std::string internal_name;
1412
					try {
1413
						internal_name = table->get_string("internal_name");
1414
						std::string descname = table->get_string("descname");
1415
1416
						std::set<KeyboardShortcutScope> scopes;
1417
						std::unique_ptr<LuaTable> scopes_table = table->get_table("scopes");
1418
						for (const std::string& scope : scopes_table->array_entries<std::string>()) {
1419
							if (scope == "global") {
1420
								scopes.insert(KeyboardShortcutScope::kGlobal);
1421
							} else if (scope == "game") {
1422
								scopes.insert(KeyboardShortcutScope::kGame);
1423
							} else if (scope == "editor") {
1424
								scopes.insert(KeyboardShortcutScope::kEditor);
1425
							} else if (scope == "main_menu") {
1426
								scopes.insert(KeyboardShortcutScope::kMainMenu);
1427
							} else {
1428
								throw WLWarning("", "Invalid scope '%s'", scope.c_str());
1429
							}
1430
						}
1431
						if (scopes.empty()) {
1432
							throw WLWarning("", "No scopes");
1433
						}
1434
1435
						std::string keycode_name = table->get_string("keycode");
1436
						SDL_Keycode default_shortcut = SDL_GetKeyFromName(keycode_name.c_str());
1437
						if (default_shortcut == SDLK_UNKNOWN) {
1438
							throw WLWarning("", "Invalid keycode '%s'", keycode_name.c_str());
1439
						}
1440
1441
						int default_mods = 0;
1442
						if (table->has_key("mods")) {
1443
							std::unique_ptr<LuaTable> mods_table = table->get_table("mods");
1444
							for (const std::string& mod : mods_table->array_entries<std::string>()) {
1445
								if (mod == "ctrl" || mod == "control") {
1446
									default_mods |= KMOD_CTRL;
1447
								} else if (mod == "shift") {
1448
									default_mods |= KMOD_SHIFT;
1449
								} else if (mod == "alt") {
1450
									default_mods |= KMOD_ALT;
1451
								} else if (mod == "gui" || mod == "super" || mod == "meta" ||
1452
								           mod == "cmd" || mod == "command" || mod == "windows") {
1453
									default_mods |= KMOD_GUI;
1454
								} else {
1455
									throw WLWarning("", "Invalid modifier '%s'", mod.c_str());
1456
								}
1457
							}
1458
						}
1459
1460
						create_replace_shortcut(
1461
						   internal_name, descname, scopes, keysym(default_shortcut, default_mods));
1462
					} catch (const std::exception& e) {
1463
						log_err("Error in plugin keyboard shortcut definition in '%s': '%s': %s",
1464
						        path.c_str(), internal_name.c_str(), e.what());
1465
					}
1466
				}
1467
			} catch (const std::exception& e) {
1468
				log_err("Error reading plugin keyboard shortcut definitions from '%s': %s",
1469
				        path.c_str(), e.what());
1470
			}
1471
		}
1472
	}
1473
}
1474
5826.1.1 by Martin
Fixed usage of uninstalled languages in Ubuntu
1475
/**
1181 by bedouin
- WLApplication path #11/12
1476
 * Remember the last settings: write them into the config file
1179 by bedouin
- WLApplication patch #8/12:
1477
 */
8048 by GunChleoc
Ran clang-format.
1478
void WLApplication::shutdown_settings() {
9190.1.2 by GunChleoc
Fix compiler warning in read/write config.
1479
	write_config();
1175 by bedouin
- WLApplication patch #4/12:
1480
}
1481
8048 by GunChleoc
Ran clang-format.
1482
void WLApplication::shutdown_hardware() {
9251 by The Widelands Bunnybot
Add numpad hotkeys (#3840)
1483
	delete g_mouse_cursor;
1484
	g_mouse_cursor = nullptr;
1485
7275.1.1 by Holger Rapp
- Make fullscreen toggle work. Fullscreen is now always at the native resolution
1486
	delete g_gr;
1487
	g_gr = nullptr;
4995.2.14 by Timo Wingender
Restructuring of the render classes:
1488
8182.2.15 by GunChleoc
Fixed codecheck.
1489
// SOUND can lock up with buggy SDL/drivers. we try to do the right thing
1490
// but if it doesn't happen we will kill widelands anyway in 5 seconds.
8182.2.11 by GunChleoc
terminate(int) isn't called in Windows.
1491
#ifndef _WIN32
5174 by Victor Pelt
more misc code check updates
1492
	signal(SIGALRM, terminate);
8182.2.15 by GunChleoc
Fixed codecheck.
1493
	// TODO(GunChleoc): alarm is a POSIX function. If we found a Windows equivalent, we could call
1494
	// terminate in Windows as well.
5159 by Victor Pelt
improve hang detection
1495
	alarm(5);
5180 by Jari Hautio
Fixed to compile on windows. Disabled pulse audio related audio hang fix in r5159 for win32.
1496
#endif
5159 by Victor Pelt
improve hang detection
1497
9015.2.45 by GunChleoc
Renamed g_soundhandler to g_sh for consistency with other global objects.
1498
	delete g_sh;
1499
	g_sh = nullptr;
5158 by Victor Pelt
hack to work around pulseaudio bug
1500
8048 by GunChleoc
Ran clang-format.
1501
	SDL_QuitSubSystem(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
1175 by bedouin
- WLApplication patch #4/12:
1502
}
1503
1179 by bedouin
- WLApplication patch #8/12:
1504
/**
2617 by bedouin
- extract method parse_commandline
1505
 * Parse the commandline and translate the options into name/value pairs
1506
 *
1507
 * The format for commandline parameters is --paramname[=value], that means:
1508
 * \li starts with "--", i.e. all parameters are "long options"
1509
 * \li arguments are passed with "="
1510
 *
1511
 * \param argc The number of command line arguments
1512
 * \param argv Array of command line arguments
1513
 */
8048 by GunChleoc
Ran clang-format.
1514
void WLApplication::parse_commandline(int const argc, char const* const* const argv) {
2790 by sigra
Move some types out of geometry.h to their own files. Group and sort includes properly. Remove many redundant includes.
1515
	for (int i = 1; i < argc; ++i) {
3697 by sigra
General cleanups:
1516
		std::string opt = argv[i];
2617 by bedouin
- extract method parse_commandline
1517
		std::string value;
1518
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
1519
		if (opt.compare(0, 5, "-psn_") == 0) {
7247 by Holger Rapp
Fixes for deployment on Mac OS X.
1520
			// Mac OS passes this on the commandline when launched from finder.
1521
			// SDL1 removed it for us (apparently), but SDL2 does no longer, so we
1522
			// have to do this ourselves.
1523
			continue;
1524
		}
1525
7839.10.2 by fios at foramnagaidhlig
Fixed the code. Also, removed a bit of dead code.
1526
		// Are we looking at an option at all?
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
1527
		if (opt.size() < 2 || (opt.compare(0, 2, "--") != 0)) {
9706 by The Widelands Bunnybot
Allow savegames anywhere (#4515)
1528
			if (argc == 2) {
1529
				// Special case of opening a savegame or replay from file browser
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
1530
				if (opt.size() > kSavegameExtension.size() &&
1531
				    0 == opt.compare(opt.size() - kSavegameExtension.size(), kSavegameExtension.size(),
9706 by The Widelands Bunnybot
Allow savegames anywhere (#4515)
1532
				                     kSavegameExtension)) {
1533
					commandline_["loadgame"] = opt;
1534
					continue;
10194 by The Widelands Bunnybot
Fix misc clang-tidy checks in remaining files (#5289)
1535
				}
1536
				if (opt.size() > kReplayExtension.size() &&
1537
				    0 == opt.compare(opt.size() - kReplayExtension.size(), kReplayExtension.size(),
1538
				                     kReplayExtension)) {
9706 by The Widelands Bunnybot
Allow savegames anywhere (#4515)
1539
					commandline_["replay"] = opt;
1540
					continue;
1541
				}
1542
			}
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
1543
			commandline_["error"] = opt;
1544
			break;
9386 by The Widelands Bunnybot
Enfore optional braces (#3808)
1545
		}
10194 by The Widelands Bunnybot
Fix misc clang-tidy checks in remaining files (#5289)
1546
		opt.erase(0, 2);  //  yes. remove the leading "--", just for cosmetics
2617 by bedouin
- extract method parse_commandline
1547
7839.10.2 by fios at foramnagaidhlig
Fixed the code. Also, removed a bit of dead code.
1548
		// Look if this option has a value
4735 by sigra
Optimize string usage:
1549
		std::string::size_type const pos = opt.find('=');
2617 by bedouin
- extract method parse_commandline
1550
8048 by GunChleoc
Ran clang-format.
1551
		if (pos == std::string::npos) {  //  if no equals sign found
3697 by sigra
General cleanups:
1552
			value = "";
2617 by bedouin
- extract method parse_commandline
1553
		} else {
7839.10.2 by fios at foramnagaidhlig
Fixed the code. Also, removed a bit of dead code.
1554
			// Extract option value
4735 by sigra
Optimize string usage:
1555
			value = opt.substr(pos + 1);
2617 by bedouin
- extract method parse_commandline
1556
7839.10.2 by fios at foramnagaidhlig
Fixed the code. Also, removed a bit of dead code.
1557
			// Remove value from option name
3697 by sigra
General cleanups:
1558
			opt.erase(pos, opt.size() - pos);
2617 by bedouin
- extract method parse_commandline
1559
		}
1560
7737.1.1 by Klaus Halfmann \
Migration from m_... to ..._ mostly in wui
1561
		commandline_[opt] = value;
2617 by bedouin
- extract method parse_commandline
1562
	}
1563
}
1564
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1565
namespace {
1566
1567
void throw_extra_value(const std::string& opt) {
1568
	throw ParameterError(
1569
	   CmdLineVerbosity::None, format(_("Command line parameter --%s can not use a value"), opt));
1570
}
1571
1572
void throw_empty_value(const std::string& opt) {
1573
	throw ParameterError(
1574
	   CmdLineVerbosity::None, format(_("Empty value of command line parameter --%s"), opt));
1575
}
1576
1577
void throw_exclusive(const std::string& opt, const std::string& other) {
1578
	throw ParameterError(
1579
	   CmdLineVerbosity::None,
1580
	   format(_("Command line parameters --%1$s and --%2$s can not be combined"), opt, other));
1581
}
1582
1583
}  // namespace
1584
1585
// Checks and returns whether `param` was set, but throws ParameterError if it also had a value.
1586
bool WLApplication::check_commandline_flag(const std::string& opt) {
1587
	auto found = commandline_.find(opt);
1588
	if (found == commandline_.end()) {
1589
		return false;
1590
	}
1591
	if (!found->second.empty()) {
1592
		throw_extra_value(opt);
1593
	}
1594
	commandline_.erase(found);
1595
	return true;
1596
}
1597
1598
// Returns the value of `opt`. Only returns std::nullopt if `opt` was not used.
1599
// If `opt` was used without a value, then returns an empty string if `allow_empty` is true,
1600
// otherwise throws ParameterError.
1601
OptionalParameter WLApplication::get_commandline_option_value(const std::string& opt,
1602
                                                              const bool allow_empty) {
1603
	auto found = commandline_.find(opt);
1604
	if (found == commandline_.end()) {
1605
		return std::nullopt;
1606
	}
1607
	// need to copy before deletion for returning later
1608
	std::string rv = found->second;
1609
	if (!allow_empty && rv.empty()) {
1610
		throw_empty_value(opt);
1611
	}
1612
	commandline_.erase(found);
1613
1614
	// Fix warning in old clang versions
1615
#ifdef __clang__
1616
#if __clang_major__ < 13
1617
	return std::move(rv);
1618
#else
1619
	return rv;
1620
#endif
1621
#else
1622
	return rv;
1623
#endif
1624
}
1625
2617 by bedouin
- extract method parse_commandline
1626
/**
7737.1.1 by Klaus Halfmann \
Migration from m_... to ..._ mostly in wui
1627
 * Parse the command line given in commandline_
1172 by bedouin
- Move conffile and commandline parsing into WLApplication
1628
 *
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
1629
 * \throw a ParameterError if there were errors during parsing \e or if "--help"
8939 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/appveyor_reenable_glbinding:
1630
 */
8048 by GunChleoc
Ran clang-format.
1631
void WLApplication::handle_commandline_parameters() {
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1632
1633
	if (check_commandline_flag("verbose-i18n")) {
9971 by The Widelands Bunnybot
Improved exception reporting (#5003)
1634
		i18n::enable_verbose_i18n();
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1635
	}
1636
1637
	if (OptionalParameter localedir_option = get_commandline_option_value("localedir");
1638
	    localedir_option.has_value()) {
1639
		localedir_ = *localedir_option;
1640
	}
1641
1642
	const bool skip_check_datadir_version = check_commandline_flag("skip_check_datadir_version");
1643
9954 by The Widelands Bunnybot
Add option to skip datadir version check (#4987)
1644
	auto checkdatadirversion = [skip_check_datadir_version](const std::string& dd) {
1645
		if (skip_check_datadir_version) {
1646
			return std::string();
1647
		}
9942 by The Widelands Bunnybot
Autogenerate and compare datadir version file (#4853)
1648
		try {
1649
			std::unique_ptr<FileSystem> fs(&FileSystem::create(dd));
10065 by The Widelands Bunnybot
Clean some more clang-tidy checks (#5108)
1650
			if (!fs) {
9942 by The Widelands Bunnybot
Autogenerate and compare datadir version file (#4853)
1651
				return std::string("Unable to allocate filesystem");
1652
			}
1653
1654
			size_t len;
1655
			void* textptr = fs->load("datadirversion", len);
1656
			std::string text(static_cast<char*>(textptr), len);
1657
			free(textptr);
1658
1659
			size_t sep_pos = text.find_first_of("\n\r");
1660
			if (sep_pos == std::string::npos) {
1661
				return std::string("Malformed one-liner version string");
1662
			}
1663
1664
			if (sep_pos != build_id().size() || 0 != text.compare(0, sep_pos, build_id())) {
11152 by The Widelands Bunnybot
Preserve debug symbols in windows debug builds (GH #6563 / CB #4923)
1665
				return std::string("Incorrect version string");
9942 by The Widelands Bunnybot
Autogenerate and compare datadir version file (#4853)
1666
			}
1667
		} catch (const std::exception& e) {
1668
			return std::string(e.what());
1669
		}
1670
		return std::string();
1671
	};
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
1672
	bool found_datadir = false;
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1673
	if (OptionalParameter datadir_option = get_commandline_option_value("datadir");
1674
	    datadir_option.has_value()) {
1675
		datadir_ = *datadir_option;
9942 by The Widelands Bunnybot
Autogenerate and compare datadir version file (#4853)
1676
1677
		const std::string err = checkdatadirversion(datadir_);
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
1678
		found_datadir = err.empty();
1679
		if (!found_datadir) {
9942 by The Widelands Bunnybot
Autogenerate and compare datadir version file (#4853)
1680
			log_err("Invalid explicit datadir '%s': %s", datadir_.c_str(), err.c_str());
1681
		}
7224.1.9 by Holger Rapp
One more go. Removed one configuration variable and made the code simpler.
1682
	} else {
9942 by The Widelands Bunnybot
Autogenerate and compare datadir version file (#4853)
1683
		std::vector<std::pair<std::string, std::string>> wrong_candidates;
1684
1685
		// Try absolute path first.
9706 by The Widelands Bunnybot
Allow savegames anywhere (#4515)
1686
		if (is_absolute_path(INSTALL_DATADIR)) {
1687
			datadir_ = INSTALL_DATADIR;
9942 by The Widelands Bunnybot
Autogenerate and compare datadir version file (#4853)
1688
			const std::string err = checkdatadirversion(datadir_);
1689
			if (err.empty()) {
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
1690
				found_datadir = true;
9942 by The Widelands Bunnybot
Autogenerate and compare datadir version file (#4853)
1691
			} else {
1692
				wrong_candidates.emplace_back(datadir_, err);
1693
			}
1694
		}
1695
1696
		// Next, pick the first applicable XDG path.
8729.1.21 by Lucki
Support XDG_DATA_DIRS
1697
#ifdef USE_XDG
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
1698
		if (!found_datadir) {
9706 by The Widelands Bunnybot
Allow savegames anywhere (#4515)
1699
			for (const auto& datadir : FileSystem::get_xdgdatadirs()) {
1700
				RealFSImpl dir(datadir);
1701
				if (dir.is_directory(datadir + "/widelands")) {
1702
					datadir_ = datadir + "/widelands";
9942 by The Widelands Bunnybot
Autogenerate and compare datadir version file (#4853)
1703
1704
					const std::string err = checkdatadirversion(datadir_);
1705
					if (err.empty()) {
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
1706
						found_datadir = true;
9942 by The Widelands Bunnybot
Autogenerate and compare datadir version file (#4853)
1707
						break;
1708
					}
10194 by The Widelands Bunnybot
Fix misc clang-tidy checks in remaining files (#5289)
1709
					wrong_candidates.emplace_back(datadir_, err);
9706 by The Widelands Bunnybot
Allow savegames anywhere (#4515)
1710
				}
8729.1.21 by Lucki
Support XDG_DATA_DIRS
1711
			}
9942 by The Widelands Bunnybot
Autogenerate and compare datadir version file (#4853)
1712
		}
9706 by The Widelands Bunnybot
Allow savegames anywhere (#4515)
1713
#endif
9942 by The Widelands Bunnybot
Autogenerate and compare datadir version file (#4853)
1714
1715
		// Finally, try a relative datadir.
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
1716
		if (!found_datadir) {
9942 by The Widelands Bunnybot
Autogenerate and compare datadir version file (#4853)
1717
			datadir_ = get_executable_directory() + FileSystem::file_separator() + INSTALL_DATADIR;
1718
			const std::string err = checkdatadirversion(datadir_);
1719
			if (err.empty()) {
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
1720
				found_datadir = true;
9942 by The Widelands Bunnybot
Autogenerate and compare datadir version file (#4853)
1721
			} else {
1722
				wrong_candidates.emplace_back(datadir_, err);
1723
			}
1724
		}
1725
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
1726
		if (!found_datadir) {
9942 by The Widelands Bunnybot
Autogenerate and compare datadir version file (#4853)
1727
			log_err("Unable to detect the datadir. Please specify a datadir explicitly\n"
1728
			        "with the --datadir command line option. Tried the following %d path(s):",
1729
			        static_cast<int>(wrong_candidates.size()));
1730
			for (const auto& pair : wrong_candidates) {
10878 by The Widelands Bunnybot
Stringfixes (CB #4697 / GH #6334)
1731
				log_err(" • '%s': %s", pair.first.c_str(), pair.second.c_str());
9942 by The Widelands Bunnybot
Autogenerate and compare datadir version file (#4853)
1732
			}
8729.1.21 by Lucki
Support XDG_DATA_DIRS
1733
		}
7296 by Holger Rapp
Emergency fix: Repair mac os X nightlies.
1734
	}
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
1735
	if (found_datadir && !is_absolute_path(datadir_)) {
8751.3.1 by GunChleoc
Exit gracefully if user specifies a datadir that doesn't exist
1736
		try {
1737
			datadir_ = absolute_path_if_not_windows(FileSystem::get_working_directory() +
8760 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/bug-1703833-catch-missing-datadir:
1738
			                                        FileSystem::file_separator() + datadir_);
8751.3.1 by GunChleoc
Exit gracefully if user specifies a datadir that doesn't exist
1739
		} catch (const WException& e) {
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
1740
			log_err("Error parsing datadir: %s\n", e.what());
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
1741
			found_datadir = false;
8751.3.1 by GunChleoc
Exit gracefully if user specifies a datadir that doesn't exist
1742
		}
4074 by dwarik
add --datadir flag for location of specific widelands data directory in non-default places
1743
	}
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
1744
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
1745
	if (OptionalParameter testdir = get_commandline_option_value("datadir_for_testing");
1746
	    testdir.has_value()) {
1747
		datadir_for_testing_ = *testdir;
1748
	}
1749
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1750
	if (OptionalParameter lang = get_commandline_option_value("language"); lang.has_value()) {
1751
		set_config_string("language", *lang);
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
1752
	}
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
1753
1754
	init_filesystems();
1755
1756
	// Do this now to have translated command line help.
1757
	init_language();
1758
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1759
	// Set up list of valid command line options and their translated help texts
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
1760
	fill_parameter_vector();
1761
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1762
	// This is used by the parser to report an error
1763
	if (OptionalParameter err = get_commandline_option_value("error"); err.has_value()) {
1764
		throw ParameterError(
1765
		   CmdLineVerbosity::Normal,
1766
		   format(_("Unknown command line parameter: %s\nMaybe a '=' is missing?"), *err));
1767
	}
1768
1769
	// TODO(tothxa): These were checked before datadir and locale were set up, but don't seem to be
1770
	//               used during detecting and setting them up. Let's see if anything breaks if we
1771
	//               move them here.
1772
	if (check_commandline_flag("nosound")) {
1773
		SoundHandler::disable_backend();
1774
	}
1775
	if (check_commandline_flag("fail-on-lua-error")) {
1776
		g_fail_on_lua_error = true;
1777
	}
1778
11221 by The Widelands Bunnybot
Tools for saveloading compatibility testing (CB #4859 / GH #6497)
1779
	if (OptionalParameter msg_timeout = get_commandline_option_value("messagebox-timeout");
1780
	    msg_timeout.has_value()) {
1781
		int64_t t;
1782
		if (!to_long(msg_timeout.value(), &t)) {
1783
			throw ParameterError(
1784
			   CmdLineVerbosity::None,
1785
			   format(_("Non-integer value for command line parameter --messagebox-timeout=%s"),
1786
			          msg_timeout.value()));
1787
		}
1788
		if (t <= 0) {
1789
			throw ParameterError(
1790
			   CmdLineVerbosity::None,
1791
			   ("Value for command line parameter --messagebox-timeout must be positive."));
1792
		}
1793
1794
		g_message_box_timeout = 1000 * t;
1795
		if (g_message_box_timeout / 1000 != t) {
1796
			g_message_box_timeout = 0;
1797
			throw ParameterError(
1798
			   CmdLineVerbosity::None,
1799
			   format(_("Value is out of range for command line parameter --messagebox-timeout=%s"),
1800
			          msg_timeout.value()));
1801
		}
1802
	}
1803
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1804
	// Mutually exclusive options.
1805
	// These would be better as e.g. "--use_zip=[true|false]", but then we'd have to negate the
1806
	// boolean value stored in the string, but trueWords and falseWords are hidden in io/profile.cc.
1807
	// The obvious "--nozip=[true|false]" would be confusing, or at least hard to write a helptext
1808
	// for.
1809
	const bool has_nozip = check_commandline_flag("nozip");
1810
	const bool has_zip = check_commandline_flag("zip");
1811
	if (has_nozip && has_zip) {
1812
		throw_exclusive("nozip", "zip");
1813
	}
1814
	// Only override config file if we have a command line parameter
1815
	if (has_nozip || has_zip) {
1816
		set_config_bool("nozip", has_nozip);
1817
	}
1818
1819
	// *** End of moved checks ***
1820
11221 by The Widelands Bunnybot
Tools for saveloading compatibility testing (CB #4859 / GH #6497)
1821
	if (check_commandline_flag("fail-on-errors")) {
1822
		g_fail_on_errors = true;
1823
	}
1824
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1825
	if (check_commandline_flag("verbose")) {
5142.1.2 by Nicolai Hähnle
Readd molog and editbox changes
1826
		g_verbose = true;
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1827
	}
1828
1829
	static const std::map<GameType, std::string> game_type_options = {
1830
	   {GameType::kEditor, "editor"},
1831
	   {GameType::kReplay, "replay"},
1832
	   {GameType::kFromTemplate, "new_game_from_template"},
1833
	   {GameType::kLoadGame, "loadgame"},
1834
	   {GameType::kScenario, "scenario"}};
1835
1836
	for (const auto& pair : game_type_options) {
1837
		const std::string& opt = pair.second;
1838
		const bool allow_empty = opt == "editor";
1839
		OptionalParameter val = get_commandline_option_value(opt, allow_empty);
1840
		if (!val.has_value()) {
1841
			continue;
1842
		}
1843
1844
		if (game_type_ != GameType::kNone) {
1845
			throw_exclusive(opt, game_type_options.at(game_type_));
1846
		}
1847
		game_type_ = pair.first;
1848
1849
		filename_ = *val;
11071 by The Widelands Bunnybot
Fix out-of-bounds memory access when using `--editor` without filename (CB #4894 / GH #6533)
1850
		if (!filename_.empty() && filename_.back() == '/') {
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1851
			// Strip trailing directory separator
1852
			filename_.erase(filename_.size() - 1);
1853
		}
1854
	}
1855
11221 by The Widelands Bunnybot
Tools for saveloading compatibility testing (CB #4859 / GH #6497)
1856
	if (OptionalParameter difficulty = get_commandline_option_value("difficulty");
1857
	    difficulty.has_value()) {
1858
		if (game_type_ != GameType::kScenario) {
1859
			throw ParameterError(
1860
			   CmdLineVerbosity::None,
1861
			   ("Command line parameter --difficulty can only be used with --scenario=..."));
1862
		}
1863
		int64_t d;
1864
		if (!to_long(difficulty.value(), &d)) {
1865
			throw ParameterError(
1866
			   CmdLineVerbosity::None,
1867
			   format(_("Non-integer value for command line parameter --difficulty=%s"),
1868
			          difficulty.value()));
1869
		}
1870
		if (d <= 0) {
1871
			throw ParameterError(CmdLineVerbosity::None,
1872
			                     ("Value for command line parameter --difficulty must be positive."));
1873
		}
1874
		scenario_difficulty_ = d;
1875
	}
1876
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1877
	if (OptionalParameter val = get_commandline_option_value("script"); val.has_value()) {
1878
		script_to_run_ = *val;
1879
		if (script_to_run_.back() == '/') {
1880
			// Strip trailing directory separator
7737.1.1 by Klaus Halfmann \
Migration from m_... to ..._ mostly in wui
1881
			script_to_run_.erase(script_to_run_.size() - 1);
9386 by The Widelands Bunnybot
Enfore optional braces (#3808)
1882
		}
6689.1.7 by Holger Rapp
Add a --script option to run scripts when loading a game, running a scenario or the editor on the commandline.
1883
	}
1884
8399.1.5 by tiborb95 at gmail
auto_speed swith added
1885
	// Following is used for training of AI
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1886
	set_config_bool("ai_training", check_commandline_flag("ai_training"));
1887
1888
	set_config_bool("auto_speed", check_commandline_flag("auto_speed"));
1889
1890
	if (check_commandline_flag("enable_development_testing_tools")) {
10744 by The Widelands Bunnybot
'src/ui_fsmenu/main.cc' was automatically formatted.
1891
		g_allow_script_console = true;
1892
	}
1893
#ifndef NDEBUG
1894
	// Always enable in debug builds
1895
	g_allow_script_console = true;
1896
#endif
1897
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1898
	if (check_commandline_flag("write_syncstreams")) {
10714 by The Widelands Bunnybot
Options Window Cleanup (#6059)
1899
		g_write_syncstreams = true;
1900
	}
1901
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1902
	if (check_commandline_flag("version")) {
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
1903
		throw ParameterError(CmdLineVerbosity::None);  // No message on purpose
1904
	}
1905
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1906
	if (check_commandline_flag("help-all")) {
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
1907
		throw ParameterError(CmdLineVerbosity::All);  // No message on purpose
1908
	}
1909
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1910
	if (check_commandline_flag("help")) {
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
1911
		throw ParameterError(CmdLineVerbosity::Normal);  // No message on purpose
1912
	}
1913
10898 by The Widelands Bunnybot
Refactor commandline handling (CB #4471 / GH #6154)
1914
	// Window size: three mutually exclusive possibilities
1915
	// TODO(tothxa): Move to a function, but I don't want to add another member.
1916
	//               The whole commandline parsing and handling together with reading the config file
1917
	//               should be moved out of WLApplication, but it's a mess with scattered global
1918
	//               variables and variables that need passing back to WLApplication.
1919
	{
1920
		const bool display_fullscreen = check_commandline_flag("fullscreen");
1921
		const bool display_maximized = check_commandline_flag("maximized");
1922
		if (display_maximized && display_fullscreen) {
1923
			throw_exclusive("fullscreen", "maximized");
1924
		}
1925
1926
		const OptionalParameter xres = get_commandline_option_value("xres");
1927
		const OptionalParameter yres = get_commandline_option_value("yres");
1928
		if ((xres.has_value() || yres.has_value()) && (display_fullscreen || display_maximized)) {
1929
			std::string which_res;
1930
			if (xres.has_value() && yres.has_value()) {
1931
				// "--" will be prepended... ugly here but convenient everywhere else
1932
				which_res = "xres/--yres";
1933
			} else {
1934
				// Exactly one of them
1935
				which_res = xres.has_value() ? "xres" : "yres";
1936
			}
1937
			throw_exclusive(display_fullscreen ? "fullscreen" : "maximized", which_res);
1938
		}
1939
1940
		// Only override config file if we have a command line parameter
1941
		if (xres.has_value() || yres.has_value() || display_fullscreen || display_maximized) {
1942
			set_config_bool("fullscreen", display_fullscreen);
1943
			set_config_bool("maximized", display_maximized);
1944
			if (xres.has_value()) {
1945
				set_config_string("xres", *xres);
1946
			}
1947
			if (yres.has_value()) {
1948
				set_config_string("yres", *yres);
1949
			}
1950
		}
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
1951
	}
1952
7839.10.2 by fios at foramnagaidhlig
Fixed the code. Also, removed a bit of dead code.
1953
	// If it hasn't been handled yet it's probably an attempt to
1954
	// override a conffile setting
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
1955
	for (const auto& pair : commandline_) {
1956
		if (is_parameter(pair.first)) {
1957
			if (!pair.second.empty()) {
1958
				set_config_string(pair.first, pair.second);
1959
			} else {
1960
				throw_empty_value(pair.first);
1961
			}
1962
		} else {
1963
			throw ParameterError(
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
1964
			   CmdLineVerbosity::Normal, format(_("Unknown command line parameter: %s"), pair.first));
9918 by The Widelands Bunnybot
Use shared_ptr for AddOnInfo (#4747)
1965
		}
7507.2.1 by fios at foramnagaidhlig
Fixed bug where localization is not yet initialized when handling command line. Also allows "--language=[ISO-Code] --help". Patch by Miroslav Remák (miroslavr256).
1966
	}
10081 by The Widelands Bunnybot
Fix static initialisation order in unit tests (#5137)
1967
10979 by The Widelands Bunnybot
Replace gettext with tinygettext (CB #4772 / GH #6411)
1968
	if (!found_datadir) {
10081 by The Widelands Bunnybot
Fix static initialisation order in unit tests (#5137)
1969
		throw ParameterError(CmdLineVerbosity::None);  // datadir error already printed
1970
	}
1172 by bedouin
- Move conffile and commandline parsing into WLApplication
1971
}
1972
1179 by bedouin
- WLApplication patch #8/12:
1973
/**
9703 by The Widelands Bunnybot
Main Menu Redesign, Part 4 (#4518)
1974
 * Try to save the game instance if possible
1975
 */
1976
void WLApplication::emergency_save(UI::Panel* panel,
1977
                                   Widelands::Game& game,
1978
                                   const std::string& error,
1979
                                   const uint8_t playernumber,
9822 by The Widelands Bunnybot
Request no bug report for expected disconnects (#4722)
1980
                                   const bool replace_ctrl,
1981
                                   const bool ask_for_bug_report) {
10833 by The Widelands Bunnybot
Fix calling emergency save from GameHost::disconnect_client() (CB #4597 / GH #6258)
1982
	if (!is_initializer_thread()) {
1983
		// We're already handling a bad situation... Let it go as far as it can, but UI calls
1984
		// may violate assertions and segfault.
1985
		log_err("WLApplication::emergency_save() is running in the logic thread!\n");
1986
	}
9703 by The Widelands Bunnybot
Main Menu Redesign, Part 4 (#4518)
1987
	log_err("##############################\n"
9710 by The Widelands Bunnybot
Main Menu Redesign, Part 5 (#4572)
1988
	        "  FATAL EXCEPTION: %s\n"
9822 by The Widelands Bunnybot
Request no bug report for expected disconnects (#4722)
1989
	        "##############################\n",
1990
	        error.c_str());
10506 by The Widelands Bunnybot
Make "Fogless" a Game Setting (#5733)
1991
1992
	if (Widelands::UnhandledVersionError::is_unhandled_version_error(error)) {
1993
		// It's an incompatible savegame. Don't ask for a bug report, don't bother trying to save.
11221 by The Widelands Bunnybot
Tools for saveloading compatibility testing (CB #4859 / GH #6497)
1994
		if (g_fail_on_errors) {
1995
			abort();
1996
		}
10506 by The Widelands Bunnybot
Make "Fogless" a Game Setting (#5733)
1997
		if (panel != nullptr) {
1998
			UI::WLMessageBox m(panel, UI::WindowStyle::kFsMenu, _("Incompatible"), error,
1999
			                   UI::WLMessageBox::MBoxType::kOk);
2000
			m.run<UI::Panel::Returncodes>();
2001
		}
2002
		return;
2003
	}
2004
9822 by The Widelands Bunnybot
Request no bug report for expected disconnects (#4722)
2005
	if (ask_for_bug_report) {
2006
		log_err("  Please report this problem to help us improve Widelands.\n"
2007
		        "  You will find related messages in the standard output (stdout.txt on Windows).\n"
10276 by The Widelands Bunnybot
Reformat version string (remove markdown format) (#5385)
2008
		        "  You are using version %s.\n"
9822 by The Widelands Bunnybot
Request no bug report for expected disconnects (#4722)
2009
		        "  Please add this information to your report.\n",
10276 by The Widelands Bunnybot
Reformat version string (remove markdown format) (#5385)
2010
		        build_ver_details().c_str());
9822 by The Widelands Bunnybot
Request no bug report for expected disconnects (#4722)
2011
	}
11221 by The Widelands Bunnybot
Tools for saveloading compatibility testing (CB #4859 / GH #6497)
2012
	if (g_fail_on_errors) {
2013
		abort();
2014
	}
9822 by The Widelands Bunnybot
Request no bug report for expected disconnects (#4722)
2015
	log_err("  If desired, Widelands attempts to create an emergency savegame.\n"
9703 by The Widelands Bunnybot
Main Menu Redesign, Part 4 (#4518)
2016
	        "  It is often – though not always – possible to load it and continue playing.\n"
9822 by The Widelands Bunnybot
Request no bug report for expected disconnects (#4722)
2017
	        "##############################");
9703 by The Widelands Bunnybot
Main Menu Redesign, Part 4 (#4518)
2018
	if (!game.is_loaded()) {
10506 by The Widelands Bunnybot
Make "Fogless" a Game Setting (#5733)
2019
		if (!ask_for_bug_report || panel == nullptr) {
9822 by The Widelands Bunnybot
Request no bug report for expected disconnects (#4722)
2020
			return;
2021
		}
9710 by The Widelands Bunnybot
Main Menu Redesign, Part 5 (#4572)
2022
		UI::WLMessageBox m(
2023
		   panel, UI::WindowStyle::kFsMenu, _("Error"),
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
2024
		   format(
10061 by The Widelands Bunnybot
Refactor String Assembly / Boost Format (#5081)
2025
		      _("An error has occured. The error message is:\n\n%1$s\n\nPlease report "
2026
		        "this problem to help us improve Widelands. You will find related messages in the "
10276 by The Widelands Bunnybot
Reformat version string (remove markdown format) (#5385)
2027
		        "standard output (stdout.txt on Windows). You are using version %2$s.\n"
2028
		        "Please add this information to your report."),
2029
		      error, build_ver_details()),
9710 by The Widelands Bunnybot
Main Menu Redesign, Part 5 (#4572)
2030
		   UI::WLMessageBox::MBoxType::kOk);
2031
		m.run<UI::Panel::Returncodes>();
9620 by The Widelands Bunnybot
Clear readability-non-const-parameter (#4434)
2032
		return;
2033
	}
2034
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
2035
	if (panel != nullptr) {
9703 by The Widelands Bunnybot
Main Menu Redesign, Part 4 (#4518)
2036
		UI::WLMessageBox m(
9822 by The Widelands Bunnybot
Request no bug report for expected disconnects (#4722)
2037
		   panel, UI::WindowStyle::kFsMenu,
2038
		   ask_for_bug_report ? _("Unexpected error during the game") : _("Game ended unexpectedly"),
2039
		   ask_for_bug_report ?
11093 by The Widelands Bunnybot
170 files were automatically formatted.
2040
		      format(
10061 by The Widelands Bunnybot
Refactor String Assembly / Boost Format (#5081)
2041
		         _("An error occured during the game. The error message is:\n\n%1$s\n\nPlease report "
2042
		           "this problem to help us improve Widelands. You will find related messages in the "
10276 by The Widelands Bunnybot
Reformat version string (remove markdown format) (#5385)
2043
		           "standard output (stdout.txt on Windows). You are using version %2$s.\n\n"
2044
		           "Please add this information to your report.\n\nWould you like "
10061 by The Widelands Bunnybot
Refactor String Assembly / Boost Format (#5081)
2045
		           "Widelands "
2046
		           "to attempt to create an emergency savegame? It is often – though not always – "
2047
		           "possible to load it and continue playing."),
10276 by The Widelands Bunnybot
Reformat version string (remove markdown format) (#5385)
2048
		         error, build_ver_details()) :
11093 by The Widelands Bunnybot
170 files were automatically formatted.
2049
		      format(
10061 by The Widelands Bunnybot
Refactor String Assembly / Boost Format (#5081)
2050
		         _("The game ended unexpectedly for the following reason:\n\n%s\n\nWould you like "
2051
		           "Widelands to attempt to create an emergency savegame? It is often – though not "
2052
		           "always – possible to load it and continue playing."),
2053
		         error),
9703 by The Widelands Bunnybot
Main Menu Redesign, Part 4 (#4518)
2054
		   UI::WLMessageBox::MBoxType::kOkCancel);
9593 by The Widelands Bunnybot
Random matches & Editor launching convenience (#4289)
2055
		if (m.run<UI::Panel::Returncodes>() != UI::Panel::Returncodes::kOk) {
9703 by The Widelands Bunnybot
Main Menu Redesign, Part 4 (#4518)
2056
			return;
2057
		}
2058
	}
2059
10739 by The Widelands Bunnybot
Emergency saving enhancements (#6108)
2060
	bool added_loader = false;
9703 by The Widelands Bunnybot
Main Menu Redesign, Part 4 (#4518)
2061
	try {
10739 by The Widelands Bunnybot
Emergency saving enhancements (#6108)
2062
		if (!game.has_loader_ui()) {
2063
			// Shouldn't have one yet, but in an emergency situation, don't make any assumptions.
2064
			game.create_loader_ui(
2065
			   {"crash"}, true, game.map().get_background_theme(), game.map().get_background(), true);
2066
			added_loader = true;
2067
		}
2068
9703 by The Widelands Bunnybot
Main Menu Redesign, Part 4 (#4518)
2069
		if (replace_ctrl) {
9923 by The Widelands Bunnybot
Fetched translations and updated catalogs.
2070
			game.set_game_controller(
2071
			   std::make_shared<SinglePlayerGameController>(game, true, playernumber));
9703 by The Widelands Bunnybot
Main Menu Redesign, Part 4 (#4518)
2072
		}
2073
2074
		SaveHandler& save_handler = game.save_handler();
2075
		std::string e;
2076
		if (!save_handler.save_game(
10493 by The Widelands Bunnybot
Indicate soldier preference in milsite stats string (#5730)
2077
		       game, save_handler.create_file_name(kSaveDir, timestring()), FileSystem::ZIP, &e)) {
9703 by The Widelands Bunnybot
Main Menu Redesign, Part 4 (#4518)
2078
			throw wexception("Save handler returned error: %s", e.c_str());
2079
		}
2080
	} catch (const std::exception& e) {
2081
		log_err("Emergency save failed because: %s", e.what());
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
2082
		if (panel != nullptr) {
9703 by The Widelands Bunnybot
Main Menu Redesign, Part 4 (#4518)
2083
			UI::WLMessageBox m(
2084
			   panel, UI::WindowStyle::kFsMenu, _("Emergency save failed"),
10108 by The Widelands Bunnybot
Rename `bformat` → `format` (#5163)
2085
			   format(_("We are sorry, but Widelands was unable to create an emergency "
2086
			            "savegame for the following reason:\n\n%s"),
2087
			          e.what()),
9703 by The Widelands Bunnybot
Main Menu Redesign, Part 4 (#4518)
2088
			   UI::WLMessageBox::MBoxType::kOk);
2089
			m.run<UI::Panel::Returncodes>();
2319 by knutux
- Emergency save - automatic game saving if exception occurs (should help diagnosing crashes in some cases)
2090
		}
2091
	}
10739 by The Widelands Bunnybot
Emergency saving enhancements (#6108)
2092
2093
	if (added_loader) {
2094
		game.remove_loader_ui();
2095
	}
2319 by knutux
- Emergency save - automatic game saving if exception occurs (should help diagnosing crashes in some cases)
2096
}
4691 by nasenbaer_peter
Two patches by Timo:
2097
2098
/**
8895.5.2 by artydent
compliance to style guide
2099
 * Delete old syncstream (.wss) files in the replay directory on startup
4691 by nasenbaer_peter
Two patches by Timo:
2100
 * Delete old replay files on startup
2101
 */
8048 by GunChleoc
Ran clang-format.
2102
void WLApplication::cleanup_replays() {
10473 by The Widelands Bunnybot
Replays: Single-File, Optional Writing, Autodeleting (#5645)
2103
	const int64_t keep_seconds =
2104
	   7LL * 24 * 60 * 60 * get_config_section().get_int("replay_lifetime", 0);
2105
	if (keep_seconds <= 0) {
2106
		return;
2107
	}
9129 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/list-directories-in-cpp:
2108
	for (const std::string& filename : g_fs->filter_directory(kReplayDir, [](const std::string& fn) {
10473 by The Widelands Bunnybot
Replays: Single-File, Optional Writing, Autodeleting (#5645)
2109
		     return ends_with(fn, kReplayExtension) ||
2110
		            ends_with(fn, kSyncstreamExtension)
2111
		            // TODO(Nordfriese): Remove the legacy extensions after v1.2
2112
		            || ends_with(fn, ".wrpl") || ends_with(fn, ".wrpl.wgf");
9365 by The Widelands Bunnybot
Use Ubuntu 20.04 for code formatting (#3946)
2113
	     })) {
10473 by The Widelands Bunnybot
Replays: Single-File, Optional Writing, Autodeleting (#5645)
2114
		if (is_autogenerated_and_expired(filename, keep_seconds)) {
2115
			log_info("Deleting syncstream or replay %s", filename.c_str());
8895.5.1 by artydent
Added a GenericSaveHandler class to handle saving:
2116
			try {
2117
				g_fs->fs_unlink(filename);
2118
			} catch (const FileError& e) {
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
2119
				log_warn("WLApplication::cleanup_replays: File %s couldn't be deleted: %s\n",
2120
				         filename.c_str(), e.what());
8895.5.1 by artydent
Added a GenericSaveHandler class to handle saving:
2121
			}
4691 by nasenbaer_peter
Two patches by Timo:
2122
		}
2123
	}
2124
}
5502 by Jari Hautio
Implemented support for redirecting stdio from widelands to files. Redirection is enabled if REDIRECT_STDIO is defined at compile time (enabled for MSVC builds). This allows windows version to write logs to home folder if executable folder is not writable (program files folder under Vista nd Win7). Fixes bug #625979.
2125
8400.1.5 by tiborb95 at gmail
building overdue stuff modified a bit
2126
/**
8400.1.12 by tiborb95 at gmail
code polish
2127
 * Delete old ai dna files generated during AI initialization
8400.1.5 by tiborb95 at gmail
building overdue stuff modified a bit
2128
 */
2129
void WLApplication::cleanup_ai_files() {
9129 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/list-directories-in-cpp:
2130
	for (const std::string& filename : g_fs->filter_directory(kAiDir, [](const std::string& fn) {
10060 by The Widelands Bunnybot
Deprecate Boost (#5101)
2131
		     return ends_with(fn, kAiExtension) || contains(fn, "ai_player");
9365 by The Widelands Bunnybot
Use Ubuntu 20.04 for code formatting (#3946)
2132
	     })) {
8400.1.7 by tiborb95 at gmail
changes mainly in regard to wells
2133
		if (is_autogenerated_and_expired(filename, kAIFilesKeepAroundTime)) {
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
2134
			log_info("Deleting generated ai file: %s\n", filename.c_str());
8895.5.1 by artydent
Added a GenericSaveHandler class to handle saving:
2135
			try {
2136
				g_fs->fs_unlink(filename);
2137
			} catch (const FileError& e) {
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
2138
				log_warn("WLApplication::cleanup_ai_files: File %s couldn't be deleted: %s\n",
2139
				         filename.c_str(), e.what());
8895.5.1 by artydent
Added a GenericSaveHandler class to handle saving:
2140
			}
8400.1.5 by tiborb95 at gmail
building overdue stuff modified a bit
2141
		}
2142
	}
2143
}
2144
8895.2.1 by artydent
Whenever a map is fully loaded (editor/game/replay) the map is immediately saved to a temp file and the map's filesystem is reassigned to that temp file in a special directory. So when map/save files are handled anywhere, there won't be any filesystem conflicts with or even accidentally deletion of the map filesystem (which would lead to corrupt save files later).
2145
/**
2146
 * Delete old temp files that might still lurk around (game crashes etc.)
2147
 */
2148
void WLApplication::cleanup_temp_files() {
10493 by The Widelands Bunnybot
Indicate soldier preference in milsite stats string (#5730)
2149
	for (const std::string& filename : g_fs->list_directory(kTempFileDir)) {
8895.2.1 by artydent
Whenever a map is fully loaded (editor/game/replay) the map is immediately saved to a temp file and the map's filesystem is reassigned to that temp file in a special directory. So when map/save files are handled anywhere, there won't be any filesystem conflicts with or even accidentally deletion of the map filesystem (which would lead to corrupt save files later).
2150
		if (is_autogenerated_and_expired(filename, kTempFilesKeepAroundTime)) {
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
2151
			log_info("Deleting old temp file: %s\n", filename.c_str());
8895.5.1 by artydent
Added a GenericSaveHandler class to handle saving:
2152
			try {
2153
				g_fs->fs_unlink(filename);
2154
			} catch (const FileError& e) {
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
2155
				log_warn("WLApplication::cleanup_temp_files: File %s couldn't be deleted: %s\n",
2156
				         filename.c_str(), e.what());
8895.5.1 by artydent
Added a GenericSaveHandler class to handle saving:
2157
			}
2158
		}
2159
	}
2160
}
2161
2162
/**
2163
 * Recursively delete temporary backup files in a given directory
2164
 */
9393 by The Widelands Bunnybot
Improve performance with clang-tidy (#4025)
2165
void WLApplication::cleanup_temp_backups(const std::string& dir) {
9129 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/list-directories-in-cpp:
2166
	for (const std::string& filename : g_fs->filter_directory(
10060 by The Widelands Bunnybot
Deprecate Boost (#5101)
2167
	        dir, [](const std::string& fn) { return ends_with(fn, kTempBackupExtension); })) {
8895.5.1 by artydent
Added a GenericSaveHandler class to handle saving:
2168
		if (is_autogenerated_and_expired(filename, kTempBackupsKeepAroundTime)) {
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
2169
			log_info("Deleting old temp backup file: %s\n", filename.c_str());
8895.5.1 by artydent
Added a GenericSaveHandler class to handle saving:
2170
			try {
2171
				g_fs->fs_unlink(filename);
2172
			} catch (const FileError& e) {
9485 by The Widelands Bunnybot
Refactor log() output (#4162)
2173
				log_warn("WLApplication::cleanup_temp_backups: File %s couldn't be deleted: %s\n",
2174
				         filename.c_str(), e.what());
8895.5.1 by artydent
Added a GenericSaveHandler class to handle saving:
2175
			}
2176
		}
2177
	}
2178
	// recursively delete in subdirs
8646.6.2 by GunChleoc
Moved filter function to FileSystem.
2179
	for (const std::string& dirname : g_fs->filter_directory(dir, [](const std::string& fn) {
8895.5.1 by artydent
Added a GenericSaveHandler class to handle saving:
2180
		     return g_fs->is_directory(fn) &&
8987 by Wideland's Bunnybot
Merged lp:~widelands-dev/widelands/robust-file-saving:
2181
		            // avoid searching within savegames/maps/backups that were created
2182
		            // as directories instead of zipfiles
10060 by The Widelands Bunnybot
Deprecate Boost (#5101)
2183
		            !ends_with(fn, kSavegameExtension) && !ends_with(fn, kWidelandsMapExtension) &&
2184
		            !ends_with(fn, kTempBackupExtension);
9365 by The Widelands Bunnybot
Use Ubuntu 20.04 for code formatting (#3946)
2185
	     })) {
8895.5.1 by artydent
Added a GenericSaveHandler class to handle saving:
2186
		cleanup_temp_backups(dirname);
2187
	}
2188
}
2189
2190
/**
2191
 * Delete old temporary backup files that might still lurk around (game crashes etc.)
2192
 */
2193
void WLApplication::cleanup_temp_backups() {
2194
	cleanup_temp_backups(kSaveDir);
2195
	cleanup_temp_backups(kMapsDir);
8895.2.1 by artydent
Whenever a map is fully loaded (editor/game/replay) the map is immediately saved to a temp file and the map's filesystem is reassigned to that temp file in a special directory. So when map/save files are handled anywhere, there won't be any filesystem conflicts with or even accidentally deletion of the map filesystem (which would lead to corrupt save files later).
2196
}
2197
8048 by GunChleoc
Ran clang-format.
2198
bool WLApplication::redirect_output(std::string path) {
5502 by Jari Hautio
Implemented support for redirecting stdio from widelands to files. Redirection is enabled if REDIRECT_STDIO is defined at compile time (enabled for MSVC builds). This allows windows version to write logs to home folder if executable folder is not writable (program files folder under Vista nd Win7). Fixes bug #625979.
2199
	if (path.empty()) {
6640 by Holger Rapp
Use _WIN32 everywhere to check for windows compilation.
2200
#ifdef _WIN32
5502 by Jari Hautio
Implemented support for redirecting stdio from widelands to files. Redirection is enabled if REDIRECT_STDIO is defined at compile time (enabled for MSVC builds). This allows windows version to write logs to home folder if executable folder is not writable (program files folder under Vista nd Win7). Fixes bug #625979.
2201
		char module_name[MAX_PATH];
7162.2.6 by Hans Joachim Desserud
Removed unused variable, though left the method call in place
2202
		GetModuleFileName(nullptr, module_name, MAX_PATH);
5502 by Jari Hautio
Implemented support for redirecting stdio from widelands to files. Redirection is enabled if REDIRECT_STDIO is defined at compile time (enabled for MSVC builds). This allows windows version to write logs to home folder if executable folder is not writable (program files folder under Vista nd Win7). Fixes bug #625979.
2203
		path = module_name;
2204
		size_t pos = path.find_last_of("/\\");
9386 by The Widelands Bunnybot
Enfore optional braces (#3808)
2205
		if (pos == std::string::npos) {
8048 by GunChleoc
Ran clang-format.
2206
			return false;
9386 by The Widelands Bunnybot
Enfore optional braces (#3808)
2207
		}
5502 by Jari Hautio
Implemented support for redirecting stdio from widelands to files. Redirection is enabled if REDIRECT_STDIO is defined at compile time (enabled for MSVC builds). This allows windows version to write logs to home folder if executable folder is not writable (program files folder under Vista nd Win7). Fixes bug #625979.
2208
		path.resize(pos);
2209
#else
2210
		path = ".";
2211
#endif
2212
	}
2213
	std::string stdoutfile = path + "/stdout.txt";
2214
	/* Redirect standard output */
8048 by GunChleoc
Ran clang-format.
2215
	FILE* newfp = freopen(stdoutfile.c_str(), "w", stdout);
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
2216
	if (newfp == nullptr) {
8048 by GunChleoc
Ran clang-format.
2217
		return false;
9386 by The Widelands Bunnybot
Enfore optional braces (#3808)
2218
	}
5502 by Jari Hautio
Implemented support for redirecting stdio from widelands to files. Redirection is enabled if REDIRECT_STDIO is defined at compile time (enabled for MSVC builds). This allows windows version to write logs to home folder if executable folder is not writable (program files folder under Vista nd Win7). Fixes bug #625979.
2219
	/* Redirect standard error */
2220
	std::string stderrfile = path + "/stderr.txt";
6389.1.1 by Borim
add missing check when redirect stderr
2221
	newfp = freopen(stderrfile.c_str(), "w", stderr);
10247 by The Widelands Bunnybot
Fix Sound Options Panel Styling (#5372)
2222
	if (newfp == nullptr) {
8048 by GunChleoc
Ran clang-format.
2223
		return false;
9386 by The Widelands Bunnybot
Enfore optional braces (#3808)
2224
	}
5502 by Jari Hautio
Implemented support for redirecting stdio from widelands to files. Redirection is enabled if REDIRECT_STDIO is defined at compile time (enabled for MSVC builds). This allows windows version to write logs to home folder if executable folder is not writable (program files folder under Vista nd Win7). Fixes bug #625979.
2225
5747 by Holger Rapp
Reverted revision 5744 as it broke automatic lua documentation creation
2226
	/* Line buffered */
6647 by Holger Rapp
Replaced NULL through typesafe c++11 nullptr.
2227
	setvbuf(stdout, nullptr, _IOLBF, BUFSIZ);
5747 by Holger Rapp
Reverted revision 5744 as it broke automatic lua documentation creation
2228
2229
	/* No buffering */
11206 by The Widelands Bunnybot
Fix or categorize new checks in clang-tidy-19 (CB #5011 / GH #6651)
2230
	setbuf(stderr, nullptr);  // NOLINT(bugprone-unsafe-functions)
5502 by Jari Hautio
Implemented support for redirecting stdio from widelands to files. Redirection is enabled if REDIRECT_STDIO is defined at compile time (enabled for MSVC builds). This allows windows version to write logs to home folder if executable folder is not writable (program files folder under Vista nd Win7). Fixes bug #625979.
2231
7737.1.1 by Klaus Halfmann \
Migration from m_... to ..._ mostly in wui
2232
	redirected_stdio_ = true;
5502 by Jari Hautio
Implemented support for redirecting stdio from widelands to files. Redirection is enabled if REDIRECT_STDIO is defined at compile time (enabled for MSVC builds). This allows windows version to write logs to home folder if executable folder is not writable (program files folder under Vista nd Win7). Fixes bug #625979.
2233
	return true;
4917.11.50 by Holger Rapp
Moved wl.map.create_immovable to wl.Map.place_immovable. Place is more consistent with place_road, place_flag and place_building
2234
}
10738 by The Widelands Bunnybot
Self-diagnose crashes (#6100)
2235
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
2236
void WLApplication::check_crash_reports(FsMenu::MainMenu& menu) {
10738 by The Widelands Bunnybot
Self-diagnose crashes (#6100)
2237
	// First, delete very old crash reports
2238
	for (const std::string& filename : g_fs->filter_directory(
2239
	        kCrashDir, [](const std::string& fn) { return ends_with(fn, kOldCrashExtension); })) {
2240
		if (is_autogenerated_and_expired(filename, kCrashFilesKeepAroundTime)) {
2241
			log_info("Deleting stale crash file: %s\n", filename.c_str());
2242
			try {
2243
				g_fs->fs_unlink(filename);
2244
			} catch (const FileError& e) {
2245
				log_warn("WLApplication::check_crash_reports: File %s couldn't be deleted: %s\n",
2246
				         filename.c_str(), e.what());
2247
			}
2248
		}
2249
	}
2250
2251
	// Now look for new, unreported crashes
2252
	FilenameSet crashes = g_fs->filter_directory(
2253
	   kCrashDir, [](const std::string& fn) { return ends_with(fn, kCrashExtension); });
2254
	if (crashes.empty()) {
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
2255
		return;
10738 by The Widelands Bunnybot
Self-diagnose crashes (#6100)
2256
	}
2257
2258
	log_info("Found %" PRIuS " unsent crash reports.\nPlease consider submitting them to the "
2259
	         "Widelands Development Team under %s",
2260
	         crashes.size(), FsMenu::CrashReportWindow::kReportBugsURL);
2261
	for (const std::string& filename : crashes) {
2262
		log_info("- %s", filename.c_str());
2263
	}
2264
10892 by The Widelands Bunnybot
Allow loading last savegame/replay/edited map from the command line (CB #4470 / GH #6153)
2265
	menu.abort_splashscreen();
2266
	FsMenu::CrashReportWindow reporter(menu, crashes);
10738 by The Widelands Bunnybot
Self-diagnose crashes (#6100)
2267
	reporter.run<UI::Panel::Returncodes>();
2268
}