Add route parsing

This commit is contained in:
dominik-korsa 2025-07-12 14:00:50 +02:00
parent 32c39e189c
commit c4eac723ba
No known key found for this signature in database
GPG Key ID: 5A24D76EE0A30974
3 changed files with 59 additions and 9 deletions

View File

@ -50,6 +50,7 @@ const Constants = {
attachSignsOutOfBounds: true,
signalElemsUnknownSign: true,
signalElemsUnknownSignText: true,
routeInvalidSegment: true,
},
errors: {
invalidSceneryInfo: true

View File

@ -9,6 +9,7 @@ export default class Route extends SceneryObject {
category = "routes";
type = "Route";
points = [];
segments = [];
constructor(prefab_name, pos, rot, track_count, route_name, track_offset, electrified) {
super(route_name, pos, rot);
@ -39,6 +40,10 @@ export default class Route extends SceneryObject {
return route;
}
addSegment(length, radius, trackIds) {
this.segments.push({ length, radius, trackIds });
}
_getConnectionPoints() {
if (this.track_count === 1) {
return [this.pos.clone()];

View File

@ -29,6 +29,8 @@ export default class SceneryParser {
const lines = scText.split("\n").map(line => line.trim());
const scenery = new Scenery();
let currentRoute = null;
lines.forEach((line, index) => {
if(index === 0) {
const sceneryInfo = SceneryParser._parseSceneryInfo(line);
@ -37,9 +39,21 @@ export default class SceneryParser {
}
if(!line?.length) return;
if (currentRoute !== null) {
const foundRouteEnd = SceneryParser._parseRouteLine(line, currentRoute);
if (foundRouteEnd) {
scenery.addObject(currentRoute);
currentRoute = null;
}
} else {
const object = SceneryParser._parseObject(line);
if(!object) return; // skip null objects
if (object.type === 'Route') {
currentRoute = object;
} else {
scenery.addObject(object);
}
}
});
scenery.applyObjects();
@ -69,7 +83,8 @@ export default class SceneryParser {
static _parseObject(text) {
const type = text.split(";", 2)[0];
if(type.indexOf("Forest") !== -1 || type.indexOf("Empty") !== -1) {
if (type === '' || type === 'EndRoute' || type.indexOf("Forest") !== -1 || type.indexOf("Empty") !== -1) {
SceneryParserLog.warn('unknownObjectType', `Unexpected entry of type ${type} without a preceding Route object`);
return null;
}
@ -88,7 +103,6 @@ export default class SceneryParser {
return CameraHome.fromText(text);
case 'MainCamera':
return MainCamera.fromText(text);
case 'EndRoute':
case 'MiscGroup':
case 'EndMiscGroup':
case 'Wires':
@ -101,12 +115,11 @@ export default class SceneryParser {
case 'SSPController':
case 'TerrainGroup':
case 'EndTerrainGroup':
case '':
return null;
default:
SceneryParserLog.warn('unknownObjectType', `Unknown object type: ${type}`);
return null;
};
}
}
static _parseTrack(text) {
@ -147,4 +160,35 @@ export default class SceneryParser {
return Misc.fromText(Scenery.nextMiscId++, text);
}
}
// Returns true if EndRoute was found, false otherwise
static _parseRouteLine(text, route) {
if (text === 'EndRoute') return true;
const fields = text.split(';');
if (fields.length < 4) {
SceneryParserLog.warn('routeInvalidSegment', `Invalid route segment: "${text}", not enough fields`);
return;
}
const trackIds = fields[3]
.split(',')
.map(segment => {
const id = segment.split(':')[0];
if (!id) return null;
return parseInt(id);
});
if (trackIds.some(id => id === null || isNaN(id))) {
SceneryParserLog.warn('routeInvalidSegment', `Invalid route segment track IDs: ${fields[3]}`);
return;
}
if (trackIds.length !== route.track_count) {
SceneryParserLog.warn('routeInvalidSegment', `Route segment has invalid track count: expected ${route.track_count}, got ${trackIds.length}`);
return;
}
route.addSegment(
parseInt(fields[1]), // length
parseInt(fields[2]), // radius
trackIds,
);
return false;
}
}