#pragma once #include "globalincs/pstypes.h" #include "libs/jansson.h" #include #include namespace options { // Forward declaration class OptionBase; class OptionsManager { OptionsManager(); // A value forced by something outside of the options system itself (currently only the command line). // This takes priority over the persisted config value and over any in-session edit. The options UI shows // an overridden option as a disabled control with the reason in its tooltip. struct OverrideEntry { std::unique_ptr value; SCP_string reason; // human-readable source, e.g. "-no_vsync", shown in the options UI }; SCP_unordered_map _config_overrides; SCP_unordered_map> _changed_values; SCP_unordered_map _optionsMapping; // Enforced options are hidden from the player and do not load values from user settings SCP_unordered_set _enforcedOptions; SCP_vector> _options; bool _optionsSorted = false; public: static OptionsManager* instance(); ~OptionsManager(); std::optional> getValueFromConfig(const SCP_string& key) const; void setConfigValue(const SCP_string& key, std::unique_ptr&& value); void setOverride(const SCP_string& key, const SCP_string& json, const SCP_string& reason); // Overload that takes an already-built JSON value. Prefer this one: it lets a caller reuse the option's // own serializer instead of formatting the JSON by hand, which can produce a value the option's // deserializer then rejects. void setOverride(const SCP_string& key, std::unique_ptr&& value, const SCP_string& reason); // Returns true if this key currently has an override. bool isOverridden(const SCP_string& key) const; // Returns the reason string passed to setOverride() for this key, if it is currently overridden. std::optional getOverrideReason(const SCP_string& key) const; // Removes all overrides. For tests, so that one test's overrides do not leak into the next. void clearOverrides(); const OptionBase* addOption(std::shared_ptr&& option); void removeOption(const std::shared_ptr& option); const OptionBase* getOptionByKey(SCP_string name); void enforceOption(const SCP_string& key); void unenforceOption(const SCP_string& key); bool isOptionEnforced(const SCP_string& key) const; const SCP_vector>& getOptions(); bool persistOptionChanges(const options::OptionBase* option); /** * @brief Persists changes to the disk * * This writes all the outstanding changes to the config file and returns a vector of all the options that indicated * that they could not change the value. If the return value is empty then all changes were applied but if it is not * empty then a restart is required for all the options to take effect. * * @return A vector of options that did not support changing the value */ SCP_vector persistChanges(); void discardChanges(); void loadInitialValues(); void printValues(); void set_ingame_binary_option(SCP_string key, bool value); void set_ingame_multi_option(SCP_string key, int value); void set_ingame_range_option(SCP_string key, int value); void set_ingame_range_option(SCP_string key, float value); }; }