diff --git a/AnimModel.cpp b/AnimModel.cpp index 68302832..b83ecac7 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -293,8 +293,8 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable bool TAnimModel::Load(cParser *parser, bool ter) { // rozpoznanie wpisu modelu i ustawienie świateł - std::string name = parser->getToken(); - std::string texture = parser->getToken( false ); // tekstura (zmienia na małe) + std::string name = ToLower(parser->getToken()); + std::string texture = ToLower(parser->getToken()); replace_slashes( name ); replace_slashes( texture ); if (!Init( name, texture )) diff --git a/Classes.h b/Classes.h index 65bf942c..8c6a684a 100644 --- a/Classes.h +++ b/Classes.h @@ -42,6 +42,8 @@ class vehicle_table; struct light_array; class particle_manager; struct dictionary_source; +class trainset_desc; +class scenery_desc; namespace scene { struct node_data; diff --git a/DynObj.cpp b/DynObj.cpp index 8a6bc99c..fa2adbda 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -1636,7 +1636,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" if (!MoverParameters->LoadFIZ(asBaseDir)) { // jak wczytanie CHK się nie uda, to błąd if (ConversionError == 666) - ErrorLog( "Bad vehicle: failed do locate definition file \"" + BaseDir + "/" + Type_Name + ".fiz" + "\"" ); + ErrorLog( "Bad vehicle: failed to locate definition file \"" + BaseDir + "/" + Type_Name + ".fiz" + "\"" ); else { ErrorLog( "Bad vehicle: failed to load definition from file \"" + BaseDir + "/" + Type_Name + ".fiz\" (error " + to_string( ConversionError ) + ")" ); } diff --git a/Globals.h b/Globals.h index 38b32768..d128408c 100644 --- a/Globals.h +++ b/Globals.h @@ -239,6 +239,8 @@ struct global_settings { std::vector> network_servers; std::optional> network_client; + std::vector> trainset_overrides; + // methods void LoadIniFile( std::string asFileName ); void ConfigParse( cParser &parser ); diff --git a/MdlMngr.cpp b/MdlMngr.cpp index 9cc9aa83..23dd036c 100644 --- a/MdlMngr.cpp +++ b/MdlMngr.cpp @@ -107,7 +107,7 @@ TModelsManager::GetModel(std::string const &Name, bool const Dynamic, bool const else { // there's nothing matching in the databank nor on the disk, report failure... if( Logerrors ) { - ErrorLog( "Bad file: failed do locate 3d model file \"" + filename + "\"", logtype::file ); + ErrorLog( "Bad file: failed to locate 3d model file \"" + filename + "\"", logtype::file ); } // ...and link it with the error model slot m_modelsmap.emplace( filename, null_handle ); diff --git a/Texture.cpp b/Texture.cpp index b8c9436a..b68b02d6 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -1165,7 +1165,7 @@ texture_manager::create(std::string Filename, bool const Loadnow , GLint fh) { locator = find_on_disk( Filename ); if( true == locator.first.empty() ) { // there's nothing matching in the databank nor on the disk, report failure - ErrorLog( "Bad file: failed do locate texture file \"" + Filename + "\"", logtype::file ); + ErrorLog( "Bad file: failed to locate texture file \"" + Filename + "\"", logtype::file ); return npos; } } diff --git a/application.cpp b/application.cpp index 08f56d4d..ec8d1580 100644 --- a/application.cpp +++ b/application.cpp @@ -389,7 +389,22 @@ eu07_application::pop_mode() { bool eu07_application::push_mode( eu07_application::mode const Mode ) { - if( Mode >= mode::count_ ) { return false; } + if( Mode >= mode::count_ ) + return false; + + if (!m_modes[Mode]) { + if (Mode == mode::launcher) + m_modes[Mode] = std::make_shared(); + if (Mode == mode::scenarioloader) + m_modes[Mode] = std::make_shared(); + if (Mode == mode::driver) + m_modes[Mode] = std::make_shared(); + if (Mode == mode::editor) + m_modes[Mode] = std::make_shared(); + + if (!m_modes[Mode]->init()) + return false; + } m_modes[ Mode ]->enter(); m_modestack.push( Mode ); @@ -766,21 +781,11 @@ eu07_application::init_audio() { int eu07_application::init_modes() { + if ((!Global.network_servers.empty() || Global.network_client) && Global.SceneryFile.empty()) { + ErrorLog("launcher mode is currently not supported in network mode"); + return -1; + } - // NOTE: we could delay creation/initialization until transition to specific mode is requested, - // but doing it in one go at the start saves us some error checking headache down the road - - // create all application behaviour modes - m_modes[ mode::launcher ] = std::make_shared(); - m_modes[ mode::scenarioloader ] = std::make_shared(); - m_modes[ mode::driver ] = std::make_shared(); - m_modes[ mode::editor ] = std::make_shared(); - // initialize the mode objects - for( auto &mode : m_modes ) { - if( false == mode->init() ) { - return -1; - } - } // activate the default mode if (Global.SceneryFile.empty()) push_mode( mode::launcher ); diff --git a/audio.cpp b/audio.cpp index 2bf0a08e..61aaf68a 100644 --- a/audio.cpp +++ b/audio.cpp @@ -140,7 +140,7 @@ buffer_manager::create( std::string const &Filename ) { return emplace( filelookup ); } // if we still didn't find anything, give up - ErrorLog( "Bad file: failed do locate audio file \"" + Filename + "\"", logtype::file ); + ErrorLog( "Bad file: failed to locate audio file \"" + Filename + "\"", logtype::file ); return null_handle; } diff --git a/launcher/scenery_list.cpp b/launcher/scenery_list.cpp index 7c1fbdd1..6f0ebed2 100644 --- a/launcher/scenery_list.cpp +++ b/launcher/scenery_list.cpp @@ -4,10 +4,12 @@ #include "utilities.h" #include "renderer.h" #include "McZapkie/MOVER.h" +#include "application.h" +#include "Logs.h" #include ui::scenerylist_panel::scenerylist_panel(scenery_scanner &scanner) - : ui_panel(STR("Scenario list"), false), scanner(scanner) + : ui_panel(STR("Scenario list"), false), scanner(scanner), placeholder_mini("textures/mini/other") { } @@ -25,7 +27,7 @@ void ui::scenerylist_panel::render() std::string prev_prefix; bool collapse_open = false; - for (auto const &desc : scanner.scenarios) { + for (auto &desc : scanner.scenarios) { std::string name = desc.path.stem().string(); std::string prefix = name.substr(0, name.find_first_of("-_")); if (prefix.empty()) @@ -110,7 +112,7 @@ void ui::scenerylist_panel::render() if (ImGui::BeginChild("child5", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar)) { ImGuiListClipper clipper(selected_scenery->trainsets.size()); while (clipper.Step()) for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - auto const &trainset = selected_scenery->trainsets[i]; + auto &trainset = selected_scenery->trainsets[i]; ImGui::PushID(i); if (ImGui::Selectable("##set", selected_trainset == &trainset, 0, ImVec2(0, 30))) selected_trainset = &trainset; @@ -124,8 +126,57 @@ void ui::scenerylist_panel::render() if (selected_trainset) { ImGui::NextColumn(); + ImGui::TextWrapped(selected_trainset->description.c_str()); - ImGui::Button(STR_C("Launch"), ImVec2(-1, 0)); + + if (ImGui::Button(STR_C("Launch"), ImVec2(-1, 0))) { + bool found = false; + for (auto &veh : selected_trainset->vehicles) { + if (veh.drivertype.size() > 0 && veh.drivertype != "nobody") { + Global.local_start_vehicle = ToLower(veh.name); + Global.SceneryFile = selected_scenery->path; + + std::string set = "trainset "; + set += selected_trainset->name + " "; + set += selected_trainset->track + " "; + set += std::to_string(selected_trainset->offset) + " "; + set += std::to_string(selected_trainset->velocity) + " "; + for (const auto &veh : selected_trainset->vehicles) { + set += "node -1 0 " + veh.name + " dynamic "; + set += veh.vehicle->path.parent_path().generic_string() + " "; + set += veh.skin->skin + " "; + set += veh.vehicle->path.stem().generic_string() + " "; + set += std::to_string(veh.offset) + " " + veh.drivertype + " "; + set += std::to_string(veh.coupling); + if (veh.params.size() > 0) + set += "." + veh.params; + set += " " + std::to_string(veh.loadcount) + " "; + if (veh.loadcount > 0) + set += veh.loadtype + " "; + set += "enddynamic "; + } + set += "endtrainset"; + WriteLog(set); + + Global.trainset_overrides.push_back(std::make_pair(selected_trainset->file_bounds.first, set)); + + Application.pop_mode(); + Application.push_mode(eu07_application::mode::scenarioloader); + + found = true; + break; + } + } + if (!found) + ImGui::OpenPopup("missing_driver"); + } + + if (ImGui::BeginPopup("missing_driver")) { + ImGui::TextUnformatted(STR_C("Trainset not occupied")); + if (ImGui::Button(STR_C("OK"), ImVec2(-1, 0))) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } } } } ImGui::EndChild(); @@ -134,7 +185,7 @@ void ui::scenerylist_panel::render() ImGui::End(); } -void ui::scenerylist_panel::draw_trainset(const trainset_desc &trainset) +void ui::scenerylist_panel::draw_trainset(trainset_desc &trainset) { static std::unordered_map coupling_names = { @@ -150,70 +201,93 @@ void ui::scenerylist_panel::draw_trainset(const trainset_desc &trainset) { coupling::uic, STRN("uic") } }; - draw_droptarget(); + int position = 0; + + draw_droptarget(trainset, position++); ImGui::SameLine(15.0f); for (auto const &dyn_desc : trainset.vehicles) { - if (dyn_desc.skin && dyn_desc.skin->mini.get() != -1) { - ImGui::PushID(static_cast(&dyn_desc)); + deferred_image *mini = nullptr; - glm::ivec2 size = dyn_desc.skin->mini.size(); - float width = 30.0f / size.y * size.x; - ImGui::Image(reinterpret_cast(dyn_desc.skin->mini.get()), ImVec2(width, 30), ImVec2(0, 1), ImVec2(1, 0)); + if (dyn_desc.skin && dyn_desc.skin->mini.get() != -1) + mini = &dyn_desc.skin->mini; + else + mini = &placeholder_mini; - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - std::string name = (dyn_desc.vehicle->path.parent_path() / dyn_desc.vehicle->path.stem()).string(); - std::string skin = dyn_desc.skin->skin; - ImGui::Text(STR_C("ID: %s"), dyn_desc.name.c_str()); - ImGui::NewLine(); + ImGui::PushID(static_cast(&dyn_desc)); - ImGui::Text(STR_C("Type: %s"), name.c_str()); - ImGui::Text(STR_C("Skin: %s"), skin.c_str()); - ImGui::NewLine(); + glm::ivec2 size = mini->size(); + float width = 30.0f / size.y * size.x; + ImGui::Image(reinterpret_cast(mini->get()), ImVec2(width, 30), ImVec2(0, 1), ImVec2(1, 0)); - if (dyn_desc.drivertype != "nobody") - ImGui::Text(STR_C("Occupied: %s"), dyn_desc.drivertype.c_str()); - if (dyn_desc.loadcount > 0) - ImGui::Text(STR_C("Load: %s: %d"), dyn_desc.loadtype.c_str(), dyn_desc.loadcount); - if (!dyn_desc.params.empty()) - ImGui::Text(STR_C("Parameters: %s"), dyn_desc.params.c_str()); - ImGui::NewLine(); + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + std::string name = (dyn_desc.vehicle->path.parent_path() / dyn_desc.vehicle->path.stem()).string(); + std::string skin = dyn_desc.skin->skin; + ImGui::Text(STR_C("ID: %s"), dyn_desc.name.c_str()); + ImGui::NewLine(); - ImGui::TextUnformatted(STR_C("Coupling:")); + ImGui::Text(STR_C("Type: %s"), name.c_str()); + ImGui::Text(STR_C("Skin: %s"), skin.c_str()); + ImGui::NewLine(); - for (int i = 1; i <= 0x100; i <<= 1) { - bool dummy = true; + if (dyn_desc.drivertype != "nobody") + ImGui::Text(STR_C("Occupied: %s"), dyn_desc.drivertype.c_str()); + if (dyn_desc.loadcount > 0) + ImGui::Text(STR_C("Load: %s: %d"), dyn_desc.loadtype.c_str(), dyn_desc.loadcount); + if (!dyn_desc.params.empty()) + ImGui::Text(STR_C("Parameters: %s"), dyn_desc.params.c_str()); + ImGui::NewLine(); - if (dyn_desc.coupling & i) { - std::string label = STRN("unknown"); - auto it = coupling_names.find(static_cast(i)); - if (it != coupling_names.end()) - label = it->second; - ImGui::Checkbox(Translations.lookup_c(label.c_str()), &dummy); - } + ImGui::TextUnformatted(STR_C("Coupling:")); + + for (int i = 1; i <= 0x100; i <<= 1) { + bool dummy = true; + + if (dyn_desc.coupling & i) { + std::string label = STRN("unknown"); + auto it = coupling_names.find(static_cast(i)); + if (it != coupling_names.end()) + label = it->second; + ImGui::Checkbox(Translations.lookup_c(label.c_str()), &dummy); } - - ImGui::EndTooltip(); } - ImGui::SameLine(0, 0); - float originX = ImGui::GetCursorPosX(); - - ImGui::SameLine(originX - 7.5f); - draw_droptarget(); - ImGui::SameLine(originX); - - ImGui::PopID(); + ImGui::EndTooltip(); } + + ImGui::SameLine(0, 0); + float originX = ImGui::GetCursorPosX(); + + ImGui::SameLine(originX - 7.5f); + draw_droptarget(trainset, position++); + ImGui::SameLine(originX); + + ImGui::PopID(); } } -void ui::scenerylist_panel::draw_droptarget() +#include "Logs.h" +void ui::scenerylist_panel::draw_droptarget(trainset_desc &trainset, int position) { ImGui::Dummy(ImVec2(15, 30)); if (ImGui::BeginDragDropTarget()) { - ImGui::AcceptDragDropPayload("skin"); + const ImGuiPayload *payload = ImGui::AcceptDragDropPayload("vehicle_pure"); + if (payload) { + skin_set *ptr = *(reinterpret_cast(payload->Data)); + std::shared_ptr skin; + for (auto &s : ptr->vehicle.lock()->matching_skinsets) + if (s.get() == ptr) + skin = s; + + trainset.vehicles.emplace(trainset.vehicles.begin() + position); + dynamic_desc &desc = trainset.vehicles[position]; + + desc.name = skin->skin + "_" + std::to_string((int)LocalRandom(0.0, 10000000.0)); + desc.vehicle = skin->vehicle.lock(); + desc.skin = skin; + + } ImGui::EndDragDropTarget(); } } diff --git a/launcher/scenery_list.h b/launcher/scenery_list.h index 039e7cce..d32e1f47 100644 --- a/launcher/scenery_list.h +++ b/launcher/scenery_list.h @@ -14,10 +14,11 @@ class scenerylist_panel : public ui_panel private: scenery_scanner &scanner; - scenery_desc const *selected_scenery = nullptr; - trainset_desc const *selected_trainset = nullptr; + scenery_desc *selected_scenery = nullptr; + trainset_desc *selected_trainset = nullptr; + deferred_image placeholder_mini; - void draw_trainset(const trainset_desc &trainset); - void draw_droptarget(); + void draw_trainset(trainset_desc &trainset); + void draw_droptarget(trainset_desc &trainset, int position); }; } // namespace ui diff --git a/launcher/scenery_scanner.cpp b/launcher/scenery_scanner.cpp index 3b7f6c14..ff77f6be 100644 --- a/launcher/scenery_scanner.cpp +++ b/launcher/scenery_scanner.cpp @@ -11,7 +11,7 @@ scenery_scanner::scenery_scanner(ui::vehicles_bank &bank) void scenery_scanner::scan() { for (auto &f : std::filesystem::directory_iterator("scenery")) { - std::filesystem::path path(f.path()); + std::filesystem::path path(std::filesystem::relative(f.path(), "scenery/")); if (*(path.filename().string().begin()) == '$') continue; @@ -30,7 +30,9 @@ void scenery_scanner::scan_scn(std::filesystem::path path) scenery_desc &desc = scenarios.back(); desc.path = path; - cParser parser(path.string(), cParser::buffer_FILE); + std::string file_path = "scenery/" + path.string(); + + cParser parser(file_path, cParser::buffer_FILE); parser.expandIncludes = false; while (!parser.eof()) { parser.getTokens(); @@ -38,7 +40,7 @@ void scenery_scanner::scan_scn(std::filesystem::path path) parse_trainset(parser); } - std::ifstream stream(path.string(), std::ios_base::binary | std::ios_base::in); + std::ifstream stream(file_path, std::ios_base::binary | std::ios_base::in); int line_counter = 0; std::string line; @@ -67,7 +69,7 @@ void scenery_scanner::scan_scn(std::filesystem::path path) desc.links.push_back(std::make_pair(file, label)); } else if (line[3] == 'o') { - for (trainset_desc &trainset : desc.trainsets) { + for (auto &trainset : desc.trainsets) { if (line_counter < trainset.file_bounds.first || line_counter > trainset.file_bounds.second) continue; @@ -82,7 +84,7 @@ void scenery_scanner::parse_trainset(cParser &parser) { scenery_desc &desc = scenarios.back(); desc.trainsets.emplace_back(); - trainset_desc &trainset = desc.trainsets.back(); + auto &trainset = desc.trainsets.back(); trainset.file_bounds.first = parser.Line(); parser.getTokens(4); @@ -94,7 +96,6 @@ void scenery_scanner::parse_trainset(cParser &parser) dynamic_desc &dyn = trainset.vehicles.back(); std::string datafolder, skinfile, mmdfile, params; - int offset; parser.getTokens(2); // range_max, range_min parser.getTokens(1, false); // name @@ -104,7 +105,7 @@ void scenery_scanner::parse_trainset(cParser &parser) break; parser.getTokens(7, false); - parser >> datafolder >> skinfile >> mmdfile >> offset >> dyn.drivertype >> params >> dyn.loadcount; + parser >> datafolder >> skinfile >> mmdfile >> dyn.offset >> dyn.drivertype >> params >> dyn.loadcount; size_t params_pos = params.find('.'); if (params_pos != -1 && params_pos < params.size()) { diff --git a/launcher/scenery_scanner.h b/launcher/scenery_scanner.h index 330fd4ae..67648e7f 100644 --- a/launcher/scenery_scanner.h +++ b/launcher/scenery_scanner.h @@ -8,9 +8,10 @@ struct dynamic_desc { std::string name; - std::string drivertype; + std::string drivertype = "nobody"; - std::string loadtype; + float offset; + std::string loadtype = "none"; int loadcount; unsigned int coupling; diff --git a/launcher/textures_scanner.cpp b/launcher/textures_scanner.cpp index 4544103b..c0189dfb 100644 --- a/launcher/textures_scanner.cpp +++ b/launcher/textures_scanner.cpp @@ -16,6 +16,7 @@ void ui::vehicles_bank::scan_textures() { if (line.size() < 3) continue; + if (line.back() == '\r') line.pop_back(); @@ -41,6 +42,9 @@ void ui::vehicles_bank::parse_entry(const std::string &line) std::string param; while (std::getline(stream, param, '=')) { + if (param.back() == ' ') + param.pop_back(); + if (line[0] == '!') parse_category_entry(param); else if (line[0] == '*' && line[1] == '*') @@ -110,7 +114,10 @@ void ui::vehicles_bank::parse_texture_info(const std::string &target, const std: std::getline(stream, mini, ','); std::getline(stream, miniplus, ','); + auto vehicle = get_vehicle(model); + skin_set set; + set.vehicle = vehicle; set.group = mini; if (!mini.empty()) @@ -118,6 +125,8 @@ void ui::vehicles_bank::parse_texture_info(const std::string &target, const std: if (!miniplus.empty()) set.mini = std::move(deferred_image("textures/mini/" + ToLower(miniplus))); + else if (!mini.empty()) + set.mini = std::move(deferred_image("textures/mini/" + ToLower(mini))); set.skin = ToLower(target); erase_extension(set.skin); @@ -129,7 +138,6 @@ void ui::vehicles_bank::parse_texture_info(const std::string &target, const std: } */ - auto vehicle = get_vehicle(model); group_map[set.group].insert(vehicle); vehicle->matching_skinsets.push_back(std::make_shared(std::move(set))); } diff --git a/launcher/textures_scanner.h b/launcher/textures_scanner.h index 4c962467..af059a9b 100644 --- a/launcher/textures_scanner.h +++ b/launcher/textures_scanner.h @@ -22,14 +22,17 @@ enum class vehicle_type { unknown }; +struct vehicle_desc; + struct skin_set { + std::weak_ptr vehicle; + std::string skin; //std::vector skins; deferred_image mini; std::string group; }; -struct vehicle_desc; struct texture_rule { std::shared_ptr previous_vehicle; std::vector> replace_rules; diff --git a/launcher/vehicle_picker.cpp b/launcher/vehicle_picker.cpp index 12f43169..d1f639f1 100644 --- a/launcher/vehicle_picker.cpp +++ b/launcher/vehicle_picker.cpp @@ -3,7 +3,7 @@ #include "renderer.h" ui::vehiclepicker_panel::vehiclepicker_panel() - : ui_panel(STR("Select vehicle"), false) + : ui_panel(STR("Select vehicle"), false), placeholder_mini("textures/mini/other") { bank.scan_textures(); } @@ -162,7 +162,8 @@ void ui::vehiclepicker_panel::render() //std::string label = skin->skins[0].stem().string(); std::string label = skin->skin; - if (selectable_image(label.c_str(), skin == selected_skinset, &skin->mini, true)) + auto mini = skin->mini ? &skin->mini : &placeholder_mini; + if (selectable_image(label.c_str(), skin == selected_skinset, mini, skin)) selected_skinset = skin; } } @@ -173,7 +174,7 @@ void ui::vehiclepicker_panel::render() ImGui::End(); } -bool ui::vehiclepicker_panel::selectable_image(const char *desc, bool selected, const deferred_image* image, bool pickable) +bool ui::vehiclepicker_panel::selectable_image(const char *desc, bool selected, const deferred_image* image, const skin_set *pickable) { bool ret = ImGui::Selectable(desc, selected, 0, ImVec2(0, 30)); if (pickable) @@ -194,10 +195,10 @@ bool ui::vehiclepicker_panel::selectable_image(const char *desc, bool selected, ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); ImGui::InvisibleButton(desc, ImVec2(width, 30)); - if (ImGui::BeginDragDropSource()) { + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAutoExpirePayload)) { ImGui::Image(reinterpret_cast(tex), ImVec2(width, 30), ImVec2(0, 1), ImVec2(1, 0)); - ImGui::SetDragDropPayload("skin", "aaaa", 5); + ImGui::SetDragDropPayload("vehicle_pure", &pickable, sizeof(skin_set*)); ImGui::EndDragDropSource(); } diff --git a/launcher/vehicle_picker.h b/launcher/vehicle_picker.h index 16c1b522..f19a7cab 100644 --- a/launcher/vehicle_picker.h +++ b/launcher/vehicle_picker.h @@ -13,13 +13,14 @@ class vehiclepicker_panel : public ui_panel void render() override; private: - bool selectable_image(const char *desc, bool selected, const deferred_image *image, bool pickable = false); + bool selectable_image(const char *desc, bool selected, const deferred_image *image, const skin_set *pickable = nullptr); vehicle_type selected_type = vehicle_type::none; std::shared_ptr selected_vehicle; const std::string *selected_group = nullptr; const skin_set *selected_skinset = nullptr; bool display_by_groups = false; + deferred_image placeholder_mini; vehicles_bank bank; }; diff --git a/parser.cpp b/parser.cpp index 25418197..ac94387f 100644 --- a/parser.cpp +++ b/parser.cpp @@ -324,6 +324,17 @@ bool cParser::trimComments(std::string &String) return false; } +void cParser::injectString(const std::string &str) +{ + if (mIncludeParser) { + mIncludeParser->injectString(str); + } + else { + mIncludeParser = std::make_shared( str, buffer_TEXT, "", LoadTraction ); + mIncludeParser->autoclear( m_autoclear ); + } +} + int cParser::getProgress() const { return static_cast( mStream->rdbuf()->pubseekoff(0, std::ios_base::cur) * 100 / mSize ); @@ -374,3 +385,7 @@ cParser::Line() const { if( mIncludeParser ) { return mIncludeParser->Line(); } else { return mLine; } } + +int cParser::LineMain() const { + return mIncludeParser ? -1 : mLine; +} diff --git a/parser.h b/parser.h index b909b5a0..37d2c662 100644 --- a/parser.h +++ b/parser.h @@ -70,6 +70,9 @@ class cParser //: public std::stringstream false == tokens.empty() ? tokens.front() : "" ); } + // inject string as internal include + void injectString(const std::string &str); + // returns percentage of file processed so far int getProgress() const; int getFullProgress() const; @@ -81,6 +84,8 @@ class cParser //: public std::stringstream std::string Name() const; // returns number of currently processed line std::size_t Line() const; + // returns number of currently processed line in main file, -1 if inside include + int LineMain() const; bool expandIncludes = true; private: diff --git a/scene.h b/scene.h index fa8fb55c..7237efcc 100644 --- a/scene.h +++ b/scene.h @@ -58,7 +58,6 @@ struct scratch_data { std::string name; bool initialized { false }; - //std::vector *trainsets_desc; }; // basic element of rudimentary partitioning scheme for the section. fixed size, no further subdivision diff --git a/simulationstateserializer.cpp b/simulationstateserializer.cpp index 38a14ba2..287ffa6a 100644 --- a/simulationstateserializer.cpp +++ b/simulationstateserializer.cpp @@ -643,14 +643,27 @@ state_serializer::deserialize_time( cParser &Input, scene::scratch_data &Scratch void state_serializer::deserialize_trainset( cParser &Input, scene::scratch_data &Scratchpad ) { + int line = Input.LineMain(); + if (line != -1) { + for (const std::pair &entry : Global.trainset_overrides) { + if (line != entry.first) + continue; + + skip_until(Input, "endtrainset"); + Input.injectString(entry.second); + + return; + } + } + if( true == Scratchpad.trainset.is_open ) { // shouldn't happen but if it does wrap up currently open trainset and report an error deserialize_endtrainset( Input, Scratchpad ); ErrorLog( "Bad scenario: encountered nested trainset definitions in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() ) + ")" ); } - Scratchpad.trainset = scene::scratch_data::trainset_data(); - Scratchpad.trainset.is_open = true; + Scratchpad.trainset = scene::scratch_data::trainset_data(); + Scratchpad.trainset.is_open = true; Input.getTokens( 4 ); Input