Implement reading/writing the synced and unsynced preferences

Reading the preferences will now:
* read the default preferences (if defined) and add them into the preferences config
* read the unsynced preferences and add them on top of any default preferences
* read the synced preferences and add them on top of the default and unsynced preferences.

Writing the preferences works basically the same way, just that it writes out preferences to either the synced or unsynced preferences file depending on the preference. This is determined by the std::arrays added to preferences.hpp and is checked at compile time via the static_assert these these arrays and the prefs_list are all constexpr - forgetting to add a new preference or remove an existing preference to these arrays will cause a compile error.

This also means that unknown preferences will not be written back out, so the removal of any existing "password" and "password_is_wrapped" preferences no longer needs to be explicitly done. Additionally, the clear() and erase() methods are removed:
* clear() is not desireable in the first place and it's not actually applicable to anything currently using it since they're just single attributes at the root of the config object anyway
* erase() is a one liner method that's not needed anymore since all handling now has access to the preferences_ config object
This commit is contained in:
pentarctagon 2024-06-16 13:07:49 -05:00 committed by Pentarctagon
parent 54ab301343
commit e9f13b1958
4 changed files with 284 additions and 67 deletions

View file

@ -94,6 +94,8 @@ void migrate_version_selection::post_show(window& window)
= boost::replace_all_copy(filesystem::get_addons_dir(), current_version_str, selected);
std::string migrate_prefs_file
= boost::replace_all_copy(filesystem::get_prefs_file(), current_version_str, selected);
std::string migrate_unsynced_prefs_file
= boost::replace_all_copy(filesystem::get_unsynced_prefs_file(), current_version_str, selected);
std::string migrate_credentials_file
= boost::replace_all_copy(filesystem::get_credentials_file(), current_version_str, selected);
@ -132,6 +134,7 @@ void migrate_version_selection::post_show(window& window)
if(!already_migrated)
#endif
{
prefs::get().migrate_preferences(migrate_unsynced_prefs_file);
prefs::get().migrate_preferences(migrate_prefs_file);
migrate_credentials(migrate_credentials_file);
}

View file

@ -236,21 +236,30 @@ void prefs::load_preferences()
{
preferences_.clear();
try{
config default_prefs;
config unsynced_prefs;
config synced_prefs;
#ifdef DEFAULT_PREFS_PATH
// NOTE: the system preferences file is only ever relevant for the first time wesnoth starts
// any default values will subsequently be written to the normal preferences file, which takes precedence over any values in the system preferences file
filesystem::scoped_istream stream = filesystem::istream_file(filesystem::get_default_prefs_file(),false);
read(preferences_, *stream);
config user_prefs;
stream = filesystem::istream_file(filesystem::get_prefs_file());
read(user_prefs, *stream);
preferences_.merge_with(user_prefs);
#else
filesystem::scoped_istream stream = filesystem::istream_file(filesystem::get_prefs_file(),false);
read(preferences_, *stream);
// any default values will subsequently be written to the normal preferences files, which takes precedence over any values in the system preferences file
{
filesystem::scoped_istream stream = filesystem::istream_file(filesystem::get_default_prefs_file(), false);
read(default_prefs, *stream);
}
#endif
{
filesystem::scoped_istream stream = filesystem::istream_file(filesystem::get_unsynced_prefs_file(), false);
read(unsynced_prefs, *stream);
}
{
filesystem::scoped_istream stream = filesystem::istream_file(filesystem::get_prefs_file(), false);
read(synced_prefs, *stream);
}
preferences_.merge_with(default_prefs);
preferences_.merge_with(unsynced_prefs);
preferences_.merge_with(synced_prefs);
} catch(const config::error& e) {
ERR_CFG << "Error loading preference, message: " << e.what();
}
@ -258,10 +267,6 @@ void prefs::load_preferences()
set_music_volume(music_volume());
set_sound_volume(sound_volume());
// We save the password encrypted now. Erase any saved passwords in the prefs file.
erase("password");
erase("password_is_wrapped");
/*
completed_campaigns = "A,B,C"
[completed_campaigns]
@ -309,24 +314,64 @@ void prefs::load_preferences()
void prefs::write_preferences()
{
#ifndef _WIN32
bool prefs_file_existed = filesystem::file_exists(filesystem::get_prefs_file());
bool synced_prefs_file_existed = filesystem::file_exists(filesystem::get_prefs_file());
bool unsynced_prefs_file_existed = filesystem::file_exists(filesystem::get_unsynced_prefs_file());
#endif
config synced;
config unsynced;
for(const char* attr : synced_attributes_) {
if(preferences_.has_attribute(attr)) {
synced[attr] = preferences_[attr];
}
}
for(const char* attr : synced_children_) {
for(const auto& child : preferences_.child_range(attr)) {
config& ch = synced.add_child(attr);
ch.append_children(child);
}
}
for(const char* attr : unsynced_attributes_) {
if(preferences_.has_attribute(attr)) {
unsynced[attr] = preferences_[attr];
}
}
for(const char* attr : unsynced_children_) {
for(const auto& child : preferences_.child_range(attr)) {
config& ch = unsynced.add_child(attr);
ch.append_children(child);
}
}
try {
filesystem::scoped_ostream prefs_file = filesystem::ostream_file(filesystem::get_prefs_file());
write(*prefs_file, preferences_);
filesystem::scoped_ostream synced_prefs_file = filesystem::ostream_file(filesystem::get_prefs_file());
write(*synced_prefs_file, synced);
} catch(const filesystem::io_exception&) {
ERR_FS << "error writing to preferences file '" << filesystem::get_prefs_file() << "'";
ERR_FS << "error writing to synced preferences file '" << filesystem::get_prefs_file() << "'";
}
try {
filesystem::scoped_ostream unsynced_prefs_file = filesystem::ostream_file(filesystem::get_unsynced_prefs_file());
write(*unsynced_prefs_file, unsynced);
} catch(const filesystem::io_exception&) {
ERR_FS << "error writing to unsynced preferences file '" << filesystem::get_unsynced_prefs_file() << "'";
}
save_credentials();
#ifndef _WIN32
if(!prefs_file_existed) {
if(!synced_prefs_file_existed) {
if(chmod(filesystem::get_prefs_file().c_str(), 0600) == -1) {
ERR_FS << "error setting permissions of preferences file '" << filesystem::get_prefs_file() << "'";
}
}
if(!unsynced_prefs_file_existed) {
if(chmod(filesystem::get_unsynced_prefs_file().c_str(), 0600) == -1) {
ERR_FS << "error setting permissions of unsynced preferences file '" << filesystem::get_unsynced_prefs_file() << "'";
}
}
#endif
}
@ -410,15 +455,6 @@ void prefs::save_credentials()
//
// helpers
//
void prefs::clear(const std::string& key)
{
preferences_.recursive_clear_value(key);
}
void prefs::erase(const std::string& key) {
preferences_.remove_attribute(key);
}
void prefs::set_child(const std::string& key, const config& val) {
preferences_.clear_children(key);
preferences_.add_child(key, val);
@ -1686,7 +1722,7 @@ void prefs::set_theme(const std::string& theme)
void prefs::set_mp_server_program_name(const std::string& path)
{
if(path.empty()) {
clear(prefs_list::mp_server_program_name);
preferences_.remove_attribute(prefs_list::mp_server_program_name);
} else {
preferences_[prefs_list::mp_server_program_name] = path;
}
@ -2105,7 +2141,7 @@ void prefs::set_countdown_init_time(int value)
void prefs::clear_countdown_init_time()
{
clear(prefs_list::mp_countdown_init_time);
preferences_.remove_attribute(prefs_list::mp_countdown_init_time);
}
int prefs::countdown_reservoir_time()
@ -2120,7 +2156,7 @@ void prefs::set_countdown_reservoir_time(int value)
void prefs::clear_countdown_reservoir_time()
{
clear(prefs_list::mp_countdown_reservoir_time);
preferences_.remove_attribute(prefs_list::mp_countdown_reservoir_time);
}
int prefs::countdown_turn_bonus()
@ -2135,7 +2171,7 @@ void prefs::set_countdown_turn_bonus(int value)
void prefs::clear_countdown_turn_bonus()
{
clear(prefs_list::mp_countdown_turn_bonus);
preferences_.remove_attribute(prefs_list::mp_countdown_turn_bonus);
}
int prefs::countdown_action_bonus()
@ -2150,7 +2186,7 @@ void prefs::set_countdown_action_bonus(int value)
void prefs::clear_countdown_action_bonus()
{
clear(prefs_list::mp_countdown_action_bonus);
preferences_.remove_attribute(prefs_list::mp_countdown_action_bonus);
}
int prefs::village_gold()
@ -2746,36 +2782,36 @@ void prefs::set_game_created_lobby(bool val)
void prefs::clear_mp_alert_prefs()
{
erase(prefs_list::player_joins_sound);
erase(prefs_list::player_joins_notif);
erase(prefs_list::player_joins_lobby);
erase(prefs_list::player_leaves_sound);
erase(prefs_list::player_leaves_notif);
erase(prefs_list::player_leaves_lobby);
erase(prefs_list::private_message_sound);
erase(prefs_list::private_message_notif);
erase(prefs_list::private_message_lobby);
erase(prefs_list::friend_message_sound);
erase(prefs_list::friend_message_notif);
erase(prefs_list::friend_message_lobby);
erase(prefs_list::public_message_sound);
erase(prefs_list::public_message_notif);
erase(prefs_list::public_message_lobby);
erase(prefs_list::server_message_sound);
erase(prefs_list::server_message_notif);
erase(prefs_list::server_message_lobby);
erase(prefs_list::ready_for_start_sound);
erase(prefs_list::ready_for_start_notif);
erase(prefs_list::ready_for_start_lobby);
erase(prefs_list::game_has_begun_sound);
erase(prefs_list::game_has_begun_notif);
erase(prefs_list::game_has_begun_lobby);
erase(prefs_list::turn_changed_sound);
erase(prefs_list::turn_changed_notif);
erase(prefs_list::turn_changed_lobby);
erase(prefs_list::game_created_sound);
erase(prefs_list::game_created_notif);
erase(prefs_list::game_created_lobby);
preferences_.remove_attribute(prefs_list::player_joins_sound);
preferences_.remove_attribute(prefs_list::player_joins_notif);
preferences_.remove_attribute(prefs_list::player_joins_lobby);
preferences_.remove_attribute(prefs_list::player_leaves_sound);
preferences_.remove_attribute(prefs_list::player_leaves_notif);
preferences_.remove_attribute(prefs_list::player_leaves_lobby);
preferences_.remove_attribute(prefs_list::private_message_sound);
preferences_.remove_attribute(prefs_list::private_message_notif);
preferences_.remove_attribute(prefs_list::private_message_lobby);
preferences_.remove_attribute(prefs_list::friend_message_sound);
preferences_.remove_attribute(prefs_list::friend_message_notif);
preferences_.remove_attribute(prefs_list::friend_message_lobby);
preferences_.remove_attribute(prefs_list::public_message_sound);
preferences_.remove_attribute(prefs_list::public_message_notif);
preferences_.remove_attribute(prefs_list::public_message_lobby);
preferences_.remove_attribute(prefs_list::server_message_sound);
preferences_.remove_attribute(prefs_list::server_message_notif);
preferences_.remove_attribute(prefs_list::server_message_lobby);
preferences_.remove_attribute(prefs_list::ready_for_start_sound);
preferences_.remove_attribute(prefs_list::ready_for_start_notif);
preferences_.remove_attribute(prefs_list::ready_for_start_lobby);
preferences_.remove_attribute(prefs_list::game_has_begun_sound);
preferences_.remove_attribute(prefs_list::game_has_begun_notif);
preferences_.remove_attribute(prefs_list::game_has_begun_lobby);
preferences_.remove_attribute(prefs_list::turn_changed_sound);
preferences_.remove_attribute(prefs_list::turn_changed_notif);
preferences_.remove_attribute(prefs_list::turn_changed_lobby);
preferences_.remove_attribute(prefs_list::game_created_sound);
preferences_.remove_attribute(prefs_list::game_created_notif);
preferences_.remove_attribute(prefs_list::game_created_lobby);
}
std::string prefs::get_system_username()

View file

@ -837,12 +837,10 @@ class prefs
void save_credentials();
void clear_credentials();
void clear(const std::string& key);
void set_child(const std::string& key, const config& val);
optional_const_config get_child(const std::string &key);
std::string get(const std::string& key, const std::string& def);
config::attribute_value get_as_attribute(const std::string& key);
void erase(const std::string& key);
std::string get_system_username();
/**
@ -872,6 +870,185 @@ class prefs
preferences::secure_buffer build_key(const std::string& server, const std::string& login);
preferences::secure_buffer escape(const preferences::secure_buffer& text);
preferences::secure_buffer unescape(const preferences::secure_buffer& text);
// a bit verbose, but it being a compile time error if a preference hasn't been added is nice
static constexpr std::array synced_attributes_{
prefs_list::player_joins_sound,
prefs_list::player_joins_notif,
prefs_list::player_joins_lobby,
prefs_list::player_leaves_sound,
prefs_list::player_leaves_notif,
prefs_list::player_leaves_lobby,
prefs_list::private_message_sound,
prefs_list::private_message_notif,
prefs_list::private_message_lobby,
prefs_list::friend_message_sound,
prefs_list::friend_message_notif,
prefs_list::friend_message_lobby,
prefs_list::public_message_sound,
prefs_list::public_message_notif,
prefs_list::public_message_lobby,
prefs_list::server_message_sound,
prefs_list::server_message_notif,
prefs_list::server_message_lobby,
prefs_list::ready_for_start_sound,
prefs_list::ready_for_start_notif,
prefs_list::ready_for_start_lobby,
prefs_list::game_has_begun_sound,
prefs_list::game_has_begun_notif,
prefs_list::game_has_begun_lobby,
prefs_list::turn_changed_sound,
prefs_list::turn_changed_notif,
prefs_list::turn_changed_lobby,
prefs_list::game_created_sound,
prefs_list::game_created_notif,
prefs_list::game_created_lobby,
prefs_list::_last_cache_cleaned_ver,
prefs_list::addon_manager_saved_order_direction,
prefs_list::addon_manager_saved_order_name,
prefs_list::alias,
prefs_list::allow_observers,
prefs_list::ally_orb_color,
prefs_list::ally_sighted_interrupts,
prefs_list::auto_save_max,
prefs_list::blindfold_replay,
prefs_list::campaign_server,
prefs_list::chat_lines,
prefs_list::chat_timestamp,
prefs_list::confirm_end_turn,
prefs_list::custom_command,
prefs_list::delete_saves,
prefs_list::disable_auto_moves,
prefs_list::editor_auto_update_transitions,
prefs_list::editor_draw_hex_coordinates,
prefs_list::editor_draw_num_of_bitmaps,
prefs_list::editor_draw_terrain_codes,
prefs_list::enable_planning_mode_on_start,
prefs_list::encountered_terrain_list,
prefs_list::encountered_units,
prefs_list::enemy_orb_color,
prefs_list::fi_blocked_in_game,
prefs_list::fi_friends_in_game,
prefs_list::fi_invert,
prefs_list::fi_vacant_slots,
prefs_list::floating_labels,
prefs_list::grid,
prefs_list::hide_whiteboard,
prefs_list::host,
prefs_list::idle_anim,
prefs_list::idle_anim_rate,
prefs_list::lobby_joins,
prefs_list::lobby_whisper_friends_only,
prefs_list::locale,
prefs_list::login,
prefs_list::message_bell,
prefs_list::minimap_draw_terrain,
prefs_list::minimap_draw_units,
prefs_list::minimap_draw_villages,
prefs_list::minimap_movement_coding,
prefs_list::minimap_terrain_coding,
prefs_list::moved_orb_color,
prefs_list::mp_countdown,
prefs_list::mp_countdown_action_bonus,
prefs_list::mp_countdown_init_time,
prefs_list::mp_countdown_reservoir_time,
prefs_list::mp_countdown_turn_bonus,
prefs_list::mp_fog,
prefs_list::mp_level_type,
prefs_list::mp_random_start_time,
prefs_list::mp_server_warning_disabled,
prefs_list::mp_shroud,
prefs_list::mp_turns,
prefs_list::mp_use_map_settings,
prefs_list::mp_village_gold,
prefs_list::mp_village_support,
prefs_list::mp_xp_modifier,
prefs_list::music,
prefs_list::partial_orb_color,
prefs_list::random_faction_mode,
prefs_list::remember_password,
prefs_list::save_replays,
prefs_list::scroll,
prefs_list::scroll_threshold,
prefs_list::show_ally_orb,
prefs_list::show_disengaged_orb,
prefs_list::show_enemy_orb,
prefs_list::show_moved_orb,
prefs_list::show_partial_orb,
prefs_list::show_side_colors,
prefs_list::show_status_on_ally_orb,
prefs_list::show_unmoved_orb,
prefs_list::shuffle_sides,
prefs_list::skip_ai_moves,
prefs_list::skip_mp_replay,
prefs_list::sound,
prefs_list::sample_rate,
prefs_list::stop_music_in_background,
prefs_list::turbo,
prefs_list::turbo_speed,
prefs_list::turn_bell,
prefs_list::turn_dialog,
prefs_list::ui_sound,
prefs_list::unit_standing_animations,
prefs_list::unmoved_orb_color,
prefs_list::ask_delete,
prefs_list::chat_message_aging,
prefs_list::color_cursors,
prefs_list::compress_saves,
prefs_list::confirm_load_save_from_different_version,
prefs_list::damage_prediction_allow_monte_carlo_simulation,
prefs_list::editor_max_recent_files,
prefs_list::keepalive_timeout,
prefs_list::lobby_auto_open_whisper_windows,
prefs_list::middle_click_scrolls,
prefs_list::mouse_scrolling,
prefs_list::scroll_to_action,
prefs_list::scroll_when_mouse_outside,
prefs_list::show_all_units_in_help,
prefs_list::show_combat,
prefs_list::show_deprecation,
prefs_list::use_twelve_hour_clock_format,
prefs_list::mp_era,
prefs_list::mp_level,
prefs_list::mp_modifications,
prefs_list::selected_achievement_group,
prefs_list::sp_modifications,
prefs_list::animate_map,
prefs_list::animate_water,
};
static constexpr std::array synced_children_{
prefs_list::achievements,
prefs_list::completed_campaigns,
prefs_list::history,
prefs_list::options,
};
static constexpr std::array unsynced_attributes_{
prefs_list::auto_pixel_scale,
prefs_list::core,
prefs_list::dir_bookmarks,
prefs_list::draw_delay,
prefs_list::editor_chosen_addon,
prefs_list::gui2_theme,
prefs_list::mp_server_program_name,
prefs_list::pixel_scale,
prefs_list::sound_buffer_size,
prefs_list::theme,
prefs_list::tile_size,
prefs_list::vsync,
prefs_list::xresolution,
prefs_list::yresolution,
prefs_list::font_scale,
prefs_list::bell_volume,
prefs_list::music_volume,
prefs_list::sound_volume,
prefs_list::ui_volume,
prefs_list::fullscreen,
prefs_list::maximized,
};
static constexpr std::array unsynced_children_{
prefs_list::editor_recent_files,
};
static_assert(synced_attributes_.size() + synced_children_.size() + unsynced_attributes_.size() + unsynced_children_.size() == prefs_list::values.size(), "attribute missing from lists of synced or unsynced preferences!");
};
//

View file

@ -274,6 +274,7 @@ struct preferences_list_defines
static constexpr const char* const yresolution = "yresolution";
//
// MP alert preferences
// Note, this list of items must match those ids defined in data/gui/dialogs/mp_alerts_options.cfg
//
/** whether to play a sound when a player joins the game you're in */
static constexpr const char* const player_joins_sound = "player_joins_sound";