• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Return-To-The-Roots / s25client / 18856213349

27 Oct 2025 09:18PM UTC coverage: 50.471% (-0.02%) from 50.491%
18856213349

Pull #1804

github

web-flow
Merge 1556dcccf into 2d6849772
Pull Request #1804: Android build

75 of 242 new or added lines in 14 files covered. (30.99%)

3 existing lines in 3 files now uncovered.

22552 of 44683 relevant lines covered (50.47%)

35157.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

21.61
/libs/s25main/Settings.cpp
1
// Copyright (C) 2005 - 2021 Settlers Freaks (sf-team at siedler25.org)
2
//
3
// SPDX-License-Identifier: GPL-2.0-or-later
4

5
#include "Settings.h"
6
#include "DrawPoint.h"
7
#include "RTTR_Version.h"
8
#include "RttrConfig.h"
9
#include "drivers/AudioDriverWrapper.h"
10
#include "drivers/VideoDriverWrapper.h"
11
#include "files.h"
12
#include "helpers/strUtils.h"
13
#include "languages.h"
14
#include "gameData/PortraitConsts.h"
15
#include "gameData/const_gui_ids.h"
16
#include "libsiedler2/ArchivItem_Ini.h"
17
#include "libsiedler2/ArchivItem_Text.h"
18
#include "libsiedler2/libsiedler2.h"
19
#include "s25util/StringConversion.h"
20
#include "s25util/System.h"
21
#include "s25util/error.h"
22
#include <boost/filesystem/operations.hpp>
23

24
namespace {
25
#ifdef __ANDROID__
26
constexpr bool SHARED_TEXTURES_DEFAULT = false;
27
constexpr MapScrollMode MAP_SCROLL_MODE_DEFAULT = MapScrollMode::GrabAndDrag;
28
#else
29
constexpr bool SHARED_TEXTURES_DEFAULT = true;
30
constexpr MapScrollMode MAP_SCROLL_MODE_DEFAULT = MapScrollMode::ScrollOpposite;
31
#endif
32
} // namespace
33

34
const int Settings::VERSION = 13;
35
const std::array<std::string, 10> Settings::SECTION_NAMES = {
36
  {"global", "video", "language", "driver", "sound", "lobby", "server", "proxy", "interface", "addons"}};
37

38
const std::array<short, 13> Settings::SCREEN_REFRESH_RATES = {
39
  {-1, 25, 30, 50, 60, 75, 80, 100, 120, 150, 180, 200, 240}};
40

41
const std::map<GUI_ID, std::string> persistentWindows = {{CGI_CHAT, "wnd_chat"},
42
                                                         {CGI_POSTOFFICE, "wnd_postoffice"},
43
                                                         {CGI_DISTRIBUTION, "wnd_distribution"},
44
                                                         {CGI_BUILDORDER, "wnd_buildorder"},
45
                                                         {CGI_TRANSPORT, "wnd_transport"},
46
                                                         {CGI_MILITARY, "wnd_military"},
47
                                                         {CGI_TOOLS, "wnd_tools"},
48
                                                         {CGI_INVENTORY, "wnd_inventory"},
49
                                                         {CGI_MINIMAP, "wnd_minimap"},
50
                                                         {CGI_BUILDINGS, "wnd_buildings"},
51
                                                         {CGI_BUILDINGSPRODUCTIVITY, "wnd_buildingsproductivity"},
52
                                                         {CGI_MUSICPLAYER, "wnd_musicplayer"},
53
                                                         {CGI_STATISTICS, "wnd_statistics"},
54
                                                         {CGI_ECONOMICPROGRESS, "wnd_economicprogress"},
55
                                                         {CGI_DIPLOMACY, "wnd_diplomacy"},
56
                                                         {CGI_SHIP, "wnd_ship"},
57
                                                         {CGI_MERCHANDISE_STATISTICS, "wnd_merchandise_statistics"}};
58

59
namespace validate {
60
boost::optional<uint16_t> checkPort(const std::string& port)
9✔
61
{
62
    int32_t iPort;
63
    if((helpers::tryFromString(port, iPort) || s25util::tryFromStringClassic(port, iPort)) && checkPort(iPort))
9✔
64
        return static_cast<uint16_t>(iPort);
3✔
65
    else
66
        return boost::none;
6✔
67
}
68
bool checkPort(int port)
7✔
69
{
70
    // Disallow port 0 as it may cause problems
71
    return port > 0 && port <= 65535;
7✔
72
}
73
} // namespace validate
74

75
Settings::Settings() //-V730
5✔
76
{
77
    LoadDefaults();
5✔
78
}
5✔
79

80
void Settings::LoadDefaults()
5✔
81
{
82
    // global
83
    // {
84
    // 0 = ask user at start, 1 = enabled, 2 = always ask
85
    global.submit_debug_data = 0;
5✔
86
    global.use_upnp = false;
5✔
87
    global.smartCursor = true;
5✔
88
    global.debugMode = false;
5✔
89
    global.showGFInfo = false;
5✔
90
    // }
91

92
    // video
93
    // {
94
    if(VIDEODRIVER.IsLoaded())
5✔
95
    {
96
        video.fullscreenSize = VIDEODRIVER.GetWindowSize();
3✔
97
        video.windowedSize = VIDEODRIVER.IsFullscreen() ? VideoMode(800, 600) : video.fullscreenSize;
3✔
98
        video.fullscreen = VIDEODRIVER.IsFullscreen();
3✔
99
    } else
100
    {
101
        video.windowedSize = video.fullscreenSize = VideoMode(800, 600);
2✔
102
        video.fullscreen = false;
2✔
103
    }
104
    video.framerate = 0; // Special value for HW vsync
5✔
105
    video.vbo = true;
5✔
106
    video.shared_textures = SHARED_TEXTURES_DEFAULT;
5✔
107
    video.guiScale = 0; // special value indicating automatic selection
5✔
108
    // }
109

110
    // language
111
    // {
112
    language.language.clear();
5✔
113
    // }
114

115
    LANGUAGES.setLanguage(language.language);
5✔
116

117
    // driver
118
    // {
119
    driver.audio = AUDIODRIVER.GetName();
5✔
120
    driver.video = VIDEODRIVER.GetName();
5✔
121
    // }
122

123
    // sound
124
    // {
125
    sound.musicEnabled = false;
5✔
126
    sound.musicVolume = 30;
5✔
127
    sound.effectsEnabled = true;
5✔
128
    sound.effectsVolume = 75;
5✔
129
    sound.playlist = s25::files::defaultPlaylist;
5✔
130
    // }
131

132
    // lobby
133
    // {
134

135
    lobby.name = System::getUserName();
5✔
136
    lobby.portraitIndex = 0;
5✔
137
    lobby.password.clear();
5✔
138
    lobby.save_password = false;
5✔
139
    // }
140

141
    // server
142
    // {
143
    server.last_ip.clear();
5✔
144
    server.localPort = 3665;
5✔
145
    server.ipv6 = false;
5✔
146
    // }
147

148
    proxy = ProxySettings();
5✔
149
    proxy.port = 1080;
5✔
150

151
    // interface
152
    // {
153
    interface.autosave_interval = 0;
5✔
154
    interface.mapScrollMode = MAP_SCROLL_MODE_DEFAULT;
5✔
155
    interface.enableWindowPinning = false;
5✔
156
    interface.windowSnapDistance = 8;
5✔
157
    // }
158

159
    // addons
160
    // {
161
    addons.configuration.clear();
5✔
162
    // }
163

164
    LoadIngameDefaults();
5✔
165
}
5✔
166

167
void Settings::LoadIngameDefaults()
5✔
168
{
169
    // ingame
170
    // {
171
    ingame.scale_statistics = false;
5✔
172
    ingame.showBQ = false;
5✔
173
    ingame.showNames = false;
5✔
174
    ingame.showProductivity = false;
5✔
175
    ingame.minimapExtended = false;
5✔
176
    // }
177

178
    // windows
179
    // {
180
    for(const auto& window : persistentWindows)
90✔
181
        windows.persistentSettings[window.first] = PersistentWindowSettings();
85✔
182
    // }
183
}
5✔
184

185
///////////////////////////////////////////////////////////////////////////////
186
// Routine zum Laden der Konfiguration
187
void Settings::Load()
×
188
{
189
    libsiedler2::Archiv settings;
×
190
    const auto settingsPath = RTTRCONFIG.ExpandPath(s25::resources::config);
×
191
    try
192
    {
193
        if(libsiedler2::Load(settingsPath, settings) != 0 || settings.size() < SECTION_NAMES.size())
×
194
            throw std::runtime_error("File missing or invalid");
×
195

196
        const libsiedler2::ArchivItem_Ini* iniGlobal =
197
          static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("global"));
×
198
        const libsiedler2::ArchivItem_Ini* iniVideo = static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("video"));
×
199
        const libsiedler2::ArchivItem_Ini* iniLanguage =
200
          static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("language"));
×
201
        const libsiedler2::ArchivItem_Ini* iniDriver =
202
          static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("driver"));
×
203
        const libsiedler2::ArchivItem_Ini* iniSound = static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("sound"));
×
204
        const libsiedler2::ArchivItem_Ini* iniLobby = static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("lobby"));
×
205
        const libsiedler2::ArchivItem_Ini* iniServer =
206
          static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("server"));
×
207
        const libsiedler2::ArchivItem_Ini* iniProxy = static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("proxy"));
×
208
        const libsiedler2::ArchivItem_Ini* iniInterface =
209
          static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("interface"));
×
210
        const libsiedler2::ArchivItem_Ini* iniAddons =
211
          static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("addons"));
×
212

213
        // ist eine der Kategorien nicht vorhanden?
214
        if(!iniGlobal || !iniVideo || !iniLanguage || !iniDriver || !iniSound || !iniLobby || !iniServer || !iniProxy
×
215
           || !iniInterface || !iniAddons)
×
216
        {
217
            throw std::runtime_error("Missing section");
×
218
        }
219
        // stimmt die Settingsversion?
220
        if(iniGlobal->getValue("version", 0) != VERSION)
×
221
            throw std::runtime_error("Wrong version");
×
222

223
        // global
224
        // {
225
        if(iniGlobal->getValue("gameversion") != rttr::version::GetRevision())
×
226
            s25util::warning("Your application version has changed - please recheck your settings!");
×
227

228
        global.submit_debug_data = iniGlobal->getIntValue("submit_debug_data");
×
229
        global.use_upnp = iniGlobal->getBoolValue("use_upnp");
×
230
        global.smartCursor = iniGlobal->getValue("smartCursor", true);
×
231
        global.debugMode = iniGlobal->getValue("debugMode", false);
×
232
        global.showGFInfo = iniGlobal->getValue("showGFInfo", false);
×
233
        // };
234

235
        // video
236
        // {
237
        video.windowedSize.width = iniVideo->getIntValue("windowed_width");
×
238
        video.windowedSize.height = iniVideo->getIntValue("windowed_height");
×
239
        video.fullscreenSize.width = iniVideo->getIntValue("fullscreen_width");
×
240
        video.fullscreenSize.height = iniVideo->getIntValue("fullscreen_height");
×
241
        video.fullscreen = iniVideo->getBoolValue("fullscreen");
×
242
        video.framerate = iniVideo->getValue("framerate", 0);
×
243
        video.vbo = iniVideo->getBoolValue("vbo");
×
244
        video.shared_textures = iniVideo->getBoolValue("shared_textures");
×
245
        video.guiScale = iniVideo->getValue("gui_scale", 0);
×
246
        // };
247

248
        if(video.fullscreenSize.width == 0 || video.fullscreenSize.height == 0 || video.windowedSize.width == 0
×
249
           || video.windowedSize.height == 0)
×
250
            throw std::runtime_error("Invalid video settings");
×
251

252
        // language
253
        // {
254
        language.language = iniLanguage->getValue("language");
×
255
        // }
256

257
        LANGUAGES.setLanguage(language.language);
×
258

259
        // driver
260
        // {
261
        driver.video = iniDriver->getValue("video");
×
262
        driver.audio = iniDriver->getValue("audio");
×
263
        // }
264

265
        // sound
266
        // {
267
        sound.musicEnabled = iniSound->getBoolValue("musik");
×
268
        sound.musicVolume = iniSound->getIntValue("musik_volume");
×
269
        sound.effectsEnabled = iniSound->getBoolValue("effekte");
×
270
        sound.effectsVolume = iniSound->getIntValue("effekte_volume");
×
271
        sound.playlist = iniSound->getValue("playlist");
×
272
        // }
273

274
        // lobby
275
        // {
276
        lobby.name = iniLobby->getValue("name");
×
277
        lobby.portraitIndex = iniLobby->getIntValue("portrait_index");
×
278
        lobby.password = iniLobby->getValue("password");
×
279
        lobby.save_password = iniLobby->getBoolValue("save_password");
×
280
        // }
281

282
        if(lobby.name.empty())
×
283
            lobby.name = System::getUserName();
×
284

285
        if(lobby.portraitIndex >= Portraits.size())
×
286
        {
287
            lobby.portraitIndex = 0;
×
288
        }
289

290
        // server
291
        // {
292
        server.last_ip = iniServer->getValue("last_ip");
×
293
        boost::optional<uint16_t> port = validate::checkPort(iniServer->getValue("local_port"));
×
294
        server.localPort = port.value_or(3665);
×
295
        server.ipv6 = iniServer->getBoolValue("ipv6");
×
296
        // }
297

298
        // proxy
299
        // {
300
        proxy.hostname = iniProxy->getValue("proxy");
×
301
        port = validate::checkPort(iniProxy->getValue("port"));
×
302
        proxy.port = port.value_or(1080);
×
303
        proxy.type = ProxyType(iniProxy->getIntValue("typ"));
×
304
        // }
305

306
        // leere proxyadresse deaktiviert proxy komplett
307
        // deaktivierter proxy entfernt proxyadresse
308
        if(proxy.hostname.empty() || (proxy.type != ProxyType::Socks4 && proxy.type != ProxyType::Socks5))
×
309
        {
310
            proxy.type = ProxyType::None;
×
311
            proxy.hostname.clear();
×
312
        }
313
        // aktivierter Socks v4 deaktiviert ipv6
314
        else if(proxy.type == ProxyType::Socks4 && server.ipv6)
×
315
            server.ipv6 = false;
×
316

317
        // interface
318
        // {
319
        interface.autosave_interval = iniInterface->getIntValue("autosave_interval");
×
320
        try
321
        {
NEW
322
            interface.mapScrollMode = static_cast<MapScrollMode>(iniInterface->getIntValue("map_scroll_mode"));
×
NEW
323
        } catch(const std::runtime_error&)
×
324
        {
NEW
325
            interface.mapScrollMode =
×
NEW
326
              iniInterface->getBoolValue("invert_mouse") ? MapScrollMode::ScrollSame : MapScrollMode::ScrollOpposite;
×
NEW
327
            s25util::warning(
×
328
              "Value 'map_scroll_mode' not found! Using 'invert_mouse' instead - please recheck your settings!");
329
        }
330
        interface.enableWindowPinning = iniInterface->getValue("enable_window_pinning", false);
×
331
        interface.windowSnapDistance = iniInterface->getValue("window_snap_distance", 8);
×
332
        // }
333

334
        // addons
335
        // {
336
        for(unsigned addon = 0; addon < iniAddons->size(); ++addon)
×
337
        {
338
            const auto* item = dynamic_cast<const libsiedler2::ArchivItem_Text*>(iniAddons->get(addon));
×
339

340
            if(item)
×
341
                addons.configuration.insert(std::make_pair(s25util::fromStringClassic<unsigned>(item->getName()),
×
342
                                                           s25util::fromStringClassic<unsigned>(item->getText())));
×
343
        }
344

345
        LoadIngame();
×
346
        // }
347
    } catch(const std::runtime_error& e)
×
348
    {
349
        s25util::warning(std::string("Could not use settings from \"") + settingsPath.string()
×
350
                         + "\", using default values. Reason: " + e.what());
×
351
        LoadDefaults();
×
352
        Save();
×
353
    }
354
}
×
355

356
void Settings::LoadIngame()
×
357
{
358
    libsiedler2::Archiv settingsIngame;
×
359
    const auto settingsPathIngame = RTTRCONFIG.ExpandPath(s25::resources::ingameOptions);
×
360
    try
361
    {
362
        if(libsiedler2::Load(settingsPathIngame, settingsIngame) != 0)
×
363
            throw std::runtime_error("File missing");
×
364

365
        const libsiedler2::ArchivItem_Ini* iniIngame =
366
          static_cast<libsiedler2::ArchivItem_Ini*>(settingsIngame.find("ingame"));
×
367
        if(!iniIngame)
×
368
            throw std::runtime_error("Missing section");
×
369
        // ingame
370
        // {
371
        ingame.scale_statistics = iniIngame->getBoolValue("scale_statistics");
×
372
        ingame.showBQ = iniIngame->getBoolValue("show_building_quality");
×
373
        ingame.showNames = iniIngame->getBoolValue("show_names");
×
374
        ingame.showProductivity = iniIngame->getBoolValue("show_productivity");
×
375
        ingame.minimapExtended = iniIngame->getBoolValue("minimap_extended");
×
376
        // }
377
        // ingame windows
378
        for(const auto& window : persistentWindows)
×
379
        {
380
            const auto* iniWindow = static_cast<const libsiedler2::ArchivItem_Ini*>(settingsIngame.find(window.second));
×
381
            if(!iniWindow)
×
382
                continue;
×
383
            auto& settings = windows.persistentSettings[window.first];
×
384
            const auto lastPos = settings.lastPos =
×
385
              DrawPoint(iniWindow->getIntValue("pos_x"), iniWindow->getIntValue("pos_y"));
×
386
            settings.restorePos = DrawPoint(iniWindow->getValue("restore_pos_x", lastPos.x),
×
387
                                            iniWindow->getValue("restore_pos_y", lastPos.y));
×
388
            settings.isOpen = iniWindow->getIntValue("is_open");
×
389
            settings.isPinned = iniWindow->getValue("is_pinned", false);
×
390
            settings.isMinimized = iniWindow->getValue("is_minimized", false);
×
391
        }
392
    } catch(const std::runtime_error& e)
×
393
    {
394
        s25util::warning(std::string("Could not use ingame settings from \"") + settingsPathIngame.string()
×
395
                         + "\", using default values. Reason: " + e.what());
×
396
        LoadIngameDefaults();
×
397
        SaveIngame();
×
398
    }
399
}
×
400

401
///////////////////////////////////////////////////////////////////////////////
402
// Routine zum Speichern der Konfiguration
403
void Settings::Save()
×
404
{
405
    libsiedler2::Archiv settings;
×
406
    settings.alloc(SECTION_NAMES.size());
×
407
    for(unsigned i = 0; i < SECTION_NAMES.size(); ++i)
×
408
        settings.set(i, std::make_unique<libsiedler2::ArchivItem_Ini>(SECTION_NAMES[i]));
×
409

410
    libsiedler2::ArchivItem_Ini* iniGlobal = static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("global"));
×
411
    libsiedler2::ArchivItem_Ini* iniVideo = static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("video"));
×
412
    libsiedler2::ArchivItem_Ini* iniLanguage = static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("language"));
×
413
    libsiedler2::ArchivItem_Ini* iniDriver = static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("driver"));
×
414
    libsiedler2::ArchivItem_Ini* iniSound = static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("sound"));
×
415
    libsiedler2::ArchivItem_Ini* iniLobby = static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("lobby"));
×
416
    libsiedler2::ArchivItem_Ini* iniServer = static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("server"));
×
417
    libsiedler2::ArchivItem_Ini* iniProxy = static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("proxy"));
×
418
    libsiedler2::ArchivItem_Ini* iniInterface = static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("interface"));
×
419
    libsiedler2::ArchivItem_Ini* iniAddons = static_cast<libsiedler2::ArchivItem_Ini*>(settings.find("addons"));
×
420

421
    // ist eine der Kategorien nicht vorhanden?
422
    RTTR_Assert(iniGlobal && iniVideo && iniLanguage && iniDriver && iniSound && iniLobby && iniServer && iniProxy
×
423
                && iniInterface && iniAddons);
424

425
    // global
426
    // {
427
    iniGlobal->setValue("version", VERSION);
×
428
    iniGlobal->setValue("gameversion", rttr::version::GetRevision());
×
429
    iniGlobal->setValue("submit_debug_data", global.submit_debug_data);
×
430
    iniGlobal->setValue("use_upnp", global.use_upnp);
×
431
    iniGlobal->setValue("smartCursor", global.smartCursor);
×
432
    iniGlobal->setValue("debugMode", global.debugMode);
×
433
    iniGlobal->setValue("showGFInfo", global.showGFInfo);
×
434
    // };
435

436
    // video
437
    // {
438
    iniVideo->setValue("fullscreen_width", video.fullscreenSize.width);
×
439
    iniVideo->setValue("fullscreen_height", video.fullscreenSize.height);
×
440
    iniVideo->setValue("windowed_width", video.windowedSize.width);
×
441
    iniVideo->setValue("windowed_height", video.windowedSize.height);
×
442
    iniVideo->setValue("fullscreen", video.fullscreen);
×
443
    iniVideo->setValue("framerate", video.framerate);
×
444
    iniVideo->setValue("vbo", video.vbo);
×
445
    iniVideo->setValue("shared_textures", video.shared_textures);
×
446
    iniVideo->setValue("gui_scale", video.guiScale);
×
447
    // };
448

449
    // language
450
    // {
451
    iniLanguage->setValue("language", language.language);
×
452
    // }
453

454
    // driver
455
    // {
456
    iniDriver->setValue("video", driver.video);
×
457
    iniDriver->setValue("audio", driver.audio);
×
458
    // }
459

460
    // sound
461
    // {
462
    iniSound->setValue("musik", sound.musicEnabled);
×
463
    iniSound->setValue("musik_volume", sound.musicVolume);
×
464
    iniSound->setValue("effekte", sound.effectsEnabled);
×
465
    iniSound->setValue("effekte_volume", sound.effectsVolume);
×
466
    iniSound->setValue("playlist", sound.playlist);
×
467
    // }
468

469
    // lobby
470
    // {
471
    iniLobby->setValue("name", lobby.name);
×
472
    iniLobby->setValue("portrait_index", lobby.portraitIndex);
×
473
    iniLobby->setValue("password", lobby.password);
×
474
    iniLobby->setValue("save_password", lobby.save_password);
×
475
    // }
476

477
    // server
478
    // {
479
    iniServer->setValue("last_ip", server.last_ip);
×
480
    iniServer->setValue("local_port", server.localPort);
×
481
    iniServer->setValue("ipv6", server.ipv6);
×
482
    // }
483

484
    // proxy
485
    // {
486
    iniProxy->setValue("proxy", proxy.hostname);
×
487
    iniProxy->setValue("port", proxy.port);
×
488
    iniProxy->setValue("typ", static_cast<int>(proxy.type));
×
489
    // }
490

491
    // interface
492
    // {
493
    iniInterface->setValue("autosave_interval", interface.autosave_interval);
×
NEW
494
    iniInterface->setValue("map_scroll_mode", static_cast<int>(interface.mapScrollMode));
×
495
    iniInterface->setValue("enable_window_pinning", interface.enableWindowPinning);
×
496
    iniInterface->setValue("window_snap_distance", interface.windowSnapDistance);
×
497
    // }
498

499
    // addons
500
    // {
501
    iniAddons->clear();
×
502
    for(const auto& it : addons.configuration)
×
503
        iniAddons->setValue(s25util::toStringClassic(it.first), s25util::toStringClassic(it.second));
×
504
    // }
505

506
    bfs::path settingsPath = RTTRCONFIG.ExpandPath(s25::resources::config);
×
507
    if(libsiedler2::Write(settingsPath, settings) == 0)
×
508
        bfs::permissions(settingsPath, bfs::owner_read | bfs::owner_write);
×
509

510
    SaveIngame();
×
511
}
×
512

513
void Settings::SaveIngame()
×
514
{
515
    libsiedler2::Archiv settingsIngame;
×
516
    settingsIngame.alloc(1 + persistentWindows.size());
×
517
    settingsIngame.set(0, std::make_unique<libsiedler2::ArchivItem_Ini>("ingame"));
×
518
    unsigned i = 1;
×
519
    for(const auto& window : persistentWindows)
×
520
    {
521
        settingsIngame.set(i, std::make_unique<libsiedler2::ArchivItem_Ini>(window.second));
×
522
        i++;
×
523
    }
524

525
    auto* iniIngame = static_cast<libsiedler2::ArchivItem_Ini*>(settingsIngame.find("ingame"));
×
526

527
    RTTR_Assert(iniIngame);
×
528

529
    // ingame
530
    // {
531
    iniIngame->setValue("scale_statistics", ingame.scale_statistics);
×
532
    iniIngame->setValue("show_building_quality", ingame.showBQ);
×
533
    iniIngame->setValue("show_names", ingame.showNames);
×
534
    iniIngame->setValue("show_productivity", ingame.showProductivity);
×
535
    iniIngame->setValue("minimap_extended", ingame.minimapExtended);
×
536
    // }
537

538
    // ingame windows
539
    for(const auto& window : persistentWindows)
×
540
    {
541
        auto* iniWindow = static_cast<libsiedler2::ArchivItem_Ini*>(settingsIngame.find(window.second));
×
542
        if(!iniWindow)
×
543
            continue;
×
544
        const auto& settings = windows.persistentSettings[window.first];
×
545
        iniWindow->setValue("pos_x", settings.lastPos.x);
×
546
        iniWindow->setValue("pos_y", settings.lastPos.y);
×
547
        if(settings.restorePos != settings.lastPos)
×
548
        {
549
            // only save if different; defaults to lastPos on load
550
            iniWindow->setValue("restore_pos_x", settings.restorePos.x);
×
551
            iniWindow->setValue("restore_pos_y", settings.restorePos.y);
×
552
        }
553
        iniWindow->setValue("is_open", settings.isOpen);
×
554
        iniWindow->setValue("is_pinned", settings.isPinned);
×
555
        iniWindow->setValue("is_minimized", settings.isMinimized);
×
556
    }
557

558
    bfs::path settingsPathIngame = RTTRCONFIG.ExpandPath(s25::resources::ingameOptions);
×
559
    if(libsiedler2::Write(settingsPathIngame, settingsIngame) == 0)
×
560
        bfs::permissions(settingsPathIngame, bfs::owner_read | bfs::owner_write);
×
561
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc