Skip to content

Commit f128f82

Browse files
committed
Fix rare bug where vehicle would not move to next track piece if start and end positions overlapped
1 parent 2df06ce commit f128f82

File tree

6 files changed

+81
-18
lines changed

6 files changed

+81
-18
lines changed

lib/duktape.d.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@ interface Duktape
2121
*/
2222
act(depth: number): DukStackEntry;
2323

24+
/**
25+
* Encodes its argument value into chosen format.
26+
*/
27+
enc(format: "hex" | "base64", value: any): string;
28+
enc(format: "jx" | "jc", value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;
29+
enc(format: "jx" | "jc", value: any, replacer?: (number | string)[] | null, space?: string | number): string;
30+
31+
/**
32+
* Decodes and parses its argument value from chosen format into a value.
33+
*/
34+
dec(format: "hex" | "base64", value: string): any;
35+
dec(format: "jx" | "jc", value: string, reviver?: (this: any, key: string, value: any) => any): any;
2436

2537
/**
2638
* Callback that gets triggered after an ECMAScript error has occured.
@@ -62,4 +74,4 @@ interface Performance
6274
* Gets the monotonic time in milliseconds, including fractions.
6375
*/
6476
now(): number;
65-
}
77+
}

package-lock.json

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"url": "https://github.com/Basssiiie/OpenRCT2-RideVehicleEditor/issues"
2121
},
2222
"dependencies": {
23-
"openrct2-flexui": "^0.1.0-prerelease.15"
23+
"openrct2-flexui": "^0.1.0-prerelease.20"
2424
},
2525
"devDependencies": {
2626
"@ava/typescript": "^4.0.0",

src/services/spacingEditor.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export function getDistanceFromProgress(car: Car, trackProgress: number): number
5050

5151
while (subpositionIterator._remainingProgress > 0 && iteratorSegment)
5252
{
53-
Log.debug("Remaining progress:", subpositionIterator._remainingProgress, ", total:", subpositionIterator._totalDistance);
53+
Log.debug("getDistanceFromProgress(): remaining:", subpositionIterator._remainingProgress, ", total:", subpositionIterator._totalDistance);
5454

5555
const trackPieceLength = trackDistances._progressLength;
5656

@@ -59,7 +59,7 @@ export function getDistanceFromProgress(car: Car, trackProgress: number): number
5959
// Quick add whole segment.
6060
subpositionIterator._totalDistance += trackDistances._totalDistance;
6161
subpositionIterator._remainingProgress -= trackPieceLength;
62-
Log.debug("total +=", trackDistances._totalDistance, "=", subpositionIterator._totalDistance, "(whole segment)");
62+
Log.debug("getDistanceFromProgress(): total +=", trackDistances._totalDistance, "=", subpositionIterator._totalDistance);
6363
}
6464
else
6565
{
@@ -80,15 +80,21 @@ export function getDistanceFromProgress(car: Car, trackProgress: number): number
8080

8181
const nextTrackPosition = iterator.position;
8282
const nextTrackDistance = getTrackDistances(iteratorSegment, subposition, nextTrackPosition.direction);
83+
const segmentDistance = subpositionIterator._getDistanceBetweenSegments(trackPosition, trackDistances, nextTrackPosition, nextTrackDistance);
84+
85+
if (segmentDistance)
86+
{
87+
// If segment distance is 0, the end and start positions overlap and another step should to be taken.
88+
subpositionIterator._totalDistance += segmentDistance;
89+
subpositionIterator._remainingProgress--;
90+
}
8391

84-
subpositionIterator._remainingProgress--;
85-
subpositionIterator._totalDistance += subpositionIterator._getDistanceBetweenSegments(trackPosition, trackDistances, nextTrackPosition, nextTrackDistance);
8692
trackPosition = nextTrackPosition;
8793
trackDistances = nextTrackDistance;
8894
}
8995

9096
const totalDistance = subpositionIterator._totalDistance;
91-
Log.debug("Move vehicle", totalDistance, "; progress change:", trackProgress);
97+
Log.debug("getDistanceFromProgress(): Move vehicle", totalDistance, ", progress change:", trackProgress, ", final progress:", trackDistances._totalDistance, totalDistance > 0 ? "" : "\x1b[93m[WARNING] VEHICLE DID NOT MOVE");
9298
return (trackProgress < 0) ? -totalDistance : totalDistance;
9399
}
94100

@@ -250,8 +256,13 @@ function isLocationEqual(left: CoordsXYZD, right: CoordsXYZD): boolean
250256
*/
251257
abstract class SubpositionIterator
252258
{
259+
/** Amount of track progress that's still to be iterated. */
253260
_remainingProgress: number;
261+
262+
/** Position of the car on the current track piece. */
254263
_distanceIndex: number;
264+
265+
/** Total distance travelled by the iterator. */
255266
_totalDistance: number = 0;
256267

257268
constructor (remainingProgress: number, currentProgress: number)
@@ -304,7 +315,7 @@ class ForwardIterator extends SubpositionIterator
304315
for (; distanceIdx < trackPieceLength && remainingProgress > 0; distanceIdx++)
305316
{
306317
this._totalDistance += distances[distanceIdx];
307-
Log.debug("total +=", distances[distanceIdx], "=", this._totalDistance, "(step:", distanceIdx, ", remaining:", remainingProgress, ")");
318+
Log.debug("forward(): total +=", distances[distanceIdx], "=", this._totalDistance, "(step:", distanceIdx, "/", trackPieceLength, ", remaining:", remainingProgress, ")");
308319
remainingProgress--;
309320
}
310321

@@ -313,6 +324,7 @@ class ForwardIterator extends SubpositionIterator
313324
}
314325
override _jumpSegment(trackIterator: TrackIterator): boolean
315326
{
327+
Log.debug("forward(): next segment:", trackIterator.position, "->", trackIterator.nextPosition);
316328
return trackIterator.next();
317329
}
318330
override _getDistanceBetweenSegments(previousTile: CoordsXYZ, previousTrack: Readonly<TrackDistances>, nextTile: CoordsXYZ, nextTrack: Readonly<TrackDistances>): number
@@ -350,14 +362,15 @@ class BackwardIterator extends SubpositionIterator
350362
while (--distanceIdx >= 0 && remainingProgress > 0)
351363
{
352364
this._totalDistance += distances[distanceIdx];
353-
Log.debug("total +=", distances[distanceIdx], "=", this._totalDistance, "(step:", distanceIdx, ", remaining:", remainingProgress, ")");
365+
Log.debug("backward(): total +=", distances[distanceIdx], "=", this._totalDistance, "(step:", distanceIdx, "/", trackPieceLength, ", remaining:", remainingProgress, ")");
354366
remainingProgress--;
355367
}
356368
this._remainingProgress = remainingProgress;
357369
this._distanceIndex = 0;
358370
}
359371
override _jumpSegment(trackIterator: TrackIterator): boolean
360372
{
373+
Log.debug("backward(): previous segment:", trackIterator.position, "->", trackIterator.previousPosition);
361374
return trackIterator.previous();
362375
}
363376
override _getDistanceBetweenSegments(previousTile: CoordsXYZ, previousTrack: Readonly<TrackDistances>, nextTile: CoordsXYZ, nextTrack: Readonly<TrackDistances>): number

src/utilities/logger.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ const isDuktapeAvailable = (typeof Duktape !== "undefined");
2121
*/
2222
function print(level: LogLevel, messages: unknown[]): void
2323
{
24-
console.log(`<RVE/${level}> ${messages.join(" ")}`);
24+
const message = messages
25+
.map(v => (Array.isArray(v) ? `[${v}]` : typeof v == "object" ? Duktape.enc('jx', v) : v))
26+
.join(" ");
27+
28+
console.log(`\x1b[1;33m<RVE/${level}>\x1b[37m ${message}`);
2529
}
2630

2731

tests/services/spacingEditor.tests.ts

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class TrackPiece
1212
{
1313
constructor(
1414
public position: CoordsXYZD,
15-
public type: number,
15+
public type: number, // must be unique in this test file to avoid cache collisions
1616
public subpositions: CoordsXYZ[])
1717
{}
1818

@@ -46,7 +46,7 @@ function setupTrackIterator(trackPieces: TrackPiece[], trackStartIndex?: number)
4646
x: Math.floor(p.position.x / 32),
4747
y: Math.floor(p.position.y / 32),
4848
elements: [
49-
Mock.trackElement({ type: "track", baseZ: p.position.z })
49+
Mock.trackElement({ type: "track", baseZ: p.position.z, direction: p.position.direction })
5050
]
5151
})),
5252
getTrackIterator()
@@ -331,9 +331,12 @@ const multiTurnTest = test.macro({
331331
exec(t, startTrackPiece: number, startProgress: number, progress: number, expectedResult: number): void
332332
{
333333
const trackPieces = [ rightTurn1TrackPiece, rightTurn2TrackPiece, steepUpTrackPiece, steepTurnTrackPiece ];
334-
const trackLocation: CarTrackLocation = { ...trackPieces[startTrackPiece].position, direction: 0, trackType: 0 };
335334
setupTrackIterator(trackPieces, startTrackPiece);
336-
const car = Mock.car({ trackProgress: startProgress, trackLocation, remainingDistance: (progress >= 0) ? ForwardRemainingDistance : 0 });
335+
const car = Mock.car({
336+
trackProgress: startProgress,
337+
trackLocation: trackPieces[startTrackPiece].toLocation(),
338+
remainingDistance: (progress >= 0) ? ForwardRemainingDistance : 0
339+
});
337340

338341
const distance = getDistanceFromProgress(car, progress);
339342

@@ -382,6 +385,36 @@ test("Flat track: move backwards by 1 and account for remaining distance cap", t
382385
});
383386

384387

388+
const steepToSlopedDownwardsTrackPiece = new TrackPiece({ x: 64, y: 64, z: 16, direction: 2 }, 21,
389+
[
390+
{ x: 16, y: 0, z: 31 }, { x: 16, y: 10, z: 16 }, { x: 16, y: 32, z: 0 },
391+
]);
392+
const slopedToFlatDownwardsTrackPiece = new TrackPiece({ x: 64, y: 96, z: 8, direction: 2 }, 22,
393+
[
394+
{ x: 16, y: 0, z: 8 }, { x: 16, y: 16, z: 1 }, { x: 16, y: 31, z: 0 },
395+
]);
396+
397+
test("Downward slope: move extra step forward if end point overlaps with start point", t =>
398+
{
399+
setupTrackIterator([ steepToSlopedDownwardsTrackPiece, slopedToFlatDownwardsTrackPiece ], 0);
400+
const car = Mock.car({ trackProgress: 2, remainingDistance: ForwardRemainingDistance, trackLocation: steepToSlopedDownwardsTrackPiece.toLocation() });
401+
402+
const distance = getDistanceFromProgress(car, 1);
403+
404+
t.is(distance, 10_905);
405+
});
406+
407+
test("Downward slope: move extra step backwards if end point overlaps with start point", t =>
408+
{
409+
setupTrackIterator([ steepToSlopedDownwardsTrackPiece, slopedToFlatDownwardsTrackPiece ], 1);
410+
const car = Mock.car({ trackProgress: 0, remainingDistance: 0, trackLocation: slopedToFlatDownwardsTrackPiece.toLocation() });
411+
412+
const distance = getDistanceFromProgress(car, -1);
413+
414+
t.is(distance, -10_905);
415+
});
416+
417+
385418
function createTrain(mapMock: GameMapMock, cars: Partial<Car>[]): RideTrain
386419
{
387420
const length = cars.length;

0 commit comments

Comments
 (0)