Merge pull request #598 from GriffinRichards/rme-fixes
Region map editor fixes
This commit is contained in:
commit
18bdbc8a09
6 changed files with 82 additions and 49 deletions
|
@ -7,7 +7,10 @@ and this project somewhat adheres to [Semantic Versioning](https://semver.org/sp
|
||||||
The **"Breaking Changes"** listed below are changes that have been made in the decompilation projects (e.g. pokeemerald), which porymap requires in order to work properly. It also includes changes to the scripting API that may change the behavior of existing porymap scripts. If porymap is used with a project or API script that is not up-to-date with the breaking changes, then porymap will likely break or behave improperly.
|
The **"Breaking Changes"** listed below are changes that have been made in the decompilation projects (e.g. pokeemerald), which porymap requires in order to work properly. It also includes changes to the scripting API that may change the behavior of existing porymap scripts. If porymap is used with a project or API script that is not up-to-date with the breaking changes, then porymap will likely break or behave improperly.
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
Nothing, yet.
|
### Fixed
|
||||||
|
- Fix `Add Region Map...` not updating the region map settings file.
|
||||||
|
- Fix some crashes on invalid region map tilesets.
|
||||||
|
- Improve error reporting for invalid region map editor settings.
|
||||||
|
|
||||||
## [5.4.1] - 2024-03-21
|
## [5.4.1] - 2024-03-21
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -388,6 +388,7 @@ private:
|
||||||
|
|
||||||
void initTilesetEditor();
|
void initTilesetEditor();
|
||||||
bool initRegionMapEditor(bool silent = false);
|
bool initRegionMapEditor(bool silent = false);
|
||||||
|
bool askToFixRegionMapEditor();
|
||||||
void initShortcutsEditor();
|
void initShortcutsEditor();
|
||||||
void initCustomScriptsEditor();
|
void initCustomScriptsEditor();
|
||||||
void connectSubEditorsToShortcutsEditor();
|
void connectSubEditorsToShortcutsEditor();
|
||||||
|
|
|
@ -27,6 +27,7 @@ public:
|
||||||
~RegionMapEditor();
|
~RegionMapEditor();
|
||||||
|
|
||||||
bool load(bool silent = false);
|
bool load(bool silent = false);
|
||||||
|
bool setupErrored() const { return setupError; }
|
||||||
|
|
||||||
void onRegionMapTileSelectorSelectedTileChanged(unsigned id);
|
void onRegionMapTileSelectorSelectedTileChanged(unsigned id);
|
||||||
void onRegionMapTileSelectorHoveredTileChanged(unsigned id);
|
void onRegionMapTileSelectorHoveredTileChanged(unsigned id);
|
||||||
|
@ -41,6 +42,8 @@ public:
|
||||||
|
|
||||||
void resizeTilemap(int width, int height);
|
void resizeTilemap(int width, int height);
|
||||||
|
|
||||||
|
bool reconfigure();
|
||||||
|
|
||||||
QObjectList shortcutableObjects() const;
|
QObjectList shortcutableObjects() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -53,9 +56,13 @@ private:
|
||||||
RegionMap *region_map = nullptr;
|
RegionMap *region_map = nullptr;
|
||||||
tsl::ordered_map<QString, RegionMap *> region_maps;
|
tsl::ordered_map<QString, RegionMap *> region_maps;
|
||||||
|
|
||||||
|
QString configFilepath;
|
||||||
|
QString mapSectionFilepath;
|
||||||
|
|
||||||
poryjson::Json rmConfigJson;
|
poryjson::Json rmConfigJson;
|
||||||
|
|
||||||
bool configSaved = false;
|
bool configSaved = false;
|
||||||
|
bool setupError = false;
|
||||||
|
|
||||||
QUndoGroup history;
|
QUndoGroup history;
|
||||||
|
|
||||||
|
|
|
@ -79,14 +79,25 @@ bool RegionMap::loadTilemap(poryjson::Json tilemapJson) {
|
||||||
this->palette_path = tilemapObject["palette"].string_value();
|
this->palette_path = tilemapObject["palette"].string_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QImage tilesetFile(fullPath(this->tileset_path));
|
||||||
|
if (tilesetFile.isNull()) {
|
||||||
|
logError(QString("Failed to open region map tileset file '%1'.").arg(tileset_path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tilesetFile.width() < 8 || tilesetFile.height() < 8) {
|
||||||
|
logError(QString("Region map tileset file '%1' must be at least 8x8.").arg(tileset_path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QFile tilemapFile(fullPath(this->tilemap_path));
|
QFile tilemapFile(fullPath(this->tilemap_path));
|
||||||
if (!tilemapFile.open(QIODevice::ReadOnly)) {
|
if (!tilemapFile.open(QIODevice::ReadOnly)) {
|
||||||
logError(QString("Failed to open region map tilemap file %1.").arg(tilemap_path));
|
logError(QString("Failed to open region map tilemap file '%1'.").arg(tilemap_path));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tilemapFile.size() < tilemapBytes()) {
|
if (tilemapFile.size() < tilemapBytes()) {
|
||||||
logError(QString("The region map tilemap at %1 is too small.").arg(tilemap_path));
|
logError(QString("The region map tilemap at '%1' is too small.").arg(tilemap_path));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +308,7 @@ bool RegionMap::loadLayout(poryjson::Json layoutJson) {
|
||||||
}
|
}
|
||||||
setLayout("main", layout);
|
setLayout("main", layout);
|
||||||
} else {
|
} else {
|
||||||
logError("Region map layout is not readable.");
|
logError(QString("Failed to read region map layout from '%1'.").arg(this->layout_path));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2960,23 +2960,43 @@ void MainWindow::on_pushButton_CreatePrefab_clicked() {
|
||||||
|
|
||||||
bool MainWindow::initRegionMapEditor(bool silent) {
|
bool MainWindow::initRegionMapEditor(bool silent) {
|
||||||
this->regionMapEditor = new RegionMapEditor(this, this->editor->project);
|
this->regionMapEditor = new RegionMapEditor(this, this->editor->project);
|
||||||
bool success = this->regionMapEditor->load(silent);
|
if (!this->regionMapEditor->load(silent)) {
|
||||||
if (!success) {
|
// The region map editor either failed to load,
|
||||||
delete this->regionMapEditor;
|
// or the user declined configuring their settings.
|
||||||
this->regionMapEditor = nullptr;
|
if (!silent && this->regionMapEditor->setupErrored()) {
|
||||||
if (!silent) {
|
if (this->askToFixRegionMapEditor())
|
||||||
QMessageBox msgBox(this);
|
return true;
|
||||||
QString errorMsg = QString("There was an error opening the region map data. Please see %1 for full error details.\n\n%3")
|
|
||||||
.arg(getLogPath())
|
|
||||||
.arg(getMostRecentError());
|
|
||||||
msgBox.critical(nullptr, "Error Opening Region Map Editor", errorMsg);
|
|
||||||
}
|
}
|
||||||
|
delete this->regionMapEditor;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MainWindow::askToFixRegionMapEditor() {
|
||||||
|
QMessageBox msgBox;
|
||||||
|
msgBox.setIcon(QMessageBox::Critical);
|
||||||
|
msgBox.setText(QString("There was an error opening the region map data. Please see %1 for full error details.").arg(getLogPath()));
|
||||||
|
msgBox.setDetailedText(getMostRecentError());
|
||||||
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||||
|
msgBox.setDefaultButton(QMessageBox::Ok);
|
||||||
|
auto reconfigButton = msgBox.addButton("Reconfigure", QMessageBox::ActionRole);
|
||||||
|
msgBox.exec();
|
||||||
|
if (msgBox.clickedButton() == reconfigButton) {
|
||||||
|
if (this->regionMapEditor->reconfigure()) {
|
||||||
|
// User fixed error
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (this->regionMapEditor->setupErrored()) {
|
||||||
|
// User's new settings still fail, show error and ask again
|
||||||
|
return this->askToFixRegionMapEditor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// User accepted error
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::closeSupplementaryWindows() {
|
void MainWindow::closeSupplementaryWindows() {
|
||||||
delete this->tilesetEditor;
|
delete this->tilesetEditor;
|
||||||
delete this->regionMapEditor;
|
delete this->regionMapEditor;
|
||||||
|
|
|
@ -28,6 +28,8 @@ RegionMapEditor::RegionMapEditor(QWidget *parent, Project *project) :
|
||||||
{
|
{
|
||||||
this->ui->setupUi(this);
|
this->ui->setupUi(this);
|
||||||
this->project = project;
|
this->project = project;
|
||||||
|
this->configFilepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_porymap_cfg));
|
||||||
|
this->mapSectionFilepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_map_entries));
|
||||||
this->initShortcuts();
|
this->initShortcuts();
|
||||||
this->restoreWindowState();
|
this->restoreWindowState();
|
||||||
}
|
}
|
||||||
|
@ -110,12 +112,10 @@ void RegionMapEditor::applyUserShortcuts() {
|
||||||
bool RegionMapEditor::loadRegionMapEntries() {
|
bool RegionMapEditor::loadRegionMapEntries() {
|
||||||
this->region_map_entries.clear();
|
this->region_map_entries.clear();
|
||||||
|
|
||||||
QString regionMapSectionFilepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_map_entries));
|
|
||||||
|
|
||||||
ParseUtil parser;
|
ParseUtil parser;
|
||||||
QJsonDocument sectionsDoc;
|
QJsonDocument sectionsDoc;
|
||||||
if (!parser.tryParseJsonFile(§ionsDoc, regionMapSectionFilepath)) {
|
if (!parser.tryParseJsonFile(§ionsDoc, this->mapSectionFilepath)) {
|
||||||
logError(QString("Failed to read map data from %1").arg(regionMapSectionFilepath));
|
logError(QString("Failed to read map data from %1").arg(this->mapSectionFilepath));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,11 +140,9 @@ bool RegionMapEditor::loadRegionMapEntries() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegionMapEditor::saveRegionMapEntries() {
|
bool RegionMapEditor::saveRegionMapEntries() {
|
||||||
QString regionMapSectionFilepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_map_entries));
|
QFile sectionsFile(this->mapSectionFilepath);
|
||||||
|
|
||||||
QFile sectionsFile(regionMapSectionFilepath);
|
|
||||||
if (!sectionsFile.open(QIODevice::WriteOnly)) {
|
if (!sectionsFile.open(QIODevice::WriteOnly)) {
|
||||||
logError(QString("Error: Could not open %1 for writing").arg(regionMapSectionFilepath));
|
logError(QString("Could not open %1 for writing").arg(this->mapSectionFilepath));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,7 +296,7 @@ bool RegionMapEditor::buildConfigDialog() {
|
||||||
form.addRow(addMapButton);
|
form.addRow(addMapButton);
|
||||||
|
|
||||||
// allow user to add region maps
|
// allow user to add region maps
|
||||||
connect(addMapButton, &QPushButton::clicked, [this, regionMapList] {
|
connect(addMapButton, &QPushButton::clicked, [this, regionMapList, &updateJsonFromList] {
|
||||||
poryjson::Json resultJson = configRegionMapDialog();
|
poryjson::Json resultJson = configRegionMapDialog();
|
||||||
poryjson::Json::object resultObj = resultJson.object_items();
|
poryjson::Json::object resultObj = resultJson.object_items();
|
||||||
|
|
||||||
|
@ -310,6 +308,7 @@ bool RegionMapEditor::buildConfigDialog() {
|
||||||
newItem->setText(resultObj["alias"].string_value());
|
newItem->setText(resultObj["alias"].string_value());
|
||||||
newItem->setData(Qt::UserRole, resultStr);
|
newItem->setData(Qt::UserRole, resultStr);
|
||||||
regionMapList->addItem(newItem);
|
regionMapList->addItem(newItem);
|
||||||
|
updateJsonFromList();
|
||||||
});
|
});
|
||||||
|
|
||||||
QPushButton *delMapButton = new QPushButton("Delete Selected Region Map");
|
QPushButton *delMapButton = new QPushButton("Delete Selected Region Map");
|
||||||
|
@ -403,16 +402,6 @@ bool RegionMapEditor::verifyConfig(poryjson::Json cfg) {
|
||||||
logError("Region map config json has no map list.");
|
logError("Region map config json has no map list.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
OrderedJson::array arr = obj["region_maps"].array_items();
|
|
||||||
|
|
||||||
for (auto ref : arr) {
|
|
||||||
RegionMap tempMap(this->project);
|
|
||||||
if (!tempMap.loadMapData(ref)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,6 +465,7 @@ bool RegionMapEditor::setup() {
|
||||||
if (!newMap->loadMapData(o)) {
|
if (!newMap->loadMapData(o)) {
|
||||||
delete newMap;
|
delete newMap;
|
||||||
// TODO: consider continue, just reporting error loading single map?
|
// TODO: consider continue, just reporting error loading single map?
|
||||||
|
this->setupError = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,26 +488,21 @@ bool RegionMapEditor::setup() {
|
||||||
if (!region_maps.empty()) {
|
if (!region_maps.empty()) {
|
||||||
setRegionMap(region_maps.begin()->second);
|
setRegionMap(region_maps.begin()->second);
|
||||||
}
|
}
|
||||||
|
this->setupError = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegionMapEditor::load(bool silent) {
|
bool RegionMapEditor::load(bool silent) {
|
||||||
// check for config json file
|
// check for config json file
|
||||||
QString jsonConfigFilepath = this->project->root + "/" + projectConfig.getFilePath(ProjectFilePath::json_region_porymap_cfg);
|
|
||||||
|
|
||||||
bool badConfig = true;
|
bool badConfig = true;
|
||||||
|
if (QFile::exists(this->configFilepath)) {
|
||||||
if (QFile::exists(jsonConfigFilepath)) {
|
|
||||||
logInfo("Region map configuration file found.");
|
|
||||||
ParseUtil parser;
|
ParseUtil parser;
|
||||||
OrderedJson::object obj;
|
OrderedJson::object obj;
|
||||||
if (parser.tryParseOrderedJsonFile(&obj, jsonConfigFilepath)) {
|
if (parser.tryParseOrderedJsonFile(&obj, this->configFilepath)) {
|
||||||
this->rmConfigJson = OrderedJson(obj);
|
this->rmConfigJson = OrderedJson(obj);
|
||||||
this->configSaved = true;
|
this->configSaved = true;
|
||||||
}
|
}
|
||||||
badConfig = !verifyConfig(this->rmConfigJson);
|
badConfig = !verifyConfig(this->rmConfigJson);
|
||||||
} else {
|
|
||||||
logWarn("Region Map config file not found.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (badConfig) {
|
if (badConfig) {
|
||||||
|
@ -533,14 +518,15 @@ bool RegionMapEditor::load(bool silent) {
|
||||||
if (warning.exec() == QMessageBox::Ok) {
|
if (warning.exec() == QMessageBox::Ok) {
|
||||||
// there is a separate window that allows to load multiple region maps,
|
// there is a separate window that allows to load multiple region maps,
|
||||||
if (!buildConfigDialog()) {
|
if (!buildConfigDialog()) {
|
||||||
logError("Region map loading interrupted [user]");
|
// User canceled config set up
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// do not open editor
|
// User declined config set up
|
||||||
logError("Region map loading interrupted [user]");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
logInfo("Successfully loaded region map configuration file.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return setup();
|
return setup();
|
||||||
|
@ -582,10 +568,9 @@ void RegionMapEditor::saveConfig() {
|
||||||
mapsObject["region_maps"] = mapArray;
|
mapsObject["region_maps"] = mapArray;
|
||||||
|
|
||||||
OrderedJson newConfigJson(mapsObject);
|
OrderedJson newConfigJson(mapsObject);
|
||||||
QString filepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_porymap_cfg));
|
QFile file(this->configFilepath);
|
||||||
QFile file(filepath);
|
|
||||||
if (!file.open(QIODevice::WriteOnly)) {
|
if (!file.open(QIODevice::WriteOnly)) {
|
||||||
logError(QString("Error: Could not open %1 for writing").arg(filepath));
|
logError(QString("Could not open %1 for writing").arg(this->configFilepath));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OrderedJsonDoc jsonDoc(&newConfigJson);
|
OrderedJsonDoc jsonDoc(&newConfigJson);
|
||||||
|
@ -614,6 +599,11 @@ void RegionMapEditor::on_actionSave_All_triggered() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegionMapEditor::on_action_Configure_triggered() {
|
void RegionMapEditor::on_action_Configure_triggered() {
|
||||||
|
reconfigure();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RegionMapEditor::reconfigure() {
|
||||||
|
this->setupError = false;
|
||||||
if (this->modified()) {
|
if (this->modified()) {
|
||||||
QMessageBox warning;
|
QMessageBox warning;
|
||||||
warning.setIcon(QMessageBox::Warning);
|
warning.setIcon(QMessageBox::Warning);
|
||||||
|
@ -624,15 +614,16 @@ void RegionMapEditor::on_action_Configure_triggered() {
|
||||||
|
|
||||||
if (warning.exec() == QMessageBox::Ok) {
|
if (warning.exec() == QMessageBox::Ok) {
|
||||||
if (buildConfigDialog()) {
|
if (buildConfigDialog()) {
|
||||||
reload();
|
return reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (buildConfigDialog()) {
|
if (buildConfigDialog()) {
|
||||||
reload();
|
return reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegionMapEditor::displayRegionMap() {
|
void RegionMapEditor::displayRegionMap() {
|
||||||
|
|
Loading…
Reference in a new issue