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.
This commit is contained in:
tustin2121 2022-09-01 00:57:31 -04:00
parent 0fa71dc4c8
commit 8e83daac84
7 changed files with 147 additions and 62 deletions

View file

@ -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.

View file

@ -9,6 +9,8 @@
#include <QKeySequence>
#include <QMultiMap>
#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<QString> scripts);
QList<QString> 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<QString> 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<QString> scripts);
QList<QString> getCustomScripts();
protected:
virtual QString getConfigFilepath() override;
virtual void parseConfigKeyValue(QString key, QString value) override;
virtual QMap<QString, QString> 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<QString> customScripts;
QStringList readKeys;
};
extern UserConfig userConfig;
class QAction;
class Shortcut;

View file

@ -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<QString> 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<QString, QString> ProjectConfig::getKeyValueMap() {
QMap<QString, QString> 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<QString, QString> 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<QString> 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<QString> 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<QString, QString> UserConfig::getKeyValueMap() {
QMap<QString, QString> 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<QString> scripts) {
this->customScripts = scripts;
this->save();
}
QList<QString> ProjectConfig::getCustomScripts() {
QList<QString> UserConfig::getCustomScripts() {
return this->customScripts;
}

View file

@ -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<QStringList> 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(

View file

@ -1052,7 +1052,7 @@ QString MainWindow::getBaseGameVersion() {
}
QList<QString> 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);
}

View file

@ -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<QString, int> pokemonDefines = parser.readCDefines(filename, { "MIN_", "MAX_" });

View file

@ -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;
}