From 8e83daac8436bee3d97f18d30d3ef5fac5b9b01c Mon Sep 17 00:00:00 2001 From: tustin2121 Date: Thu, 1 Sep 2022 00:57:31 -0400 Subject: [PATCH 1/5] Split project config - Project config is now split into project and user config. - Backwards compatibility with the old project config included, porting old project items over to the new user config. --- docsrc/manual/settings-and-options.rst | 12 ++- include/config.h | 53 +++++++++--- src/config.cpp | 111 ++++++++++++++++++------- src/mainwindow.cpp | 17 ++-- src/mainwindow_scriptapi.cpp | 4 +- src/project.cpp | 8 +- src/scripting.cpp | 4 +- 7 files changed, 147 insertions(+), 62 deletions(-) diff --git a/docsrc/manual/settings-and-options.rst b/docsrc/manual/settings-and-options.rst index 2c231ea2..27608636 100644 --- a/docsrc/manual/settings-and-options.rst +++ b/docsrc/manual/settings-and-options.rst @@ -10,7 +10,11 @@ A global settings file is stored in a platform-dependent location for app config A config file is also created when opening a project in porymap for the first time. It is stored in your project root as ``porymap.project.cfg``. There are several project-specific settings that are -determined by this file. +determined by this file. You may want to check in this file so that other users will have your +porject settings. + +A second config file is created for user-specific settings. It is stored in +your project root as ``porymap.user.cfg``. You should add this file to your gitignore. .. csv-table:: :header: Setting,Default,Location,Can Edit?,Description @@ -18,7 +22,7 @@ determined by this file. ``recent_project``, , global, yes, The project that will be opened on launch ``reopen_on_launch``, 1, global, yes, Whether the most recent project should be opened on launch - ``recent_map``, , global, yes, The map that will be opened on launch + ``recent_map``, , user, yes, The map that will be opened on launch ``pretty_cursors``, 1, global, yes, Whether to use custom crosshair cursors ``map_sort_order``, group, global, yes, The order map list is sorted in ``window_geometry``, , global, no, For restoring window sizes @@ -35,7 +39,7 @@ determined by this file. ``text_editor_goto_line``, , global, yes, The command that will be executed when clicking the button next the ``Script`` combo-box. ``text_editor_open_directory``, , global, yes, The command that will be executed when clicking ``Open Project in Text Editor``. ``base_game_version``, , project, no, The base pret repo for this project - ``use_encounter_json``, 1, project, yes, Enables wild encounter table editing + ``use_encounter_json``, 1, user, yes, Enables wild encounter table editing ``use_poryscript``, 0, project, yes, Whether to open .pory files for scripts ``use_custom_border_size``, 0, project, yes, Whether to allow variable border sizes ``enable_event_weather_trigger``, 1 if not ``pokefirered``, project, yes, Allows adding Weather Trigger events @@ -47,6 +51,6 @@ determined by this file. ``enable_floor_number``, 1 if ``pokefirered``, project, yes, Adds ``Floor Number`` to map headers ``create_map_text_file``, 1 if not ``pokeemerald``, project, yes, A ``text.inc`` or ``text.pory`` file will be created for any new map ``enable_triple_layer_metatiles``, 0, project, yes, Enables triple-layer metatiles (See https://github.com/pret/pokeemerald/wiki/Triple-layer-metatiles) - ``custom_scripts``, , project, yes, A list of script files to load into the scripting engine + ``custom_scripts``, , user, yes, A list of script files to load into the scripting engine Some of these settings can be toggled manually in porymap via the *Options* menu. diff --git a/include/config.h b/include/config.h index 165bab60..9746ccf6 100644 --- a/include/config.h +++ b/include/config.h @@ -9,6 +9,8 @@ #include #include +#define CONFIG_BACKWARDS_COMPATABILITY + enum MapSortOrder { Group = 0, Area = 1, @@ -145,8 +147,6 @@ public: } virtual void reset() override { this->baseGameVersion = BaseGameVersion::pokeemerald; - this->recentMap = QString(); - this->useEncounterJson = true; this->useCustomBorderSize = false; this->enableEventWeatherTrigger = true; this->enableEventSecretBase = true; @@ -157,16 +157,11 @@ public: this->enableFloorNumber = false; this->createMapTextFile = false; this->enableTripleLayerMetatiles = false; - this->customScripts.clear(); this->readKeys.clear(); } void setBaseGameVersion(BaseGameVersion baseGameVersion); BaseGameVersion getBaseGameVersion(); QString getBaseGameVersionString(); - void setRecentMap(const QString &map); - QString getRecentMap(); - void setEncounterJsonActive(bool active); - bool getEncounterJsonActive(); void setUsePoryScript(bool usePoryScript); bool getUsePoryScript(); void setProjectDir(QString projectDir); @@ -191,8 +186,6 @@ public: bool getCreateMapTextFileEnabled(); void setTripleLayerMetatilesEnabled(bool enable); bool getTripleLayerMetatilesEnabled(); - void setCustomScripts(QList scripts); - QList getCustomScripts(); protected: virtual QString getConfigFilepath() override; virtual void parseConfigKeyValue(QString key, QString value) override; @@ -202,8 +195,6 @@ protected: private: BaseGameVersion baseGameVersion; QString projectDir; - QString recentMap; - bool useEncounterJson; bool usePoryScript; bool useCustomBorderSize; bool enableEventWeatherTrigger; @@ -215,12 +206,50 @@ private: bool enableFloorNumber; bool createMapTextFile; bool enableTripleLayerMetatiles; - QList customScripts; QStringList readKeys; }; extern ProjectConfig projectConfig; +class UserConfig: public KeyValueConfigBase +{ +public: + UserConfig() { + reset(); + } + virtual void reset() override { + this->recentMap = QString(); + this->useEncounterJson = true; + this->customScripts.clear(); + this->readKeys.clear(); + } + void setRecentMap(const QString &map); + QString getRecentMap(); + void setEncounterJsonActive(bool active); + bool getEncounterJsonActive(); + void setProjectDir(QString projectDir); + QString getProjectDir(); + void setCustomScripts(QList scripts); + QList getCustomScripts(); +protected: + virtual QString getConfigFilepath() override; + virtual void parseConfigKeyValue(QString key, QString value) override; + virtual QMap getKeyValueMap() override; + virtual void onNewConfigFileCreated() override; + virtual void setUnreadKeys() override; +#ifdef CONFIG_BACKWARDS_COMPATABILITY + friend class ProjectConfig; +#endif +private: + QString projectDir; + QString recentMap; + bool useEncounterJson; + QList customScripts; + QStringList readKeys; +}; + +extern UserConfig userConfig; + class QAction; class Shortcut; diff --git a/src/config.cpp b/src/config.cpp index 0ed1e081..4f9d80ad 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -468,10 +468,6 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) { this->baseGameVersion = BaseGameVersion::pokeemerald; logWarn(QString("Invalid config value for base_game_version: '%1'. Must be 'pokeruby', 'pokefirered' or 'pokeemerald'.").arg(value)); } - } else if (key == "recent_map") { - this->recentMap = value; - } else if (key == "use_encounter_json") { - setConfigBool(key, &this->useEncounterJson, value); } else if (key == "use_poryscript") { setConfigBool(key, &this->usePoryScript, value); } else if (key == "use_custom_border_size") { @@ -494,15 +490,21 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) { setConfigBool(key, &this->createMapTextFile, value); } else if (key == "enable_triple_layer_metatiles") { setConfigBool(key, &this->enableTripleLayerMetatiles, value); +#ifdef CONFIG_BACKWARDS_COMPATABILITY + } else if (key == "recent_map") { + userConfig.setRecentMap(value); + } else if (key == "use_encounter_json") { + userConfig.setConfigBool(key, &userConfig.useEncounterJson, value); } else if (key == "custom_scripts") { - this->customScripts.clear(); + userConfig.customScripts.clear(); QList paths = value.split(","); paths.removeDuplicates(); for (QString script : paths) { if (!script.isEmpty()) { - this->customScripts.append(script); + userConfig.customScripts.append(script); } } +#endif } else { logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key)); } @@ -526,8 +528,6 @@ void ProjectConfig::setUnreadKeys() { QMap ProjectConfig::getKeyValueMap() { QMap map; map.insert("base_game_version", baseGameVersionMap.value(this->baseGameVersion)); - map.insert("recent_map", this->recentMap); - map.insert("use_encounter_json", QString::number(this->useEncounterJson)); map.insert("use_poryscript", QString::number(this->usePoryScript)); map.insert("use_custom_border_size", QString::number(this->useCustomBorderSize)); map.insert("enable_event_weather_trigger", QString::number(this->enableEventWeatherTrigger)); @@ -539,7 +539,6 @@ QMap ProjectConfig::getKeyValueMap() { map.insert("enable_floor_number", QString::number(this->enableFloorNumber)); map.insert("create_map_text_file", QString::number(this->createMapTextFile)); map.insert("enable_triple_layer_metatiles", QString::number(this->enableTripleLayerMetatiles)); - map.insert("custom_scripts", this->customScripts.join(",")); return map; } @@ -579,10 +578,8 @@ void ProjectConfig::onNewConfigFileCreated() { this->enableEventCloneObject = isPokefirered; this->enableFloorNumber = isPokefirered; this->createMapTextFile = (this->baseGameVersion != BaseGameVersion::pokeemerald); - this->useEncounterJson = true; this->usePoryScript = false; this->enableTripleLayerMetatiles = false; - this->customScripts.clear(); } void ProjectConfig::setProjectDir(QString projectDir) { @@ -606,24 +603,6 @@ QString ProjectConfig::getBaseGameVersionString() { return baseGameVersionMap.value(this->baseGameVersion); } -void ProjectConfig::setRecentMap(const QString &map) { - this->recentMap = map; - this->save(); -} - -QString ProjectConfig::getRecentMap() { - return this->recentMap; -} - -void ProjectConfig::setEncounterJsonActive(bool active) { - this->useEncounterJson = active; - this->save(); -} - -bool ProjectConfig::getEncounterJsonActive() { - return this->useEncounterJson; -} - void ProjectConfig::setUsePoryScript(bool usePoryScript) { this->usePoryScript = usePoryScript; this->save(); @@ -723,12 +702,82 @@ bool ProjectConfig::getTripleLayerMetatilesEnabled() { return this->enableTripleLayerMetatiles; } -void ProjectConfig::setCustomScripts(QList scripts) { +UserConfig userConfig; + +QString UserConfig::getConfigFilepath() { + // porymap config file is in the same directory as porymap itself. + return QDir(this->projectDir).filePath("porymap.user.cfg"); +} + +void UserConfig::parseConfigKeyValue(QString key, QString value) { + if (key == "recent_map") { + this->recentMap = value; + } else if (key == "use_encounter_json") { + setConfigBool(key, &this->useEncounterJson, value); + } else if (key == "custom_scripts") { + this->customScripts.clear(); + QList paths = value.split(","); + paths.removeDuplicates(); + for (QString script : paths) { + if (!script.isEmpty()) { + this->customScripts.append(script); + } + } + } else { + logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key)); + } + readKeys.append(key); +} + +void UserConfig::setUnreadKeys() { +} + +QMap UserConfig::getKeyValueMap() { + QMap map; + map.insert("recent_map", this->recentMap); + map.insert("use_encounter_json", QString::number(this->useEncounterJson)); + map.insert("custom_scripts", this->customScripts.join(",")); + return map; +} + +void UserConfig::onNewConfigFileCreated() { + QString dirName = QDir(this->projectDir).dirName().toLower(); + this->useEncounterJson = true; + this->customScripts.clear(); +} + +void UserConfig::setProjectDir(QString projectDir) { + this->projectDir = projectDir; +} + +QString UserConfig::getProjectDir() { + return this->projectDir; +} + +void UserConfig::setRecentMap(const QString &map) { + this->recentMap = map; + this->save(); +} + +QString UserConfig::getRecentMap() { + return this->recentMap; +} + +void UserConfig::setEncounterJsonActive(bool active) { + this->useEncounterJson = active; + this->save(); +} + +bool UserConfig::getEncounterJsonActive() { + return this->useEncounterJson; +} + +void UserConfig::setCustomScripts(QList scripts) { this->customScripts = scripts; this->save(); } -QList ProjectConfig::getCustomScripts() { +QList UserConfig::getCustomScripts() { return this->customScripts; } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 71089327..9986a5bc 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -357,7 +357,7 @@ void MainWindow::setWildEncountersUIEnabled(bool enabled) { void MainWindow::setProjectSpecificUIVisibility() { ui->actionUse_Poryscript->setChecked(projectConfig.getUsePoryScript()); - this->setWildEncountersUIEnabled(projectConfig.getEncounterJsonActive()); + this->setWildEncountersUIEnabled(userConfig.getEncounterJsonActive()); switch (projectConfig.getBaseGameVersion()) { @@ -509,6 +509,8 @@ bool MainWindow::openProject(QString dir) { this->statusBar()->showMessage(QString("Opening project %1").arg(nativeDir)); bool success = true; + userConfig.setProjectDir(dir); + userConfig.load(); projectConfig.setProjectDir(dir); projectConfig.load(); @@ -570,7 +572,7 @@ QString MainWindow::getDefaultMap() { if (editor && editor->project) { QList names = editor->project->groupedMapNames; if (!names.isEmpty()) { - QString recentMap = projectConfig.getRecentMap(); + QString recentMap = userConfig.getRecentMap(); if (!recentMap.isNull() && recentMap.length() > 0) { for (int i = 0; i < names.length(); i++) { if (names.value(i).contains(recentMap)) { @@ -597,8 +599,8 @@ QString MainWindow::getExistingDirectory(QString dir) { void MainWindow::on_action_Open_Project_triggered() { QString recent = "."; - if (!projectConfig.getRecentMap().isEmpty()) { - recent = projectConfig.getRecentMap(); + if (!userConfig.getRecentMap().isEmpty()) { + recent = userConfig.getRecentMap(); } QString dir = getExistingDirectory(recent); if (!dir.isEmpty()) { @@ -742,7 +744,7 @@ void MainWindow::openWarpMap(QString map_name, QString event_id, QString event_g } void MainWindow::setRecentMap(QString mapName) { - projectConfig.setRecentMap(mapName); + userConfig.setRecentMap(mapName); } void MainWindow::displayMapProperties() { @@ -1707,7 +1709,7 @@ void MainWindow::on_mainTabBar_tabBarClicked(int index) editor->setEditingConnections(); } if (index != 4) { - if (projectConfig.getEncounterJsonActive()) + if (userConfig.getEncounterJsonActive()) editor->saveEncounterTabData(); } if (index != 1) { @@ -1758,7 +1760,7 @@ void MainWindow::on_actionUse_Encounter_Json_triggered(bool checked) warning.setText("You must reload the project for this setting to take effect."); warning.setIcon(QMessageBox::Information); warning.exec(); - projectConfig.setEncounterJsonActive(checked); + userConfig.setEncounterJsonActive(checked); } void MainWindow::on_actionMonitor_Project_Files_triggered(bool checked) @@ -3217,6 +3219,7 @@ void MainWindow::closeEvent(QCloseEvent *event) { } } projectConfig.save(); + userConfig.save(); } porymapConfig.setMainGeometry( diff --git a/src/mainwindow_scriptapi.cpp b/src/mainwindow_scriptapi.cpp index 5875bb08..75d6b417 100644 --- a/src/mainwindow_scriptapi.cpp +++ b/src/mainwindow_scriptapi.cpp @@ -1052,7 +1052,7 @@ QString MainWindow::getBaseGameVersion() { } QList MainWindow::getCustomScripts() { - return projectConfig.getCustomScripts(); + return userConfig.getCustomScripts(); } int MainWindow::getMainTab() { @@ -1065,7 +1065,7 @@ void MainWindow::setMainTab(int index) { if (!this->ui || !this->ui->mainTabBar || index < 0 || index >= this->ui->mainTabBar->count()) return; // Can't select Wild Encounters tab if it's disabled - if (index == 4 && !projectConfig.getEncounterJsonActive()) + if (index == 4 && !userConfig.getEncounterJsonActive()) return; this->on_mainTabBar_tabBarClicked(index); } diff --git a/src/project.cpp b/src/project.cpp index beda1e79..706cc306 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -727,7 +727,7 @@ void Project::saveMapGroups() { } void Project::saveWildMonData() { - if (!projectConfig.getEncounterJsonActive()) return; + if (!userConfig.getEncounterJsonActive()) return; QString wildEncountersJsonFilepath = QString("%1/src/data/wild_encounters.json").arg(root); QFile wildEncountersFile(wildEncountersJsonFilepath); @@ -1716,7 +1716,7 @@ bool Project::readWildMonData() { wildMonFields.clear(); wildMonData.clear(); encounterGroupLabels.clear(); - if (!projectConfig.getEncounterJsonActive()) { + if (!userConfig.getEncounterJsonActive()) { return true; } @@ -1727,7 +1727,7 @@ bool Project::readWildMonData() { if (!parser.tryParseOrderedJsonFile(&wildMonObj, wildMonJsonFilepath)) { // Failing to read wild encounters data is not a critical error, just disable the // encounter editor and log a warning in case the user intended to have this data. - projectConfig.setEncounterJsonActive(false); + userConfig.setEncounterJsonActive(false); emit disableWildEncountersUI(); logWarn(QString("Failed to read wild encounters from %1").arg(wildMonJsonFilepath)); return true; @@ -2295,7 +2295,7 @@ bool Project::readObjEventGfxConstants() { bool Project::readMiscellaneousConstants() { miscConstants.clear(); - if (projectConfig.getEncounterJsonActive()) { + if (userConfig.getEncounterJsonActive()) { QString filename = "include/constants/pokemon.h"; fileWatcher.addPath(root + "/" + filename); QMap pokemonDefines = parser.readCDefines(filename, { "MIN_", "MAX_" }); diff --git a/src/scripting.cpp b/src/scripting.cpp index ef757464..58f64b1c 100644 --- a/src/scripting.cpp +++ b/src/scripting.cpp @@ -30,7 +30,7 @@ Scripting::Scripting(MainWindow *mainWindow) { this->engine = new QJSEngine(mainWindow); this->engine->installExtensions(QJSEngine::ConsoleExtension); this->engine->globalObject().setProperty("map", this->engine->newQObject(mainWindow)); - for (QString script : projectConfig.getCustomScripts()) { + for (QString script : userConfig.getCustomScripts()) { this->filepaths.append(script); } this->loadModules(this->filepaths); @@ -40,7 +40,7 @@ void Scripting::loadModules(QStringList moduleFiles) { for (QString filepath : moduleFiles) { QJSValue module = this->engine->importModule(filepath); if (module.isError()) { - QString relativePath = QDir::cleanPath(projectConfig.getProjectDir() + QDir::separator() + filepath); + QString relativePath = QDir::cleanPath(userConfig.getProjectDir() + QDir::separator() + filepath); module = this->engine->importModule(relativePath); if (tryErrorJS(module)) continue; } From 3d9cd2ad0d827b83621981ea652da437e4dc52e0 Mon Sep 17 00:00:00 2001 From: tustin2121 Date: Thu, 1 Sep 2022 12:14:47 -0400 Subject: [PATCH 2/5] Moving paths to project config - Replaced all instances of hardcoded paths with requesting a path from the new project config file properties for "path/". - As a result, all default paths hardcoded into porymap are now in one place. - When reading the config file, it now trims out white space around the key and value. --- docsrc/manual/project-files.rst | 3 + include/config.h | 48 +++++++++++++++ src/config.cpp | 81 ++++++++++++++++++++++++- src/mainwindow.cpp | 5 +- src/project.cpp | 104 ++++++++++++++++---------------- src/ui/regionmapeditor.cpp | 8 +-- 6 files changed, 190 insertions(+), 59 deletions(-) diff --git a/docsrc/manual/project-files.rst b/docsrc/manual/project-files.rst index 46554bb5..4c3685c6 100644 --- a/docsrc/manual/project-files.rst +++ b/docsrc/manual/project-files.rst @@ -33,16 +33,19 @@ to a file, it probably is not a good idea to edit yourself unless otherwise note include/constants/flags.h, yes, no, include/constants/vars.h, yes, no, include/constants/weather.h, yes, no, + include/constants/songs.h, yes, no, include/constants/heal_locations.h, no, yes, include/constants/pokemon.h, yes, no, reads min and max level constants include/constants/map_types.h, yes, no, include/constants/trainer_types.h, yes, no, include/constants/secret_bases.h, yes, no, pokeemerald and pokeruby only include/constants/event_object_movement.h, yes, no, + include/constants/event_objects.h, yes, no, include/constants/event_bg.h, yes, no, include/constants/region_map_sections.h, yes, no, include/constants/metatile_labels.h, yes, yes, include/constants/metatile_behaviors.h, yes, no, include/fieldmap.h, yes, no, reads tileset related constants + src/event_object_movement.c, yes, no, diff --git a/include/config.h b/include/config.h index 9746ccf6..7e00b5a2 100644 --- a/include/config.h +++ b/include/config.h @@ -139,6 +139,50 @@ enum BaseGameVersion { pokeemerald, }; +enum ProjectFilePath { + data_map_folders, + data_scripts_folders, + data_layouts_folders, + data_event_scripts, + json_map_groups, + json_layouts, + json_wild_encounters, + json_region_map_entries, + json_region_porymap_cfg, + tilesets_headers, + tilesets_graphics, + tilesets_metatiles, + data_obj_event_gfx_pointers, + data_obj_event_gfx_info, + data_obj_event_pic_tables, + data_obj_event_gfx, + data_pokemon_gfx, + data_heal_locations, + data_region_map_entries, + constants_global, + constants_map_groups, + constants_items, + constants_opponents, + constants_flags, + constants_vars, + constants_weather, + constants_songs, + constants_heal_locations, + constants_pokemon, + constants_map_types, + constants_trainer_types, + constants_secret_bases, + constants_obj_event_movement, + constants_obj_events, + constants_event_bg, + constants_region_map_sections, + constants_metatile_labels, + constants_metatile_behaviors, + constants_fieldmap, + path_initial_facing_table, + path_pokemon_icon_table, +}; + class ProjectConfig: public KeyValueConfigBase { public: @@ -157,6 +201,7 @@ public: this->enableFloorNumber = false; this->createMapTextFile = false; this->enableTripleLayerMetatiles = false; + this->filePaths.clear(); this->readKeys.clear(); } void setBaseGameVersion(BaseGameVersion baseGameVersion); @@ -186,6 +231,8 @@ public: bool getCreateMapTextFileEnabled(); void setTripleLayerMetatilesEnabled(bool enable); bool getTripleLayerMetatilesEnabled(); + void setFilePath(ProjectFilePath pathId, QString path); + QString getFilePath(ProjectFilePath pathId); protected: virtual QString getConfigFilepath() override; virtual void parseConfigKeyValue(QString key, QString value) override; @@ -195,6 +242,7 @@ protected: private: BaseGameVersion baseGameVersion; QString projectDir; + QMap filePaths; bool usePoryScript; bool useCustomBorderSize; bool enableEventWeatherTrigger; diff --git a/src/config.cpp b/src/config.cpp index 4f9d80ad..83f512b6 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -15,6 +15,59 @@ #include #include +const QMap> defaultPaths = { + {ProjectFilePath::data_map_folders, { "data_map_folders", "data/maps/"}}, + {ProjectFilePath::data_scripts_folders, { "data_scripts_folders", "data/scripts/"}}, + {ProjectFilePath::data_layouts_folders, { "data_layouts_folders", "data/layouts/"}}, + {ProjectFilePath::data_event_scripts, { "data_event_scripts", "data/event_scripts.s"}}, + {ProjectFilePath::json_map_groups, { "json_map_groups", "data/maps/map_groups.json"}}, + {ProjectFilePath::json_layouts, { "json_layouts", "data/layouts/layouts.json"}}, + {ProjectFilePath::json_wild_encounters, { "json_wild_encounters", "src/data/wild_encounters.json"}}, + {ProjectFilePath::json_region_map_entries, { "json_region_map_entries", "src/data/region_map/region_map_sections.json"}}, + {ProjectFilePath::json_region_porymap_cfg, { "json_region_porymap_cfg", "src/data/region_map/porymap_config.json"}}, + {ProjectFilePath::tilesets_headers, { "tilesets_headers", "data/tilesets/headers.inc"}}, + {ProjectFilePath::tilesets_graphics, { "tilesets_graphics", "data/tilesets/graphics.inc"}}, + {ProjectFilePath::tilesets_metatiles, { "tilesets_metatiles", "data/tilesets/metatiles.inc"}}, + {ProjectFilePath::data_obj_event_gfx_pointers, { "data_obj_event_gfx_pointers", "src/data/object_events/object_event_graphics_info_pointers.h"}}, + {ProjectFilePath::data_obj_event_gfx_info, { "data_obj_event_gfx_info", "src/data/object_events/object_event_graphics_info.h"}}, + {ProjectFilePath::data_obj_event_pic_tables, { "data_obj_event_pic_tables", "src/data/object_events/object_event_pic_tables.h"}}, + {ProjectFilePath::data_obj_event_gfx, { "data_obj_event_gfx", "src/data/object_events/object_event_graphics.h"}}, + {ProjectFilePath::data_pokemon_gfx, { "data_pokemon_gfx", "src/data/graphics/pokemon.h"}}, + {ProjectFilePath::data_heal_locations, { "data_heal_locations", "src/data/heal_locations.h"}}, + {ProjectFilePath::data_region_map_entries, { "data_region_map_entries", "src/data/region_map/region_map_entries.h"}}, + {ProjectFilePath::constants_global, { "constants_global", "include/constants/global.h"}}, + {ProjectFilePath::constants_map_groups, { "constants_map_groups", "include/constants/map_groups.h"}}, + {ProjectFilePath::constants_items, { "constants_items", "include/constants/items.h"}}, + {ProjectFilePath::constants_opponents, { "constants_opponents", "include/constants/opponents.h"}}, + {ProjectFilePath::constants_flags, { "constants_flags", "include/constants/flags.h"}}, + {ProjectFilePath::constants_vars, { "constants_vars", "include/constants/vars.h"}}, + {ProjectFilePath::constants_weather, { "constants_weather", "include/constants/weather.h"}}, + {ProjectFilePath::constants_songs, { "constants_songs", "include/constants/songs.h"}}, + {ProjectFilePath::constants_heal_locations, { "constants_heal_locations", "include/constants/heal_locations.h"}}, + {ProjectFilePath::constants_pokemon, { "constants_pokemon", "include/constants/pokemon.h"}}, + {ProjectFilePath::constants_map_types, { "constants_map_types", "include/constants/map_types.h"}}, + {ProjectFilePath::constants_trainer_types, { "constants_trainer_types", "include/constants/trainer_types.h"}}, + {ProjectFilePath::constants_secret_bases, { "constants_secret_bases", "include/constants/secret_bases.h"}}, + {ProjectFilePath::constants_obj_event_movement, { "constants_obj_event_movement", "include/constants/event_object_movement.h"}}, + {ProjectFilePath::constants_obj_events, { "constants_obj_events", "include/constants/event_objects.h"}}, + {ProjectFilePath::constants_event_bg, { "constants_event_bg", "include/constants/event_bg.h"}}, + {ProjectFilePath::constants_region_map_sections, { "constants_region_map_sections", "include/constants/region_map_sections.h"}}, + {ProjectFilePath::constants_metatile_labels, { "constants_metatile_labels", "include/constants/metatile_labels.h"}}, + {ProjectFilePath::constants_metatile_behaviors, { "constants_metatile_behaviors", "include/constants/metatile_behaviors.h"}}, + {ProjectFilePath::constants_fieldmap, { "constants_fieldmap", "include/fieldmap.h"}}, + {ProjectFilePath::path_pokemon_icon_table, { "path_pokemon_icon_table", "src/pokemon_icon.c"}}, + {ProjectFilePath::path_initial_facing_table, { "path_initial_facing_table", "src/event_object_movement.c"}}, +}; + +std::optional reverseDefaultPaths(QString str) { + for (auto it = defaultPaths.constKeyValueBegin(); it != defaultPaths.constKeyValueEnd(); ++it) { + if (it->second.first == str) return it->first; + } + return std::nullopt; +} + + + KeyValueConfigBase::~KeyValueConfigBase() { } @@ -56,7 +109,7 @@ void KeyValueConfigBase::load() { continue; } - this->parseConfigKeyValue(match.captured("key").toLower(), match.captured("value")); + this->parseConfigKeyValue(match.captured("key").trimmed().toLower(), match.captured("value").trimmed()); } this->setUnreadKeys(); @@ -222,6 +275,7 @@ QMap PorymapConfig::getKeyValueMap() { map.insert("theme", this->theme); map.insert("text_editor_open_directory", this->textEditorOpenFolder); map.insert("text_editor_goto_line", this->textEditorGotoLine); + return map; } @@ -505,6 +559,13 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) { } } #endif + } else if (key.startsWith("path/")) { + auto k = reverseDefaultPaths(key.mid(5)); + if (k.has_value()) { + this->filePaths[k.value()] = value; + } else { + logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key)); + } } else { logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key)); } @@ -539,6 +600,9 @@ QMap ProjectConfig::getKeyValueMap() { map.insert("enable_floor_number", QString::number(this->enableFloorNumber)); map.insert("create_map_text_file", QString::number(this->createMapTextFile)); map.insert("enable_triple_layer_metatiles", QString::number(this->enableTripleLayerMetatiles)); + for (auto it = this->filePaths.constKeyValueBegin(); it != this->filePaths.constKeyValueEnd(); ++it) { + map.insert("path/"+defaultPaths[it->first].first, it->second); + } return map; } @@ -590,6 +654,21 @@ QString ProjectConfig::getProjectDir() { return this->projectDir; } +void ProjectConfig::setFilePath(ProjectFilePath pathId, QString path) { + if (!defaultPaths.contains(pathId)) return; + this->filePaths[pathId] = path; +} + +QString ProjectConfig::getFilePath(ProjectFilePath pathId) { + if (this->filePaths.contains(pathId)) { + return this->filePaths[pathId]; + } else if (defaultPaths.contains(pathId)) { + return defaultPaths[pathId].second; + } else { + return QString(); + } +} + void ProjectConfig::setBaseGameVersion(BaseGameVersion baseGameVersion) { this->baseGameVersion = baseGameVersion; this->save(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 9986a5bc..422d5f4b 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1865,8 +1865,9 @@ void MainWindow::addNewEvent(QString event_type) msgBox.setText("Failed to add new event"); if (Event::typeToGroup(event_type) == EventGroup::Object) { msgBox.setInformativeText(QString("The limit for object events (%1) has been reached.\n\n" - "This limit can be adjusted with OBJECT_EVENT_TEMPLATES_COUNT in 'include/constants/global.h'.") - .arg(editor->project->getMaxObjectEvents())); + "This limit can be adjusted with OBJECT_EVENT_TEMPLATES_COUNT in '%2'.") + .arg(editor->project->getMaxObjectEvents()) + .arg(projectConfig.getFilePath(ProjectFilePath::constants_global))); } msgBox.setDefaultButton(QMessageBox::Ok); msgBox.setIcon(QMessageBox::Icon::Warning); diff --git a/src/project.cpp b/src/project.cpp index 706cc306..a5cda297 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -183,7 +183,7 @@ bool Project::loadMapData(Map* map) { return true; } - QString mapFilepath = QString("%1/data/maps/%2/map.json").arg(root).arg(map->name); + QString mapFilepath = QString("%1/%3%2/map.json").arg(root).arg(map->name).arg(projectConfig.getFilePath(ProjectFilePath::data_map_folders)); QJsonDocument mapDoc; if (!parser.tryParseJsonFile(&mapDoc, mapFilepath)) { logError(QString("Failed to read map data from %1").arg(mapFilepath)); @@ -425,7 +425,7 @@ QString Project::readMapLayoutId(QString map_name) { return mapCache.value(map_name)->layoutId; } - QString mapFilepath = QString("%1/data/maps/%2/map.json").arg(root).arg(map_name); + QString mapFilepath = QString("%1/%3%2/map.json").arg(root).arg(map_name).arg(projectConfig.getFilePath(ProjectFilePath::data_map_folders)); QJsonDocument mapDoc; if (!parser.tryParseJsonFile(&mapDoc, mapFilepath)) { logError(QString("Failed to read map layout id from %1").arg(mapFilepath)); @@ -441,7 +441,7 @@ QString Project::readMapLocation(QString map_name) { return mapCache.value(map_name)->location; } - QString mapFilepath = QString("%1/data/maps/%2/map.json").arg(root).arg(map_name); + QString mapFilepath = QString("%1/%3%2/map.json").arg(root).arg(map_name).arg(projectConfig.getFilePath(ProjectFilePath::data_map_folders)); QJsonDocument mapDoc; if (!parser.tryParseJsonFile(&mapDoc, mapFilepath)) { logError(QString("Failed to read map's region map section from %1").arg(mapFilepath)); @@ -508,7 +508,7 @@ bool Project::readMapLayouts() { mapLayouts.clear(); mapLayoutsTable.clear(); - QString layoutsFilepath = QString("%1/data/layouts/layouts.json").arg(root); + QString layoutsFilepath = QString("%1/%2").arg(root).arg(projectConfig.getFilePath(ProjectFilePath::json_layouts)); fileWatcher.addPath(layoutsFilepath); QJsonDocument layoutsDoc; if (!parser.tryParseJsonFile(&layoutsDoc, layoutsFilepath)) { @@ -627,7 +627,7 @@ bool Project::readMapLayouts() { } void Project::saveMapLayouts() { - QString layoutsFilepath = QString("%1/data/layouts/layouts.json").arg(root); + QString layoutsFilepath = QString("%1/%2").arg(root).arg(projectConfig.getFilePath(ProjectFilePath::json_layouts)); QFile layoutsFile(layoutsFilepath); if (!layoutsFile.open(QIODevice::WriteOnly)) { logError(QString("Error: Could not open %1 for writing").arg(layoutsFilepath)); @@ -679,8 +679,8 @@ void Project::setNewMapLayout(Map* map) { layout->height = QString::number(getDefaultMapSize()); layout->border_width = QString::number(DEFAULT_BORDER_WIDTH); layout->border_height = QString::number(DEFAULT_BORDER_HEIGHT); - layout->border_path = QString("data/layouts/%1/border.bin").arg(map->name); - layout->blockdata_path = QString("data/layouts/%1/map.bin").arg(map->name); + layout->border_path = QString("%2%1/border.bin").arg(map->name).arg(projectConfig.getFilePath(ProjectFilePath::data_layouts_folders)); + layout->blockdata_path = QString("%2%1/map.bin").arg(map->name).arg(projectConfig.getFilePath(ProjectFilePath::data_layouts_folders)); layout->tileset_primary_label = tilesetLabels["primary"].value(0, "gTileset_General"); layout->tileset_secondary_label = tilesetLabels["secondary"].value(0, projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered ? "gTileset_PalletTown" : "gTileset_Petalburg"); map->layout = layout; @@ -692,7 +692,7 @@ void Project::setNewMapLayout(Map* map) { } void Project::saveMapGroups() { - QString mapGroupsFilepath = QString("%1/data/maps/map_groups.json").arg(root); + QString mapGroupsFilepath = QString("%1/%2").arg(root).arg(projectConfig.getFilePath(ProjectFilePath::json_map_groups)); QFile mapGroupsFile(mapGroupsFilepath); if (!mapGroupsFile.open(QIODevice::WriteOnly)) { logError(QString("Error: Could not open %1 for writing").arg(mapGroupsFilepath)); @@ -729,7 +729,7 @@ void Project::saveMapGroups() { void Project::saveWildMonData() { if (!userConfig.getEncounterJsonActive()) return; - QString wildEncountersJsonFilepath = QString("%1/src/data/wild_encounters.json").arg(root); + QString wildEncountersJsonFilepath = QString("%1/%2").arg(root).arg(projectConfig.getFilePath(ProjectFilePath::json_wild_encounters)); QFile wildEncountersFile(wildEncountersJsonFilepath); if (!wildEncountersFile.open(QIODevice::WriteOnly)) { logError(QString("Error: Could not open %1 for writing").arg(wildEncountersJsonFilepath)); @@ -849,7 +849,7 @@ void Project::saveMapConstantsHeader() { text += QString("#define MAP_GROUPS_COUNT %1\n\n").arg(groupNum); text += QString("#endif // GUARD_CONSTANTS_MAP_GROUPS_H\n"); - QString mapGroupFilepath = root + "/include/constants/map_groups.h"; + QString mapGroupFilepath = root + "/" + projectConfig.getFilePath(ProjectFilePath::constants_map_groups); ignoreWatchedFileTemporarily(mapGroupFilepath); saveTextFile(mapGroupFilepath, text); } @@ -953,11 +953,11 @@ void Project::saveHealLocationStruct(Map *map) { data_text += QString("};\n"); constants_text += QString("\n#endif // GUARD_CONSTANTS_HEAL_LOCATIONS_H\n"); - QString healLocationFilepath = root + "/src/data/heal_locations.h"; + QString healLocationFilepath = root + "/" + projectConfig.getFilePath(ProjectFilePath::data_heal_locations); ignoreWatchedFileTemporarily(healLocationFilepath); saveTextFile(healLocationFilepath, data_text); - QString healLocationConstantsFilepath = root + "/include/constants/heal_locations.h"; + QString healLocationConstantsFilepath = root + "/" + projectConfig.getFilePath(ProjectFilePath::constants_heal_locations); ignoreWatchedFileTemporarily(healLocationConstantsFilepath); saveTextFile(healLocationConstantsFilepath, constants_text); } @@ -981,7 +981,7 @@ void Project::saveTilesetMetatileLabels(Tileset *primaryTileset, Tileset *second QMap defines; bool definesFileModified = false; - QString metatileLabelsFilename = "include/constants/metatile_labels.h"; + QString metatileLabelsFilename = projectConfig.getFilePath(ProjectFilePath::constants_metatile_labels); defines = parser.readCDefines(metatileLabelsFilename, (QStringList() << "METATILE_")); // Purge old entries from the file. @@ -1630,7 +1630,7 @@ void Project::loadTilesetMetatiles(Tileset* tileset) { void Project::loadTilesetMetatileLabels(Tileset* tileset) { QString tilesetPrefix = QString("METATILE_%1_").arg(QString(tileset->name).replace("gTileset_", "")); - QString metatileLabelsFilename = "include/constants/metatile_labels.h"; + QString metatileLabelsFilename = projectConfig.getFilePath(ProjectFilePath::constants_metatile_labels); fileWatcher.addPath(root + "/" + metatileLabelsFilename); QMap labels = parser.readCDefines(metatileLabelsFilename, QStringList() << tilesetPrefix); @@ -1720,7 +1720,7 @@ bool Project::readWildMonData() { return true; } - QString wildMonJsonFilepath = QString("%1/src/data/wild_encounters.json").arg(root); + QString wildMonJsonFilepath = QString("%1/%2").arg(root).arg(projectConfig.getFilePath(ProjectFilePath::json_wild_encounters)); fileWatcher.addPath(wildMonJsonFilepath); OrderedJson::object wildMonObj; @@ -1944,7 +1944,7 @@ QMap Project::getTilesetLabels() { bool Project::readTilesetProperties() { QStringList definePrefixes; definePrefixes << "\\bNUM_"; - QString filename = "include/fieldmap.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_fieldmap); fileWatcher.addPath(root + "/" + filename); QMap defines = parser.readCDefines(filename, definePrefixes); @@ -2002,7 +2002,7 @@ bool Project::readTilesetProperties() { bool Project::readMaxMapDataSize() { QStringList definePrefixes; definePrefixes << "\\bMAX_"; - QString filename = "include/fieldmap.h"; // already in fileWatcher from readTilesetProperties + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_fieldmap); // already in fileWatcher from readTilesetProperties QMap defines = parser.readCDefines(filename, definePrefixes); auto it = defines.find("MAX_MAP_DATA_SIZE"); @@ -2031,7 +2031,7 @@ bool Project::readRegionMapSections() { this->mapSectionValueToName.clear(); QStringList prefixes = (QStringList() << "\\bMAPSEC_"); - QString filename = "include/constants/region_map_sections.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_region_map_sections); fileWatcher.addPath(root + "/" + filename); this->mapSectionNameToValue = parser.readCDefines(filename, prefixes); if (this->mapSectionNameToValue.isEmpty()) { @@ -2048,7 +2048,7 @@ bool Project::readRegionMapSections() { bool Project::readHealLocations() { dataQualifiers.clear(); healLocations.clear(); - QString filename = "src/data/heal_locations.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::data_heal_locations); fileWatcher.addPath(root + "/" + filename); QString text = parser.readTextFile(root + "/" + filename); text.replace(QRegularExpression("//.*?(\r\n?|\n)|/\\*.*?\\*/", QRegularExpression::DotMatchesEverythingOption), ""); @@ -2095,7 +2095,7 @@ bool Project::readHealLocations() { bool Project::readItemNames() { QStringList prefixes("\\bITEM_(?!(B_)?USE_)"); // Exclude ITEM_USE_ and ITEM_B_USE_ constants - QString filename = "include/constants/items.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_items); fileWatcher.addPath(root + "/" + filename); itemNames = parser.readCDefinesSorted(filename, prefixes); if (itemNames.isEmpty()) { @@ -2108,12 +2108,12 @@ bool Project::readItemNames() { bool Project::readFlagNames() { // First read MAX_TRAINERS_COUNT, used to skip over trainer flags // If this fails flags may simply be out of order, no need to check for success - QString opponentsFilename = "include/constants/opponents.h"; + QString opponentsFilename = projectConfig.getFilePath(ProjectFilePath::constants_opponents); fileWatcher.addPath(root + "/" + opponentsFilename); QMap maxTrainers = parser.readCDefines(opponentsFilename, QStringList() << "\\bMAX_"); // Parse flags QStringList prefixes("\\bFLAG_"); - QString flagsFilename = "include/constants/flags.h"; + QString flagsFilename = projectConfig.getFilePath(ProjectFilePath::constants_flags); fileWatcher.addPath(root + "/" + flagsFilename); flagNames = parser.readCDefinesSorted(flagsFilename, prefixes, maxTrainers); if (flagNames.isEmpty()) { @@ -2125,7 +2125,7 @@ bool Project::readFlagNames() { bool Project::readVarNames() { QStringList prefixes("\\bVAR_"); - QString filename = "include/constants/vars.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_vars); fileWatcher.addPath(root + "/" + filename); varNames = parser.readCDefinesSorted(filename, prefixes); if (varNames.isEmpty()) { @@ -2137,7 +2137,7 @@ bool Project::readVarNames() { bool Project::readMovementTypes() { QStringList prefixes("\\bMOVEMENT_TYPE_"); - QString filename = "include/constants/event_object_movement.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_obj_event_movement); fileWatcher.addPath(root + "/" + filename); movementTypes = parser.readCDefinesSorted(filename, prefixes); if (movementTypes.isEmpty()) { @@ -2148,7 +2148,7 @@ bool Project::readMovementTypes() { } bool Project::readInitialFacingDirections() { - QString filename = "src/event_object_movement.c"; + QString filename = projectConfig.getFilePath(ProjectFilePath::path_initial_facing_table); fileWatcher.addPath(root + "/" + filename); facingDirections = parser.readNamedIndexCArray(filename, "gInitialMovementTypeFacingDirections"); if (facingDirections.isEmpty()) { @@ -2160,7 +2160,7 @@ bool Project::readInitialFacingDirections() { bool Project::readMapTypes() { QStringList prefixes("\\bMAP_TYPE_"); - QString filename = "include/constants/map_types.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_map_types); fileWatcher.addPath(root + "/" + filename); mapTypes = parser.readCDefinesSorted(filename, prefixes); if (mapTypes.isEmpty()) { @@ -2172,9 +2172,9 @@ bool Project::readMapTypes() { bool Project::readMapBattleScenes() { QStringList prefixes("\\bMAP_BATTLE_SCENE_"); - QString filename = "include/constants/map_types.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_map_types); fileWatcher.addPath(root + "/" + filename); - mapBattleScenes = parser.readCDefinesSorted("include/constants/map_types.h", prefixes); + mapBattleScenes = parser.readCDefinesSorted(filename, prefixes); if (mapBattleScenes.isEmpty()) { logError(QString("Failed to read map battle scene constants from %1").arg(filename)); return false; @@ -2184,7 +2184,7 @@ bool Project::readMapBattleScenes() { bool Project::readWeatherNames() { QStringList prefixes("\\bWEATHER_"); - QString filename = "include/constants/weather.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_weather); fileWatcher.addPath(root + "/" + filename); weatherNames = parser.readCDefinesSorted(filename, prefixes); if (weatherNames.isEmpty()) { @@ -2199,7 +2199,7 @@ bool Project::readCoordEventWeatherNames() { return true; QStringList prefixes("\\bCOORD_EVENT_WEATHER_"); - QString filename = "include/constants/weather.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_weather); fileWatcher.addPath(root + "/" + filename); coordEventWeatherNames = parser.readCDefinesSorted(filename, prefixes); if (coordEventWeatherNames.isEmpty()) { @@ -2214,7 +2214,7 @@ bool Project::readSecretBaseIds() { return true; QStringList prefixes("\\bSECRET_BASE_[A-Za-z0-9_]*_[0-9]+"); - QString filename = "include/constants/secret_bases.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_secret_bases); fileWatcher.addPath(root + "/" + filename); secretBaseIds = parser.readCDefinesSorted(filename, prefixes); if (secretBaseIds.isEmpty()) { @@ -2226,7 +2226,7 @@ bool Project::readSecretBaseIds() { bool Project::readBgEventFacingDirections() { QStringList prefixes("\\bBG_EVENT_PLAYER_FACING_"); - QString filename = "include/constants/event_bg.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_event_bg); fileWatcher.addPath(root + "/" + filename); bgEventFacingDirections = parser.readCDefinesSorted(filename, prefixes); if (bgEventFacingDirections.isEmpty()) { @@ -2238,7 +2238,7 @@ bool Project::readBgEventFacingDirections() { bool Project::readTrainerTypes() { QStringList prefixes("\\bTRAINER_TYPE_"); - QString filename = "include/constants/trainer_types.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_trainer_types); fileWatcher.addPath(root + "/" + filename); trainerTypes = parser.readCDefinesSorted(filename, prefixes); if (trainerTypes.isEmpty()) { @@ -2253,7 +2253,7 @@ bool Project::readMetatileBehaviors() { this->metatileBehaviorMapInverse.clear(); QStringList prefixes("\\bMB_"); - QString filename = "include/constants/metatile_behaviors.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_metatile_behaviors); fileWatcher.addPath(root + "/" + filename); this->metatileBehaviorMap = parser.readCDefines(filename, prefixes); if (this->metatileBehaviorMap.isEmpty()) { @@ -2269,7 +2269,7 @@ bool Project::readMetatileBehaviors() { bool Project::readSongNames() { QStringList songDefinePrefixes{ "\\bSE_", "\\bMUS_" }; - QString filename = "include/constants/songs.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_songs); fileWatcher.addPath(root + "/" + filename); QMap songDefines = parser.readCDefines(filename, songDefinePrefixes); this->songNames = songDefines.keys(); @@ -2283,7 +2283,7 @@ bool Project::readSongNames() { bool Project::readObjEventGfxConstants() { QStringList objEventGfxPrefixes("\\bOBJ_EVENT_GFX_"); - QString filename = "include/constants/event_objects.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_obj_events); fileWatcher.addPath(root + "/" + filename); this->gfxDefines = parser.readCDefines(filename, objEventGfxPrefixes); if (this->gfxDefines.isEmpty()) { @@ -2296,14 +2296,14 @@ bool Project::readObjEventGfxConstants() { bool Project::readMiscellaneousConstants() { miscConstants.clear(); if (userConfig.getEncounterJsonActive()) { - QString filename = "include/constants/pokemon.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_pokemon); fileWatcher.addPath(root + "/" + filename); QMap pokemonDefines = parser.readCDefines(filename, { "MIN_", "MAX_" }); miscConstants.insert("max_level_define", pokemonDefines.value("MAX_LEVEL") > pokemonDefines.value("MIN_LEVEL") ? pokemonDefines.value("MAX_LEVEL") : 100); miscConstants.insert("min_level_define", pokemonDefines.value("MIN_LEVEL") < pokemonDefines.value("MAX_LEVEL") ? pokemonDefines.value("MIN_LEVEL") : 1); } - QString filename = "include/constants/global.h"; + QString filename = projectConfig.getFilePath(ProjectFilePath::constants_global); fileWatcher.addPath(root + "/" + filename); QStringList definePrefixes("\\bOBJECT_"); QMap defines = parser.readCDefines(filename, definePrefixes); @@ -2366,7 +2366,7 @@ QString Project::getScriptDefaultString(bool usePoryScript, QString mapName) con QString Project::getMapScriptsFilePath(const QString &mapName) const { const bool usePoryscript = projectConfig.getUsePoryScript(); - auto path = QDir::cleanPath(root + "/data/maps/" + mapName + "/scripts"); + auto path = QDir::cleanPath(root + projectConfig.getFilePath(ProjectFilePath::data_map_folders) + mapName + "/scripts"); auto extension = getScriptFileExtension(usePoryscript); if (usePoryscript && !QFile::exists(path + extension)) extension = getScriptFileExtension(false); @@ -2375,9 +2375,9 @@ QString Project::getMapScriptsFilePath(const QString &mapName) const { } QStringList Project::getEventScriptsFilePaths() const { - QStringList filePaths(QDir::cleanPath(root + "/data/event_scripts.s")); - const QString scriptsDir = QDir::cleanPath(root + "/data/scripts"); - const QString mapsDir = QDir::cleanPath(root + "/data/maps"); + QStringList filePaths(QDir::cleanPath(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_event_scripts))); + const QString scriptsDir = QDir::cleanPath(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_scripts_folders)); + const QString mapsDir = QDir::cleanPath(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_map_folders)); const bool usePoryscript = projectConfig.getUsePoryScript(); if (usePoryscript) { @@ -2463,12 +2463,12 @@ void Project::setEventPixmap(Event * event, bool forceLoad) { } bool Project::readEventGraphics() { - fileWatcher.addPaths(QStringList() << root + "/" + "src/data/object_events/object_event_graphics_info_pointers.h" - << root + "/" + "src/data/object_events/object_event_graphics_info.h" - << root + "/" + "src/data/object_events/object_event_pic_tables.h" - << root + "/" + "src/data/object_events/object_event_graphics.h"); + fileWatcher.addPaths(QStringList() << root + "/" + projectConfig.getFilePath(ProjectFilePath::data_obj_event_gfx_pointers) + << root + "/" + projectConfig.getFilePath(ProjectFilePath::data_obj_event_gfx_info) + << root + "/" + projectConfig.getFilePath(ProjectFilePath::data_obj_event_pic_tables) + << root + "/" + projectConfig.getFilePath(ProjectFilePath::data_obj_event_gfx)); - QMap pointerHash = parser.readNamedIndexCArray("src/data/object_events/object_event_graphics_info_pointers.h", "gObjectEventGraphicsInfoPointers"); + QMap pointerHash = parser.readNamedIndexCArray(projectConfig.getFilePath(ProjectFilePath::data_obj_event_gfx_pointers), "gObjectEventGraphicsInfoPointers"); qDeleteAll(eventGraphicsMap); eventGraphicsMap.clear(); @@ -2488,9 +2488,9 @@ bool Project::readEventGraphics() { QString dimensions_label = gfxInfoAttributes.value("oam"); QString subsprites_label = gfxInfoAttributes.value("subspriteTables"); - QString gfx_label = parser.readCArray("src/data/object_events/object_event_pic_tables.h", pic_label).value(0); + QString gfx_label = parser.readCArray(projectConfig.getFilePath(ProjectFilePath::data_obj_event_pic_tables), pic_label).value(0); gfx_label = gfx_label.section(QRegularExpression("[\\(\\)]"), 1, 1); - QString path = parser.readCIncbin("src/data/object_events/object_event_graphics.h", gfx_label); + QString path = parser.readCIncbin(projectConfig.getFilePath(ProjectFilePath::data_obj_event_gfx), gfx_label); if (!path.isNull()) { path = fixGraphicPath(path); @@ -2525,7 +2525,7 @@ QMap> Project::readObjEventGfxInfo() { // TODO: refactor this to be more general if we end up directly parsing C // for more use cases in the future. auto cParser = fex::Parser(); - auto tokens = fex::Lexer().LexFile((root + "/src/data/object_events/object_event_graphics_info.h").toStdString()); + auto tokens = fex::Lexer().LexFile((root + "/" + projectConfig.getFilePath(ProjectFilePath::data_obj_event_gfx_info)).toStdString()); auto gfxInfoObjects = cParser.ParseTopLevelObjects(tokens); QMap> gfxInfos; for (auto it = gfxInfoObjects.begin(); it != gfxInfoObjects.end(); it++) { @@ -2565,8 +2565,8 @@ QMap> Project::readObjEventGfxInfo() { bool Project::readSpeciesIconPaths() { speciesToIconPath.clear(); - QString srcfilename = "src/pokemon_icon.c"; - QString incfilename = "src/data/graphics/pokemon.h"; + QString srcfilename = projectConfig.getFilePath(ProjectFilePath::path_pokemon_icon_table); + QString incfilename = projectConfig.getFilePath(ProjectFilePath::data_pokemon_gfx); fileWatcher.addPath(root + "/" + srcfilename); fileWatcher.addPath(root + "/" + incfilename); QMap monIconNames = parser.readNamedIndexCArray(srcfilename, "gMonIconTable"); diff --git a/src/ui/regionmapeditor.cpp b/src/ui/regionmapeditor.cpp index 8e4f036c..dc2c458e 100644 --- a/src/ui/regionmapeditor.cpp +++ b/src/ui/regionmapeditor.cpp @@ -110,7 +110,7 @@ void RegionMapEditor::applyUserShortcuts() { bool RegionMapEditor::loadRegionMapEntries() { this->region_map_entries.clear(); - QString regionMapSectionFilepath = QString("%1/src/data/region_map/region_map_sections.json").arg(this->project->root); + QString regionMapSectionFilepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_map_entries)); ParseUtil parser; QJsonDocument sectionsDoc; @@ -140,7 +140,7 @@ bool RegionMapEditor::loadRegionMapEntries() { } bool RegionMapEditor::saveRegionMapEntries() { - QString regionMapSectionFilepath = QString("%1/src/data/region_map/region_map_sections.json").arg(this->project->root); + QString regionMapSectionFilepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_map_entries)); QFile sectionsFile(regionMapSectionFilepath); if (!sectionsFile.open(QIODevice::WriteOnly)) { @@ -508,7 +508,7 @@ bool RegionMapEditor::setup() { bool RegionMapEditor::load() { // check for config json file - QString jsonConfigFilepath = this->project->root + "/src/data/region_map/porymap_config.json"; + QString jsonConfigFilepath = this->project->root + "/" + projectConfig.getFilePath(ProjectFilePath::json_region_porymap_cfg); bool badConfig = true; @@ -586,7 +586,7 @@ void RegionMapEditor::saveConfig() { mapsObject["region_maps"] = mapArray; OrderedJson newConfigJson(mapsObject); - QString filepath = QString("%1/src/data/region_map/porymap_config.json").arg(this->project->root); + QString filepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_porymap_cfg)); QFile file(filepath); if (!file.open(QIODevice::WriteOnly)) { logError(QString("Error: Could not open %1 for writing").arg(filepath)); From 09a590e01afcabae67ce357f7f9c3d4e58890a24 Mon Sep 17 00:00:00 2001 From: tustin2121 Date: Thu, 1 Sep 2022 13:03:11 -0400 Subject: [PATCH 3/5] Fixing integration failure - Apparently Qt 5.15 operations are not allowed. --- src/config.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index 83f512b6..8cca9258 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -61,7 +61,7 @@ const QMap> defaultPaths = { std::optional reverseDefaultPaths(QString str) { for (auto it = defaultPaths.constKeyValueBegin(); it != defaultPaths.constKeyValueEnd(); ++it) { - if (it->second.first == str) return it->first; + if ((*it).second.first == str) return (*it).first; } return std::nullopt; } @@ -601,7 +601,7 @@ QMap ProjectConfig::getKeyValueMap() { map.insert("create_map_text_file", QString::number(this->createMapTextFile)); map.insert("enable_triple_layer_metatiles", QString::number(this->enableTripleLayerMetatiles)); for (auto it = this->filePaths.constKeyValueBegin(); it != this->filePaths.constKeyValueEnd(); ++it) { - map.insert("path/"+defaultPaths[it->first].first, it->second); + map.insert("path/"+defaultPaths[(*it).first].first, (*it).second); } return map; } From d97ed4b64f3bca22f2ff91ffd00d6bc1d52801ab Mon Sep 17 00:00:00 2001 From: tustin2121 Date: Thu, 1 Sep 2022 13:29:05 -0400 Subject: [PATCH 4/5] Removing optional - C++11 compliance: there's no optional, so use invalid enum value instead. --- src/config.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index 8cca9258..97f8ff7b 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -59,11 +59,11 @@ const QMap> defaultPaths = { {ProjectFilePath::path_initial_facing_table, { "path_initial_facing_table", "src/event_object_movement.c"}}, }; -std::optional reverseDefaultPaths(QString str) { +ProjectFilePath reverseDefaultPaths(QString str) { for (auto it = defaultPaths.constKeyValueBegin(); it != defaultPaths.constKeyValueEnd(); ++it) { if ((*it).second.first == str) return (*it).first; } - return std::nullopt; + return static_cast(-1); } @@ -561,8 +561,8 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) { #endif } else if (key.startsWith("path/")) { auto k = reverseDefaultPaths(key.mid(5)); - if (k.has_value()) { - this->filePaths[k.value()] = value; + if (k != static_cast(-1)) { + this->filePaths[k] = value; } else { logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key)); } From e241cdd1049cbb908b536ceedddff8a33aaf5302 Mon Sep 17 00:00:00 2001 From: tustin2121 Date: Thu, 22 Sep 2022 12:04:51 -0400 Subject: [PATCH 5/5] Fixed path composing bug with goto script --- src/project.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/project.cpp b/src/project.cpp index 4b8f949a..3fec0e05 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -2371,7 +2371,7 @@ QString Project::getScriptDefaultString(bool usePoryScript, QString mapName) con QString Project::getMapScriptsFilePath(const QString &mapName) const { const bool usePoryscript = projectConfig.getUsePoryScript(); - auto path = QDir::cleanPath(root + projectConfig.getFilePath(ProjectFilePath::data_map_folders) + mapName + "/scripts"); + auto path = QDir::cleanPath(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_map_folders) + "/" + mapName + "/scripts"); auto extension = getScriptFileExtension(usePoryscript); if (usePoryscript && !QFile::exists(path + extension)) extension = getScriptFileExtension(false);