#pragma once #include "cfile/cfile.h" #include "controlconfig/controlsconfig.h" #include "globalincs/pstypes.h" #include "globalincs/vmallocator.h" #include /** API for saving and loading player custom bindings, known as Presets Init. If the player/preset dir doesn't exist. Create it, and print a help.txt with all enums (as strings) to label the button names and action names. Example output: { "actions": { "TARGET_NEXT": { "first": { "cid": 0, "flags": 0, "btn": 0 }, "second": { "cid": 0, "flags": 0, "btn": 0 } }, "TARGET_PREV" : { "first": { "cid": 0, "flags": 0, "btn": 0 }, "second": { "cid": 0, "flags": 0, "btn": 0 } }, }, "version": 0 } */ namespace io { namespace presets { static const unsigned int PST_VERSION = 0; static const unsigned int PST_FILE_ID = 0x5f545350; // "PST_" in file enum class Section { Invalid = -1, Unnamed = 0, // arrays Actions, // subsections Primary, Secondary }; class PresetFileHandler { public: PresetFileHandler(CFILE* cfp, bool reading); ~PresetFileHandler(); /** * begins writing to a section using the presets::Section as its name * @param[in] s id of the section */ void beginSectionWrite(presets::Section s); /** * begins reading a section, if it exists * @param[in] s id of the section */ bool beginSectionRead(presets::Section s); /** * Begins writing to an array using the presets::Section as its name * * @param[in] s id of the array */ void beginArrayWrite(presets::Section s); /** * Begins reading from an array * @param[int] s id of the array * @param[out] size the size of the array */ bool beginArrayRead(presets::Section s, size_t &size); /** * ends writing to a section */ void endSectionWrite(); /** * ends reading a section */ void endSectionRead(); /** * ends writing to an array. */ void endArrayWrite(); /** * ends reading from an array */ void endArrayRead(); /** * Writes a string with the given key name */ void writeString(const char* key, SCP_string s); /** * Reads a string with the given key name */ SCP_string readString(const char* key); /** * Writes an int with the given key name */ void writeInt(const char* key, int val); /** * Reads an int with the given key name */ int readInt(const char* key); /** * For writing, Flushes the buffers and dumps to file */ void flush(); /** * Advances the array parser to the next element */ void nextArrayElement(); private: CFILE* _cfp = nullptr; json_t* _rootObj = nullptr; json_t* _currentEl = nullptr; /** * BufferStack of all json elements being read/written */ SCP_vector _elementStack; /** * Stack to keep track of the heirachy/nesting. Back is immediate parent, Front is root */ SCP_vector _parentStack; size_t _arrayIndex = INVALID_SIZE; //void* _sectionIterator = nullptr; //!< Pointer to the current section/array we're in private: /** * Pushes an element onto the elementStack */ void pushElement(json_t* el); /** * Pops an element off the elementStack */ json_t * popElement(); /** * Used for optionals, checks if an element exists with the given name * @return True if the element exists * @return False otherwise */ bool exists(const char* name); /** * Throws an error if an element with the given name does not exist */ void ensureExists(const char* name); /** * Throws an error if an element with the given name exists */ void ensureNotExists(const char* name); }; } // namespace presets } // namespace io /** * @brief Saves the given preset to file. * @param[in] preset The preset to save * @param[in] overwrite If true, overwrite existing preset file which have the same name as the given preset * * @returns True if successful, or * @returns False Preset does not have a name, or * @returns False Preset file exists and overwrite == false, or * @returns False Preset file .JSON could not be written */ bool save_preset_file(CC_preset preset, bool overwrite); /** * @brief Deletes the given preset to file. * @param[in] preset The preset to delete * * @returns True if successful, or * @returns False Preset is default, or * @returns False Preset file is the currently selected preset */ bool delete_preset_file(CC_preset preset); /** * @brief Loads in all preset .json files from 'players/presets' * @details If a preset file is unique, it is loaded into the game and available for use by the player. However, if * a preset is a duplicate of another preset, it is ignored, and the player is warned of it * * @param[in] clone Used to check if we just cloned a particular preset and allows just that clone in without warning */ void load_preset_files(SCP_string clone = ""); /** * @brief Checks if the given preset is a duplicate within Control_config_presets vector * @returns iterator to the duplicate if found, or * @returns iterator to Control_config_presets.end() otherwise */ SCP_vector::iterator preset_find_duplicate(const CC_preset& new_preset); /** * @brief Returns true if a preset file with the given name exists. */ bool preset_file_exists(SCP_string name);