diff --git a/application/scenarioloadermode.cpp b/application/scenarioloadermode.cpp index f05c3869..a2293fe5 100644 --- a/application/scenarioloadermode.cpp +++ b/application/scenarioloadermode.cpp @@ -55,6 +55,9 @@ bool scenarioloader_mode::update() { ErrorLog( "Bad init: scenario loading failed" ); Application.pop_mode(); } + // the loading state holds the scenario file open, which on some systems keeps the file from being replaced + // when the scenery is saved in the editor. it'd also get in the way of another load + state.reset(); WriteLog( "Scenario loading time: " + std::to_string( std::chrono::duration_cast( std::chrono::system_clock::now() - timestart ).count() ) + " seconds" ); // TODO: implement and use next mode cue diff --git a/editor/editorIncludeInfo.cpp b/editor/editorIncludeInfo.cpp index f9f09920..720bab29 100644 --- a/editor/editorIncludeInfo.cpp +++ b/editor/editorIncludeInfo.cpp @@ -418,6 +418,7 @@ bool save(std::string const &File, include_info const &Info, std::string &Error) if (error) { Error = "can't replace file \"" + File + "\": " + error.message(); + std::filesystem::remove(filepath + ".tmp", error); return false; } return true; diff --git a/scene/scenelayerssave.cpp b/scene/scenelayerssave.cpp index b76a9f2b..b42c7286 100644 --- a/scene/scenelayerssave.cpp +++ b/scene/scenelayerssave.cpp @@ -862,6 +862,7 @@ save_result node_layers::save(std::vector const &Rootstatements) } written.emplace_back(output); } + std::vector replaced; for (auto const output : written) { auto const filepath{path(output)}; @@ -873,10 +874,35 @@ save_result node_layers::save(std::vector const &Rootstatements) std::filesystem::rename(filepath + ".tmp", filepath, error); if (error) { - return fail("can't replace file \"" + layer(output).name + "\": " + error.message()); + // e.g. the file is held open by another program. take back what was done so far: the scenery files + // have to stay in step with each other, and with what we know about them + auto const cause{error.message()}; + for (auto const restored : replaced) + { + auto const lookup{state.content.find(restored)}; + if (lookup != state.content.end()) + { + std::ofstream{path(restored), std::ios_base::binary | std::ios_base::trunc} << lookup->second; + stat(restored); + } + else + { + std::filesystem::remove(path(restored), error); + } + } + for (auto const leftover : written) + { + std::filesystem::remove(path(leftover) + ".tmp", error); + } + result.files.clear(); + return fail("can't replace file \"" + layer(output).name + "\": " + cause); } + replaced.emplace_back(output); result.files.emplace_back(layer(output).name); - WriteLog("Scenery save: file \"" + layer(output).name + "\" updated"); + } + for (auto const &file : result.files) + { + WriteLog("Scenery save: file \"" + file + "\" updated"); } // the scenery files now match the scene, update the bookkeeping to reflect it