Files
maszyna/launcher/scenery_scanner.cpp
2026-03-14 19:16:48 +00:00

172 lines
4.5 KiB
C++

#include "stdafx.h"
#include "scenery_scanner.h"
#include "utilities/Logs.h"
scenery_scanner::scenery_scanner(ui::vehicles_bank &bank)
: bank(bank)
{
}
void scenery_scanner::scan()
{
for (auto &f : std::filesystem::directory_iterator("scenery")) {
std::filesystem::path path(std::filesystem::relative(f.path(), "scenery/"));
if (*(path.filename().string().begin()) == '$')
continue;
if (string_ends_with(path.string(), ".scn"))
scan_scn(path);
}
std::sort(scenarios.begin(), scenarios.end(),
[](const scenery_desc &a, const scenery_desc &b) { return a.path < b.path; });
build_categories();
}
void scenery_scanner::scan_scn(std::filesystem::path path)
{
scenarios.emplace_back();
scenery_desc &desc = scenarios.back();
desc.path = path;
std::string file_path = "scenery/" + path.string();
cParser parser(file_path, cParser::buffer_FILE);
parser.expandIncludes = false;
while (!parser.eof()) {
parser.getTokens();
if (parser.peek() == "trainset")
parse_trainset(parser);
}
std::ifstream stream(file_path, std::ios_base::binary | std::ios_base::in);
int line_counter = 0;
std::string line;
while (std::getline(stream, line))
{
line_counter++;
if (line.size() < 6 || !string_starts_with(line, "//$"))
continue;
if (line[3] == 'i')
desc.image_path = "scenery/images/" + line.substr(5);
else if (line[3] == 'n')
desc.name = win1250_to_utf8(line.substr(5));
else if (line[3] == 'd')
desc.description += win1250_to_utf8(line.substr(5)) + '\n';
else if (line[3] == 'l')
desc.category = win1250_to_utf8(line.substr(5));
else if (line[3] == 'f') {
std::string lang;
std::string file;
std::string label;
std::istringstream stream(line.substr(5));
stream >> lang >> file;
std::getline(stream, label);
desc.links.push_back(std::make_pair(file, win1250_to_utf8(label)));
}
else if (line[3] == 'o') {
for (auto &trainset : desc.trainsets) {
if (line_counter < trainset.file_bounds.first
|| line_counter > trainset.file_bounds.second)
continue;
trainset.description = win1250_to_utf8(line.substr(5));
}
}
}
}
void scenery_scanner::parse_trainset(cParser &parser)
{
scenery_desc &desc = scenarios.back();
desc.trainsets.emplace_back();
auto &trainset = desc.trainsets.back();
trainset.file_bounds.first = parser.Line();
parser.getTokens(4);
parser >> trainset.name >> trainset.track >> trainset.offset >> trainset.velocity;
parser.getTokens();
while (parser.peek() == "node") {
trainset.vehicles.emplace_back();
dynamic_desc &dyn = trainset.vehicles.back();
std::string datafolder, skinfile, mmdfile, params;
parser.getTokens(2); // range_max, range_min
parser.getTokens(1, false); // name
parser >> dyn.name;
if (!parser.expectToken("dynamic"))
break;
parser.getTokens(7, false);
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()) {
dyn.params = params.substr(params_pos + 1, -1);
params.erase(params_pos);
}
{
std::istringstream couplingparser(params);
couplingparser >> dyn.coupling;
}
skinfile = ToLower(skinfile);
erase_extension(skinfile);
replace_slashes(datafolder);
auto vehicle_path = std::filesystem::path(ToLower(datafolder)) / ToLower(mmdfile);
auto it = bank.vehicles.find(vehicle_path);
if (it != bank.vehicles.end()) {
dyn.vehicle = it->second;
bool found = false;
for (const std::shared_ptr<ui::skin_set> &vehicle_skin : it->second->matching_skinsets) {
if (vehicle_skin->skin != skinfile)
continue;
dyn.skin = vehicle_skin;
found = true;
break;
}
if (!found && skinfile != "none")
ErrorLog("skin not found: " + skinfile + ", vehicle type: " + vehicle_path.string() + ", file: " + parser.Name(), logtype::file);
}
else {
ErrorLog("vehicle type not found: " + vehicle_path.string() + ", file: " + parser.Name(), logtype::file);
}
parser.getTokens();
if (parser.peek() != "enddynamic") {
parser >> dyn.loadtype;
parser.getTokens();
}
parser.getTokens();
}
trainset.file_bounds.second = parser.Line();
}
void scenery_scanner::build_categories()
{
for (auto &desc : scenarios) {
std::string name = desc.path.stem().string();
std::string prefix = desc.category;
// If the scenario does have a category, add it to the list so we can render it later in a group.
if (!prefix.empty())
categories[prefix].push_back(&desc);
}
}