From 3ebc7a93d46da5705c1906fee2714dcb44cf82b7 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Fri, 19 Jan 2024 11:59:04 -0500 Subject: [PATCH] Soften launch requirements, fix some potential crashes --- CHANGELOG.md | 8 ++- include/project.h | 4 -- src/core/events.cpp | 22 +++--- src/mainwindow.cpp | 43 +++++------ src/project.cpp | 157 +++++++++++++++++------------------------ src/ui/newmappopup.cpp | 12 ++-- 6 files changed, 106 insertions(+), 140 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e546dc45..8d1b6e6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,13 @@ The **"Breaking Changes"** listed below are changes that have been made in the d ## [Unreleased] ### Changed -- If settings-specific features like Wild Encounters fail to load they are now only disabled for that session +- If Wild Encounters fail to load they are now only disabled for that session, and the settings remain unchanged. +- Defaults are used if project constants are missing, rather than failing to open the project or changing settings. ### Fixed -- Fix the Tileset Editor selectors scrolling to the wrong selection when zoomed -- Fix the Tileset Editor selectors getting extra white space when changing tilesets +- Fix the Tileset Editor selectors scrolling to the wrong selection when zoomed. +- Fix the Tileset Editor selectors getting extra white space when changing tilesets. +- Fix a crash when adding disabled events with the Pencil tool. ## [5.3.0] - 2024-01-15 ### Added diff --git a/include/project.h b/include/project.h index 89249d55..a7c3799d 100644 --- a/include/project.h +++ b/include/project.h @@ -78,8 +78,6 @@ public: bool usingAsmTilesets; QString importExportPath; QSet disabledSettingsNames; - bool weatherEventConstantsLoaded; - bool secretBaseConstantsLoaded; bool wildEncountersLoaded; void set_root(QString); @@ -165,8 +163,6 @@ public: void saveTilesetMetatiles(Tileset*); void saveTilesetTilesImage(Tileset*); void saveTilesetPalettes(Tileset*); - - QString defaultSong; void appendTilesetLabel(QString label, QString isSecondaryStr); bool readTilesetLabels(); bool readTilesetMetatileLabels(); diff --git a/src/core/events.cpp b/src/core/events.cpp index 1b9605fb..40067e22 100644 --- a/src/core/events.cpp +++ b/src/core/events.cpp @@ -233,8 +233,8 @@ bool ObjectEvent::loadFromJson(QJsonObject json, Project *) { } void ObjectEvent::setDefaultValues(Project *project) { - this->setGfx(project->gfxDefines.keys().first()); - this->setMovement(project->movementTypes.first()); + this->setGfx(project->gfxDefines.keys().value(0, "0")); + this->setMovement(project->movementTypes.value(0, "0")); this->setScript("NULL"); this->setTrainerType(project->trainerTypes.value(0, "0")); this->setFlag("0"); @@ -404,7 +404,7 @@ bool CloneObjectEvent::loadFromJson(QJsonObject json, Project *project) { } void CloneObjectEvent::setDefaultValues(Project *project) { - this->setGfx(project->gfxDefines.keys().first()); + this->setGfx(project->gfxDefines.keys().value(0, "0")); this->setTargetID(1); if (this->getMap()) this->setTargetMap(this->getMap()->name); } @@ -436,8 +436,8 @@ void CloneObjectEvent::loadPixmap(Project *project) { this->movement = clonedObject->getMovement(); } else { // Invalid object specified, use default graphics data (as would be shown in-game) - this->gfx = project->gfxDefines.key(0); - this->movement = project->movementTypes.first(); + this->gfx = project->gfxDefines.key(0, "0"); + this->movement = project->movementTypes.value(0, "0"); } EventGraphics *eventGfx = project->eventGraphicsMap.value(gfx, nullptr); @@ -596,7 +596,7 @@ bool TriggerEvent::loadFromJson(QJsonObject json, Project *) { void TriggerEvent::setDefaultValues(Project *project) { this->setScriptLabel("NULL"); - this->setScriptVar(project->varNames.first()); + this->setScriptVar(project->varNames.value(0, "0")); this->setScriptVarValue("0"); this->setElevation(0); } @@ -665,7 +665,7 @@ bool WeatherTriggerEvent::loadFromJson(QJsonObject json, Project *) { } void WeatherTriggerEvent::setDefaultValues(Project *project) { - this->setWeather(project->coordEventWeatherNames.first()); + this->setWeather(project->coordEventWeatherNames.value(0, "0")); this->setElevation(0); } @@ -734,7 +734,7 @@ bool SignEvent::loadFromJson(QJsonObject json, Project *) { } void SignEvent::setDefaultValues(Project *project) { - this->setFacingDirection(project->bgEventFacingDirections.first()); + this->setFacingDirection(project->bgEventFacingDirections.value(0, "0")); this->setScriptLabel("NULL"); this->setElevation(0); } @@ -819,8 +819,8 @@ bool HiddenItemEvent::loadFromJson(QJsonObject json, Project *) { } void HiddenItemEvent::setDefaultValues(Project *project) { - this->setItem(project->itemNames.first()); - this->setFlag(project->flagNames.first()); + this->setItem(project->itemNames.value(0, "0")); + this->setFlag(project->flagNames.value(0, "0")); if (projectConfig.getHiddenItemQuantityEnabled()) { this->setQuantity(1); } @@ -898,7 +898,7 @@ bool SecretBaseEvent::loadFromJson(QJsonObject json, Project *) { } void SecretBaseEvent::setDefaultValues(Project *project) { - this->setBaseID(project->secretBaseIds.first()); + this->setBaseID(project->secretBaseIds.value(0, "0")); this->setElevation(0); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index c4a128d9..58ba3f13 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -376,8 +376,8 @@ void MainWindow::setProjectSpecificUI() ui->label_AllowBiking->setVisible(hasFlags); ui->label_AllowEscaping->setVisible(hasFlags); - ui->newEventToolButton->newWeatherTriggerAction->setVisible(editor->project->weatherEventConstantsLoaded); - ui->newEventToolButton->newSecretBaseAction->setVisible(editor->project->secretBaseConstantsLoaded); + ui->newEventToolButton->newWeatherTriggerAction->setVisible(projectConfig.getEventWeatherTriggerEnabled()); + ui->newEventToolButton->newSecretBaseAction->setVisible(projectConfig.getEventSecretBaseEnabled()); ui->newEventToolButton->newCloneObjectAction->setVisible(projectConfig.getEventCloneObjectEnabled()); bool floorNumEnabled = projectConfig.getFloorNumberEnabled(); @@ -498,7 +498,10 @@ bool MainWindow::openProject(const QString &dir, bool initial) { } return false; } - this->statusBar()->showMessage(QString("Opening %1").arg(projectString)); + + const QString openMessage = QString("Opening %1").arg(projectString); + this->statusBar()->showMessage(openMessage); + logInfo(openMessage); userConfig.setProjectDir(dir); userConfig.load(); @@ -541,10 +544,7 @@ bool MainWindow::openProject(const QString &dir, bool initial) { } showWindowTitle(); - - const QString successMessage = QString("Opened %1").arg(projectString); - this->statusBar()->showMessage(successMessage); - logInfo(successMessage); + this->statusBar()->showMessage(QString("Opened %1").arg(projectString)); porymapConfig.addRecentProject(dir); refreshRecentProjectsMenu(); @@ -572,29 +572,22 @@ bool MainWindow::isProjectOpen() { } bool MainWindow::setInitialMap() { - QList names; + QStringList names; if (editor && editor->project) - names = editor->project->groupedMapNames; + names = editor->project->mapNames; + // Try to set most recently-opened map, if it's still in the list. QString recentMap = userConfig.getRecentMap(); - if (!recentMap.isEmpty()) { - // Make sure the recent map is still in the map list - for (int i = 0; i < names.length(); i++) { - if (names.value(i).contains(recentMap)) { - return setMap(recentMap, true); - } - } + if (!recentMap.isEmpty() && names.contains(recentMap) && setMap(recentMap, true)) + return true; + + // Failing that, try loading maps in the map list sequentially. + for (auto name : names) { + if (name != recentMap && setMap(name, true)) + return true; } - // Failing that, just get the first map in the list. - for (int i = 0; i < names.length(); i++) { - QStringList list = names.value(i); - if (list.length()) { - return setMap(list.value(0), true); - } - } - - logError("Failed to load any map names."); + logError("Failed to load any maps."); return false; } diff --git a/src/project.cpp b/src/project.cpp index 3550e859..fc9b989a 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1705,50 +1705,59 @@ bool Project::readWildMonData() { } bool Project::readMapGroups() { - mapConstantsToMapNames.clear(); - mapNamesToMapConstants.clear(); - mapGroups.clear(); + this->mapConstantsToMapNames.clear(); + this->mapNamesToMapConstants.clear(); + this->mapGroups.clear(); + this->groupNames.clear(); + this->groupedMapNames.clear(); + this->mapNames.clear(); - QString mapGroupsFilepath = root + "/" + projectConfig.getFilePath(ProjectFilePath::json_map_groups); - fileWatcher.addPath(mapGroupsFilepath); + const QString filepath = root + "/" + projectConfig.getFilePath(ProjectFilePath::json_map_groups); + fileWatcher.addPath(filepath); QJsonDocument mapGroupsDoc; - if (!parser.tryParseJsonFile(&mapGroupsDoc, mapGroupsFilepath)) { - logError(QString("Failed to read map groups from %1").arg(mapGroupsFilepath)); + if (!parser.tryParseJsonFile(&mapGroupsDoc, filepath)) { + logError(QString("Failed to read map groups from %1").arg(filepath)); return false; } QJsonObject mapGroupsObj = mapGroupsDoc.object(); QJsonArray mapGroupOrder = mapGroupsObj["group_order"].toArray(); - - QList groupedMaps; - QStringList maps; - QStringList groups; for (int groupIndex = 0; groupIndex < mapGroupOrder.size(); groupIndex++) { QString groupName = ParseUtil::jsonToQString(mapGroupOrder.at(groupIndex)); - QJsonArray mapNames = mapGroupsObj.value(groupName).toArray(); - groupedMaps.append(QStringList()); - groups.append(groupName); - for (int j = 0; j < mapNames.size(); j++) { - QString mapName = ParseUtil::jsonToQString(mapNames.at(j)); - mapGroups.insert(mapName, groupIndex); - groupedMaps[groupIndex].append(mapName); - maps.append(mapName); + QJsonArray mapNamesJson = mapGroupsObj.value(groupName).toArray(); + this->groupedMapNames.append(QStringList()); + this->groupNames.append(groupName); + for (int j = 0; j < mapNamesJson.size(); j++) { + QString mapName = ParseUtil::jsonToQString(mapNamesJson.at(j)); + if (mapName == DYNAMIC_MAP_NAME) { + logWarn(QString("Ignoring map with reserved name '%1'.").arg(mapName)); + continue; + } + this->mapGroups.insert(mapName, groupIndex); + this->groupedMapNames[groupIndex].append(mapName); + this->mapNames.append(mapName); // Build the mapping and reverse mapping between map constants and map names. QString mapConstant = Map::mapConstantFromName(mapName); - mapConstantsToMapNames.insert(mapConstant, mapName); - mapNamesToMapConstants.insert(mapName, mapConstant); + this->mapConstantsToMapNames.insert(mapConstant, mapName); + this->mapNamesToMapConstants.insert(mapName, mapConstant); } } - const QString defineName = this->getDynamicMapDefineName(); - mapConstantsToMapNames.insert(defineName, DYNAMIC_MAP_NAME); - mapNamesToMapConstants.insert(DYNAMIC_MAP_NAME, defineName); - maps.append(DYNAMIC_MAP_NAME); + if (this->groupNames.isEmpty()) { + logError(QString("Failed to find any map groups in %1").arg(filepath)); + return false; + } + if (this->mapNames.isEmpty()) { + logError(QString("Failed to find any map names in %1").arg(filepath)); + return false; + } + + const QString defineName = this->getDynamicMapDefineName(); + this->mapConstantsToMapNames.insert(defineName, DYNAMIC_MAP_NAME); + this->mapNamesToMapConstants.insert(DYNAMIC_MAP_NAME, defineName); + this->mapNames.append(DYNAMIC_MAP_NAME); - groupNames = groups; - groupedMapNames = groupedMaps; - mapNames = maps; return true; } @@ -2176,10 +2185,8 @@ bool Project::readItemNames() { const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_items); fileWatcher.addPath(root + "/" + filename); itemNames = parser.readCDefineNames(filename, prefixes); - if (itemNames.isEmpty()) { - logError(QString("Failed to read item constants from %1").arg(filename)); - return false; - } + if (itemNames.isEmpty()) + logWarn(QString("Failed to read item constants from %1").arg(filename)); return true; } @@ -2188,10 +2195,8 @@ bool Project::readFlagNames() { const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_flags); fileWatcher.addPath(root + "/" + filename); flagNames = parser.readCDefineNames(filename, prefixes); - if (flagNames.isEmpty()) { - logError(QString("Failed to read flag constants from %1").arg(filename)); - return false; - } + if (flagNames.isEmpty()) + logWarn(QString("Failed to read flag constants from %1").arg(filename)); return true; } @@ -2200,10 +2205,8 @@ bool Project::readVarNames() { const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_vars); fileWatcher.addPath(root + "/" + filename); varNames = parser.readCDefineNames(filename, prefixes); - if (varNames.isEmpty()) { - logError(QString("Failed to read var constants from %1").arg(filename)); - return false; - } + if (varNames.isEmpty()) + logWarn(QString("Failed to read var constants from %1").arg(filename)); return true; } @@ -2212,10 +2215,8 @@ bool Project::readMovementTypes() { const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_obj_event_movement); fileWatcher.addPath(root + "/" + filename); movementTypes = parser.readCDefineNames(filename, prefixes); - if (movementTypes.isEmpty()) { - logError(QString("Failed to read movement type constants from %1").arg(filename)); - return false; - } + if (movementTypes.isEmpty()) + logWarn(QString("Failed to read movement type constants from %1").arg(filename)); return true; } @@ -2223,10 +2224,8 @@ bool Project::readInitialFacingDirections() { QString filename = projectConfig.getFilePath(ProjectFilePath::initial_facing_table); fileWatcher.addPath(root + "/" + filename); facingDirections = parser.readNamedIndexCArray(filename, projectConfig.getIdentifier(ProjectIdentifier::symbol_facing_directions)); - if (facingDirections.isEmpty()) { - logError(QString("Failed to read initial movement type facing directions from %1").arg(filename)); - return false; - } + if (facingDirections.isEmpty()) + logWarn(QString("Failed to read initial movement type facing directions from %1").arg(filename)); return true; } @@ -2235,10 +2234,8 @@ bool Project::readMapTypes() { const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_map_types); fileWatcher.addPath(root + "/" + filename); mapTypes = parser.readCDefineNames(filename, prefixes); - if (mapTypes.isEmpty()) { - logError(QString("Failed to read map type constants from %1").arg(filename)); - return false; - } + if (mapTypes.isEmpty()) + logWarn(QString("Failed to read map type constants from %1").arg(filename)); return true; } @@ -2247,10 +2244,8 @@ bool Project::readMapBattleScenes() { const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_map_types); fileWatcher.addPath(root + "/" + filename); mapBattleScenes = parser.readCDefineNames(filename, prefixes); - if (mapBattleScenes.isEmpty()) { - logError(QString("Failed to read map battle scene constants from %1").arg(filename)); - return false; - } + if (mapBattleScenes.isEmpty()) + logWarn(QString("Failed to read map battle scene constants from %1").arg(filename)); return true; } @@ -2259,15 +2254,12 @@ bool Project::readWeatherNames() { const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_weather); fileWatcher.addPath(root + "/" + filename); weatherNames = parser.readCDefineNames(filename, prefixes); - if (weatherNames.isEmpty()) { - logError(QString("Failed to read weather constants from %1").arg(filename)); - return false; - } + if (weatherNames.isEmpty()) + logWarn(QString("Failed to read weather constants from %1").arg(filename)); return true; } bool Project::readCoordEventWeatherNames() { - this->weatherEventConstantsLoaded = false; if (!projectConfig.getEventWeatherTriggerEnabled()) return true; @@ -2275,17 +2267,12 @@ bool Project::readCoordEventWeatherNames() { const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_weather); fileWatcher.addPath(root + "/" + filename); coordEventWeatherNames = parser.readCDefineNames(filename, prefixes); - if (coordEventWeatherNames.isEmpty()) { - logWarn(QString("Failed to read coord event weather constants from %1. Disabling Weather Trigger events.").arg(filename)); - return true; - } - - this->weatherEventConstantsLoaded = true; + if (coordEventWeatherNames.isEmpty()) + logWarn(QString("Failed to read coord event weather constants from %1").arg(filename)); return true; } bool Project::readSecretBaseIds() { - this->secretBaseConstantsLoaded = false; if (!projectConfig.getEventSecretBaseEnabled()) return true; @@ -2293,12 +2280,8 @@ bool Project::readSecretBaseIds() { const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_secret_bases); fileWatcher.addPath(root + "/" + filename); secretBaseIds = parser.readCDefineNames(filename, prefixes); - if (secretBaseIds.isEmpty()) { - logWarn(QString("Failed to read secret base id constants from '%1'. Disabling Secret Base events.").arg(filename)); - return true; - } - - this->secretBaseConstantsLoaded = true; + if (secretBaseIds.isEmpty()) + logWarn(QString("Failed to read secret base id constants from '%1'").arg(filename)); return true; } @@ -2307,10 +2290,8 @@ bool Project::readBgEventFacingDirections() { const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_event_bg); fileWatcher.addPath(root + "/" + filename); bgEventFacingDirections = parser.readCDefineNames(filename, prefixes); - if (bgEventFacingDirections.isEmpty()) { - logError(QString("Failed to read bg event facing direction constants from %1").arg(filename)); - return false; - } + if (bgEventFacingDirections.isEmpty()) + logWarn(QString("Failed to read bg event facing direction constants from %1").arg(filename)); return true; } @@ -2319,10 +2300,8 @@ bool Project::readTrainerTypes() { const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_trainer_types); fileWatcher.addPath(root + "/" + filename); trainerTypes = parser.readCDefineNames(filename, prefixes); - if (trainerTypes.isEmpty()) { - logError(QString("Failed to read trainer type constants from %1").arg(filename)); - return false; - } + if (trainerTypes.isEmpty()) + logWarn(QString("Failed to read trainer type constants from %1").arg(filename)); return true; } @@ -2356,11 +2335,9 @@ bool Project::readSongNames() { const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_songs); fileWatcher.addPath(root + "/" + filename); this->songNames = parser.readCDefineNames(filename, prefixes); - if (this->songNames.isEmpty()) { - logError(QString("Failed to read song names from %1.").arg(filename)); - return false; - } - this->defaultSong = this->songNames.value(0); + if (this->songNames.isEmpty()) + logWarn(QString("Failed to read song names from %1.").arg(filename)); + // Song names don't have a very useful order (esp. if we include SE_* values), so sort them alphabetically. this->songNames.sort(); return true; @@ -2371,10 +2348,8 @@ bool Project::readObjEventGfxConstants() { QString filename = projectConfig.getFilePath(ProjectFilePath::constants_obj_events); fileWatcher.addPath(root + "/" + filename); this->gfxDefines = parser.readCDefinesByPrefix(filename, prefixes); - if (this->gfxDefines.isEmpty()) { - logError(QString("Failed to read object event graphics constants from %1.").arg(filename)); - return false; - } + if (this->gfxDefines.isEmpty()) + logWarn(QString("Failed to read object event graphics constants from %1.").arg(filename)); return true; } diff --git a/src/ui/newmappopup.cpp b/src/ui/newmappopup.cpp index 0239b710..241d29c3 100644 --- a/src/ui/newmappopup.cpp +++ b/src/ui/newmappopup.cpp @@ -33,7 +33,7 @@ void NewMapPopup::init() { ui->comboBox_NewMap_Group->addItems(project->groupNames); ui->comboBox_NewMap_Song->addItems(project->songNames); ui->comboBox_NewMap_Type->addItems(project->mapTypes); - ui->comboBox_NewMap_Location->addItems(project->mapSectionValueToName.values()); + ui->comboBox_NewMap_Location->addItems(project->mapSectionNameToValue.keys()); // Set spin box limits ui->spinBox_NewMap_Width->setMinimum(1); @@ -173,9 +173,9 @@ void NewMapPopup::setDefaultSettings(Project *project) { settings.borderHeight = DEFAULT_BORDER_HEIGHT; settings.primaryTilesetLabel = project->getDefaultPrimaryTilesetLabel(); settings.secondaryTilesetLabel = project->getDefaultSecondaryTilesetLabel(); - settings.type = project->mapTypes.at(0); - settings.location = project->mapSectionValueToName.values().at(0); - settings.song = project->defaultSong; + settings.type = project->mapTypes.value(0, "0"); + settings.location = project->mapSectionNameToValue.keys().value(0, "0"); + settings.song = project->songNames.value(0, "0"); settings.canFlyTo = false; settings.showLocationName = true; settings.allowRunning = false; @@ -258,9 +258,9 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() { newMap->location = this->ui->comboBox_NewMap_Location->currentText(); newMap->song = this->ui->comboBox_NewMap_Song->currentText(); newMap->requiresFlash = false; - newMap->weather = this->project->weatherNames.value(0); + newMap->weather = this->project->weatherNames.value(0, "0"); newMap->show_location = this->ui->checkBox_NewMap_Show_Location->isChecked(); - newMap->battle_scene = this->project->mapBattleScenes.value(0); + newMap->battle_scene = this->project->mapBattleScenes.value(0, "0"); if (this->existingLayout) { layout = this->project->mapLayouts.value(this->layoutId);