Write editor state to a new, separate xml file (fix #728)

This commit is contained in:
2025-05-07 20:56:56 -05:00
parent 744a7eb591
commit e95d4dcaf8
7 changed files with 58 additions and 11 deletions

2
.gitignore vendored
View File

@@ -98,6 +98,8 @@ test/junk/*.map
oldstructs.txt
src/tools/gitrev.hpp
rsrc/**/scenario
rsrc/scenarios/**/editor.xml
rsrc/bases/**/editor.xml
# Dependency-generated files
deps/**/

View File

@@ -49,6 +49,7 @@ static bool load_scenario_v2(fs::path file_to_load, cScenario& scenario, eLoadSc
// Some of these are non-static so that the test cases can access them.
ticpp::Document xmlDocFromStream(std::istream& stream, std::string name);
void readScenarioFromXml(ticpp::Document&& data, cScenario& scenario);
void readEditorStateFromXml(ticpp::Document&& data, cScenario& scenario);
void readTerrainFromXml(ticpp::Document&& data, cScenario& scenario);
void readItemsFromXml(ticpp::Document&& data, cScenario& scenario);
void readMonstersFromXml(ticpp::Document&& data, cScenario& scenario);
@@ -932,7 +933,7 @@ void readScenarioFromXml(ticpp::Document&& data, cScenario& scenario) {
if(!reqs.empty())
throw xMissingElem("game", *reqs.begin(), elem->Row(), elem->Column(), fname);
} else if(type == "editor") {
std::set<std::string> reqs = {"default-ground", "last-out-section", "last-town"};
std::set<std::string> reqs = {"default-ground"};
Iterator<Element> edit;
int num_storage = 0, num_pics = 0;
for(edit = edit.begin(elem.Get()); edit != edit.end(); edit++) {
@@ -940,11 +941,14 @@ void readScenarioFromXml(ticpp::Document&& data, cScenario& scenario) {
reqs.erase(type);
if(type == "default-ground") {
edit->GetText(&scenario.default_ground);
} else if(type == "last-out-section") {
}
// Old scenario files may have last-out-section and last-town in scenario.xml
else if(type == "last-out-section") {
scenario.last_out_edited = readLocFromXml(*edit);
} else if(type == "last-town") {
edit->GetText(&scenario.last_town_edited);
} else if(type == "sound") {
}
else if(type == "sound") {
int sndnum = 0;
edit->GetAttribute("id", &sndnum);
if(sndnum < 100)
@@ -1066,6 +1070,23 @@ void readScenarioFromXml(ticpp::Document&& data, cScenario& scenario) {
throw xMissingElem("scenario", *reqs.begin(), data.FirstChildElement()->Row(), data.FirstChildElement()->Column(), fname);
}
void readEditorStateFromXml(ticpp::Document&& data, cScenario& scenario) {
using namespace ticpp;
int maj, min, rev;
std::string fname, type, name, val;
initialXmlRead(data, "editor", maj, min, rev, fname);
Iterator<Attribute> attr;
Iterator<Element> elem;
for(elem = elem.begin(data.FirstChildElement()); elem != elem.end(); elem++) {
elem->GetValue(&type);
if(type == "last-out-section") {
scenario.last_out_edited = readLocFromXml(*elem);
} else if(type == "last-town") {
elem->GetText(&scenario.last_town_edited);
}
}
}
void readTerrainFromXml(ticpp::Document&& data, cScenario& scenario) {
using namespace ticpp;
int maj, min, rev;
@@ -2187,6 +2208,10 @@ bool load_scenario_v2(fs::path file_to_load, cScenario& scenario, eLoadScenario
return false;
}
}
auto hasFile = [&](std::string relpath) -> bool {
if(is_packed) return pack.hasFile("scenario/" + relpath);
return fs::exists(file_to_load/relpath);
};
auto getFile = [&](std::string relpath) -> std::istream& {
if(is_packed) return pack.getFile("scenario/" + relpath);
if(fin.is_open()) fin.close();
@@ -2217,6 +2242,12 @@ bool load_scenario_v2(fs::path file_to_load, cScenario& scenario, eLoadScenario
if(load_type == eLoadScenario::ONLY_HEADER) return true;
if(load_type != eLoadScenario::SAVE_PREVIEW){
// Editor state, even though the game won't need it
if(hasFile("editor.xml")){
std::istream& editor = getFile("editor.xml");
readEditorStateFromXml(xmlDocFromStream(editor, "editor.xml"), scenario);
}
// Next, terrain types...
std::istream& terrain = getFile("terrain.xml");
readTerrainFromXml(xmlDocFromStream(terrain, "terrain.xml"), scenario);

View File

@@ -241,8 +241,7 @@ static bool handle_lb_action(location the_point) {
case LB_LOAD_SCEN:
file_to_load = nav_get_scenario();
if(!file_to_load.empty() && load_scenario(file_to_load, scenario)) {
set_current_town(scenario.last_town_edited);
set_current_out(scenario.last_out_edited);
restore_editor_state();
} else if(!file_to_load.empty())
// If we tried to load but failed, the scenario record is messed up, so boot to start screen.
set_up_start_screen();
@@ -2881,3 +2880,8 @@ bool monst_on_space(location loc,short m_num) {
return false;
}
void restore_editor_state() {
set_current_town(scenario.last_town_edited);
set_current_out(scenario.last_out_edited);
}

View File

@@ -2,6 +2,7 @@
#include "scen.global.hpp"
#include "tools/undo.hpp"
void restore_editor_state();
void init_screen_locs();
void handle_action(location the_point,sf::Event event);
void flash_rect(rectangle to_flash);

View File

@@ -51,10 +51,9 @@ void set_up_apple_events() {
std::copy(msg.get(), msg.get() + len, std::inserter(fileName, fileName.begin()));
if(load_scenario(fileName, scenario)) {
set_current_town(scenario.last_town_edited);
restore_editor_state();
change_made = false;
ae_loading = true;
set_current_out(scenario.last_out_edited);
}
return TRUE;
}

View File

@@ -43,6 +43,7 @@ void load_spec_graphics();
// These aren't static solely so that the test cases can access them.
void writeScenarioToXml(ticpp::Printer&& data, cScenario& scenario);
void writeEditorStateToXml(ticpp::Printer&& data, cScenario& scenario);
void writeTerrainToXml(ticpp::Printer&& data, cScenario& scenario);
void writeItemsToXml(ticpp::Printer&& data, cScenario& scenario);
void writeMonstersToXml(ticpp::Printer&& data, cScenario& scenario);
@@ -121,6 +122,14 @@ namespace ticpp {
}
}
void writeEditorStateToXml(ticpp::Printer&& data, cScenario& scenario) {
data.OpenElement("editor");
data.PushAttribute("boes", scenario.format_ed_version());
data.PushElement("last-out-section", cur_out);
data.PushElement("last-town", cur_town);
data.CloseElement("editor");
}
void writeScenarioToXml(ticpp::Printer&& data, cScenario& scenario) {
data.OpenElement("scenario");
data.PushAttribute("boes", scenario.format_ed_version());
@@ -357,8 +366,6 @@ void writeScenarioToXml(ticpp::Printer&& data, cScenario& scenario) {
data.CloseElement("game");
data.OpenElement("editor");
data.PushElement("default-ground", scenario.default_ground);
data.PushElement("last-out-section", cur_out);
data.PushElement("last-town", cur_town);
if(!scenario.custom_graphics.empty()) {
data.OpenElement("graphics");
for(size_t i = 0; i < scenario.custom_graphics.size(); i++) {
@@ -1075,6 +1082,10 @@ void save_scenario(bool rename) {
std::ostream& header = scen_file.newFile("scenario/header.exs");
header.write(reinterpret_cast<char*>(&scenario.format), sizeof(scenario_header_flags));
// Write scenario's editor state to a file that can be added to .gitignore
std::ostream& editor_data = scen_file.newFile("scenario/editor.xml");
writeEditorStateToXml(ticpp::Printer("scenario.xml", editor_data), scenario);
// Next, the bulk scenario data.
std::ostream& scen_data = scen_file.newFile("scenario/scenario.xml");
writeScenarioToXml(ticpp::Printer("scenario.xml", scen_data), scenario);

View File

@@ -301,10 +301,9 @@ static void process_args(int argc, char* argv[]) {
}
if(!file.empty()) {
if(load_scenario(file, scenario)) {
set_current_town(scenario.last_town_edited);
restore_editor_state();
change_made = false;
ae_loading = true;
set_current_out(scenario.last_out_edited);
} else {
std::cout << "Failed to load scenario: " << file << std::endl;
}