Skip to content

Scripting: Add Car.moveToTrack API #23359

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 2, 2025

Conversation

guysv
Copy link
Contributor

@guysv guysv commented Dec 9, 2024

So #22272 introduced the ability to set a vehicle's track location property, which allows teleporting vehicles across any other track piece available.

Back when I wrote that addition, I noticed that merely setting trackLocation does not actually trigger vehicle redraw. The vehicle teleports to its correct position only after trying to advance the track a bit on its own.

Alternatively, you could trigger track advancement with car.travelBy(), which is how I made the demo. I came to realize using travelBy is kind of hack, so here I figured a way to trigger vehicle redraw after setting trackLocation.

The way travelBy gets this effect is by adding some pending progress to be made for that vehicle (vehicle.remaining_distance, and calling UpdateTrackMotion, which eventually translates remaining_distance into calls to UpdateTrackMotionForwards (when going forward)

So the first move is to introduce a new vehicle flag VehicleFlags::UpdateSingleCar, that bypasses UpdateTrackMotion remaining_distance check, and makes the call to UpdateTrackMotionForwards regardless of pending moves.

Next, use VehicleFlags::UpdateSingleCar to also prevent UpdateTrackMotionForwards from advancing vehicle.track_progress, as we don't want to advance there when just recalculating state due to new trackLocation.

Errm nvm. all that, see second comment. Anyway I found how to recalculate vehicle state according to new track location

@Basssiiie FYI

@guysv
Copy link
Contributor Author

guysv commented Dec 9, 2024

Maybe instead of modifying trackLocation_set, I could introduce a new dedicated Car scripting method dedicated to calling UpdateTrackChange. Open for ideas.

@guysv guysv force-pushed the car-track-location-update branch from c08e648 to 3e8993d Compare December 9, 2024 13:30
@guysv
Copy link
Contributor Author

guysv commented Dec 9, 2024

I pushed a new version that calculates the new vehicle state on its own instead of piggy-backing UpdateTrackMotionForwards

@guysv guysv force-pushed the car-track-location-update branch 2 times, most recently from d272e08 to 9c15671 Compare December 9, 2024 13:35
@guysv
Copy link
Contributor Author

guysv commented Dec 9, 2024

rctdemo17.mp4

le demo (now without travelBy())

I also added track_progress clipping code to be within the current piece when coming from a longer one.

@@ -584,6 +584,20 @@ void Vehicle::MoveRelativeDistance(int32_t distance)
ClearFlag(VehicleFlags::MoveSingleCar | VehicleFlags::CollisionDisabled);
}

void Vehicle::UpdateTrackChange()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is all only ever useful for your one scripting bit of code it would make more sense to keep it with the rest of the scripting function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but doesn't it touch private Vehicle fields? I thought this means it has to happen in Vehicle.cpp no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_vehicleCurPosition namely.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_vehicleCurPosition namely.

Pretty sure that is a global var

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well but it's still only accessible from Vehicle.cpp if it's defined there. But nevermind that because I just tested and it works well with just using a local variable instead. dunno why it's being done like that in the existing functions.

But... on my way trying to move it to ScVehicle I ran into couple of Vehicle functions that really are private.
GetTrackProgress/GetMoveInfo/GetRideTypeDescriptor. What do you suggest?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the reason all the other users are using a global Is just because thats how it worked in assembly. I'd need to have a look see how all this is getting updated. Perhaps there is a different function we can make that can be used by a few other consumers. I'm just not a fan of having basically half a function in one file and the other half in another.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I follow what are you suggesting to do? refactor the bunch of other similar code to a single function that sorta looks like what I made?

@guysv guysv force-pushed the car-track-location-update branch 4 times, most recently from 892cfd2 to 214f33e Compare December 11, 2024 22:56
@duncanspumpkin
Copy link
Contributor

I would say bump scripting api version but I'm not sure it's needed at this time.

@guysv
Copy link
Contributor Author

guysv commented Dec 12, 2024

(comment deleted)

I thought I wrote trackLocation_set but I just expanded it to set more track properties onto the vehicle.
I can't tell if anyone who ever used car.trackLocation wants to get redraws now. Probably not?

That's why in my starting attempt I tried to confine all the code that relates to the redraw itself in another function, in case we want to introduce as a new method to Car that won't break earlier car.trackLocation usages.

@guysv
Copy link
Contributor Author

guysv commented Dec 12, 2024

Okay nevermind that^ I think we're ready for merge here.

Copy link
Member

@Basssiiie Basssiiie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still running in some redraw issues when moving the vehicle when the game is paused. Note how only half of the sprite is redrawn in the screenshot below.

image

When a game tick is triggered (either via the shortcut or unpausing), the vehicle is redrawn fully.

// Clip track progress to avoid being out of bounds of current piece
uint16_t trackTotalProgress = GetTrackProgress();
if (track_progress >= trackTotalProgress)
track_progress = trackTotalProgress - 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The track progress is capped here but the track progress of the vehicle is not updated accordingly, so the trackProgress getter now returns an out of bounds value if read after updating the trackLocation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm looks like I didn't even validate for invalid value from GetTrackProgress(). Nice catch!

@guysv
Copy link
Contributor Author

guysv commented Dec 26, 2024

I moved the new functionality to a new API method, Car.moveToTrack({x,y},elementIndex). Easier than documenting how you should only really ever set trackLocation to a valid track piece.

@guysv guysv force-pushed the car-track-location-update branch from 0f574f9 to ab63f2b Compare December 26, 2024 19:33
@guysv guysv changed the title Scripting: Redraw vehicle when setting track location Scripting: Add Car.moveToTrack API Dec 29, 2024
@tupaschoal tupaschoal requested a review from Basssiiie December 29, 2024 19:39
@guysv guysv force-pushed the car-track-location-update branch 3 times, most recently from 9d12cc1 to 2308cd3 Compare January 1, 2025 17:08
@tupaschoal
Copy link
Member

@duncanspumpkin and @Basssiiie can you double check this is ready to merge?

Copy link
Member

@Basssiiie Basssiiie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have tested it again and both the setter and the moveToTrack method still have some issues.

2025-01-02.13-44-13.mp4

Also wouldn't it be better to either have only moveToTrack and then trackLocation as a readonly getter, OR only having trackLocation getter and setter, instead of both the method and the setter?

Click here for my updated test script.
/// <reference path="../bin/openrct2.d.ts" />
// @ts-check

registerPlugin({
	name: "Test track location",
	version: "1",
	authors: ['Basssiiie'],
	targetApiVersion: 82,
	type: "local",
	licence: "MIT",
	main() {
		ui.registerMenuItem("Test track location", function() {
			ui.activateTool({
				id: 'test-pick-vehicle',
				cursor: 'cross_hair',
				filter: ["entity"],
				onDown: function(args) {
					var entityId = args.entityId;
					if (entityId === undefined) return;
					ui.tool.cancel();
					console.log("Entity "+entityId+" selected");
					var entity = map.getEntity(entityId);
					var window = ui.openWindow({
						classification: "test-track-location",
						title: "Test track location",
						width: 200,
						height: 150,
						onUpdate: function()
						{
							var trackLocation = entity.trackLocation;
							window.findWidget("info-label").text =
								"Entity id: "+entityId
								+"\nTile: "+[Math.floor(trackLocation.x / 32), Math.floor(trackLocation.y / 32)].join(", ")
								+"\nTrack: "+[trackLocation.x, trackLocation.y, trackLocation.z].join(", ")
								+"\nDirection: "+trackLocation.direction
								+"\nType: "+trackLocation.trackType
								+"\nProgress: "+entity.trackProgress+" / "+context.getTrackSegment(trackLocation.trackType).getSubpositionLength(entity.subposition, trackLocation.direction);
						},
						widgets: [
							{
								name: "info-label",
								type: "label",
								x: 10,
								y: 25,
								width: 180,
								height: 15,
							},
							{
								name: "pick-location-button",
								type: "button",
								x: 10,
								y: 105,
								width: 180,
								height: 15,
								text: "Set track location",
								onClick: function() {
									ui.activateTool({
										id: "test-set-track-location",
										cursor: "cross_hair",
										filter: ["ride"],
										onDown: function(args) {
											var coords = args.mapCoords;
											var index = args.tileElementIndex;
											if (!coords || index === undefined) return;
											ui.tool.cancel();
											var element = map.getTile(Math.floor(coords.x / 32), Math.floor(coords.y / 32)).getElement(index);
											var location = {
												x: coords.x,
												y: coords.y,
												z: element.baseZ,
												direction: element.direction,
												trackType: element.trackType
											}
											console.log("Set location to", location);
											entity.trackLocation = location;
										}
									})
								}
							},
							{
								name: "move-location-button",
								type: "button",
								x: 10,
								y: 125,
								width: 180,
								height: 15,
								text: "Move track location",
								onClick: function() {
									ui.activateTool({
										id: "test-move-track-location",
										cursor: "cross_hair",
										filter: ["ride"],
										onDown: function(args) {
											var coords = args.mapCoords;
											var index = args.tileElementIndex;
											if (!coords || index === undefined) return;
											ui.tool.cancel();
											var location = {
												x: coords.x,
												y: coords.y
											}
											console.log("Move location to", location, index);
											entity.moveToTrack(location, index);
										}
									})
								}
							},
						]
					})
				}
			})
		})
	}
});

And the park:
Six Flags flat train track.zip

/**
* Moves the vehicle to the track piece specified in the parameters.
*/
moveToTrack(coord: CoordsXY, elemIndex: number): void;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
moveToTrack(coord: CoordsXY, elemIndex: number): void;
moveToTrack(x: number, y: number, trackElementIndex: number): void;

And also have x and y be tile coordinates instead of entity coordinates would probably be neater. 🙂

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@guysv could you still look at this one?

Copy link

github-actions bot commented Feb 3, 2025

This pull request has been marked as stale and will be closed in 14 days if no action is taken. To keep it open, leave a comment or remove the stale-pr label. If you're awaiting feedback from a developer, please send us a reminder (either here or on Discord).

@github-actions github-actions bot removed the stale-pr label Feb 14, 2025
Copy link

This pull request has been marked as stale and will be closed in 14 days if no action is taken. To keep it open, leave a comment or remove the stale-pr label. If you're awaiting feedback from a developer, please send us a reminder (either here or on Discord).

@guysv guysv force-pushed the car-track-location-update branch from 2308cd3 to 71875c3 Compare March 22, 2025 09:13
Copy link
Member

@Basssiiie Basssiiie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had another test at this and it works great for the most part. All previous issues are resolved, except for one. The only thing that is still missing is calling this function in both travelBy() and moveToTrack() at the end, to prevent it from snapping back to the original position when "Uncap FPS" is enabled. 🙂

EntityTweener::Get().RemoveEntity(vehicle);

@@ -2676,7 +2669,7 @@ declare global {
/**
* The location and direction of where the car is on the track.
*/
trackLocation: CarTrackLocation;
trackLocation: CoordsXYZD;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's best to not revert this to the prior PR. Instead it'd be better to keep the getter as is, but only remove the setter as that's the broken one. Reading the vehicle's track type could still be useful in other scenarios.

Also make sure to make the properties on CarTrackLocation readonly as well, to avoid any confusion there. 🙂

Suggested change
trackLocation: CoordsXYZD;
readonly trackLocation: CarTrackLocation;

@@ -109,7 +110,7 @@
- Fix: [#22742, #22793] In game console does not handle format tokens properly.
- Fix: [#23135] Map generator tree placement has noticable patterns.
- Fix: [#23286] Currency formatted incorrectly in the in game console.
- Fix: [#23348] Console set commands dont print output properly.
- Fix: [#23348] Console set commands don't print output properly.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change is a mistake and should probably be reverted?

@guysv
Copy link
Contributor Author

guysv commented Mar 26, 2025

made a final push. I think its GTG!! @Basssiiie @tupaschoal

@guysv guysv force-pushed the car-track-location-update branch 2 times, most recently from 749402e to 90e9e46 Compare March 26, 2025 18:43
@tupaschoal tupaschoal requested a review from Basssiiie March 27, 2025 10:00
Copy link
Member

@Basssiiie Basssiiie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still missing two of my suggested changes unfortunately. 😥

One being that I suggested changing CarTrackLocation to this, to avoid people attempting to assign the properties (which does nothing):

    interface CarTrackLocation extends Readonly<CoordsXYZD> {
        readonly trackType: number;
    }

The other is an alternative signature for the moveToTrack() method, which I now have tagged you in again here @guysv

Edit: also needs a plugin api version increment.

@Basssiiie Basssiiie added the plugin api version Plugin API version needs updating - double check before merging! label Mar 27, 2025
@guysv guysv force-pushed the car-track-location-update branch from 4bf98ea to 8480ff5 Compare March 29, 2025 17:51
Copy link
Member

@Basssiiie Basssiiie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking all good to me. I have tested it again as well and it all works great now! Thank you for your time. 😃

@Basssiiie Basssiiie removed the plugin api version Plugin API version needs updating - double check before merging! label Mar 30, 2025
Guy Sviry added 7 commits April 1, 2025 18:13
A new function to move cars to tracks easier. Also redraws the car.
reverts 30a555d
car.moveToTrack() achieves the same thing in a saner API.
added back tracklocation.Get with track type
added EntityTweener call at the end of travelBy/moveToTrack
@guysv guysv force-pushed the car-track-location-update branch from 8480ff5 to 866a69d Compare April 1, 2025 15:13
Copy link
Member

@tupaschoal tupaschoal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At a glance it looks good to me.

@tupaschoal tupaschoal enabled auto-merge (squash) April 2, 2025 23:27
@tupaschoal tupaschoal added this to the v0.4.21 milestone Apr 2, 2025
@tupaschoal tupaschoal merged commit b92e05b into OpenRCT2:develop Apr 2, 2025
23 checks passed
Gymnasiast added a commit that referenced this pull request Apr 5, 2025
- Feature: [#22646] New scenario files now contain a minimap image, shown in the scenario selection window.
- Feature: [#23774] Climates can now be customised using objects.
- Feature: [#23876] New park save files now contain a preview image, shown in the load/save window.
- Improved: [#24078] Handrails on Wooden Roller Coaster station sprites with no platforms have been removed.
- Improved: [objects#379] Add additional colour schemes to Mine Train.
- Change: [#23932] The land rights window now checks “Land Owned” by default.
- Change: [#23936] The ‘guests prefer less/more intense rides’ settings have been turned into a dropdown.
- Change: [#24059] The ‘select other ride’ button is now available in the track designs manager.
- Change: [#24067] [Plugin] Registered menu items are now listed alphabetically.
- Change: [#24070] Footpath selection menus now show object names on hover using a tooltip.
- Change: [#24101] Frozen peeps are no longer removed when using the 'remove all guests' cheat.
- Fix: [#4225] Ride Construction window offers non-existent banked sloped to level curve (original bug).
- Fix: [#5281] Missing supports on miniature railways built backwards.
- Fix: [#7222] Transparent pixels in sloped path tunnels (original bug).
- Fix: [#10379] Banners outside the park can be renamed and modified (original bug).
- Fix: [#10582] Low clearance tunnels below water are drawn incorrectly (original bug).
- Fix: [#17524, #23710] Station bases are drawn on many ride types when the “No entrance, no platform station” style is selected.
- Fix: [#18169] CJK, Arabic and Vietnamese display all text as ‘???’ on Android.
- Fix: [#18309] Flying and Multi Dimension trains glitch when changing between inverted and uninverted track when uncap fps is on.
- Fix: [#19506] Queue paths can be placed on level crossings by replacing an existing regular path.
- Fix: [#21803] The park fence is drawn differently in OpenGL compared to software rendering when zoomed out.
- Fix: [#21824] Some sprites are drawn incorrectly when zoomed out in OpenGL rendering.
- Fix: [#21908] Ride mode warnings when hovering track designs.
- Fix: [#22820] OpenGL does not draw masked sprites correctly.
- Fix: [#22961] Clicking on the construction preview places duplicate flat rides and stalls.
- Fix: [#23359] Scripting: Add car.moveToTrack, an easier API than setting car.trackLocation directly.
- Fix: [#23443] New GOG version of RCT2 is not extracted correctly.
- Fix: [#23484] Stray coloured pixels on castle-themed stations and Roman-themed entrances/exits (original bug).
- Fix: [#23486] Object selection minimum requirements can be bypassed with close window hotkey.
- Fix: [#23743] Parks with guest goals over 32767 do not appear in the scenario list.
- Fix: [#23844] Sound effects keep playing when loading another save.
- Fix: [#23881] Compiling on Raspbian/arm-linux-gnueabihf fails.
- Fix: [#23891] Inverted Hairpin Coaster track can draw over things above it (original bug).
- Fix: [#23892] Gentle banked Wooden Roller Coaster track glitches as trains pass (original bug).
- Fix: [#23897] Reverse Freefall Coaster slope up to vertical track piece does not draw a vertical tunnel.
- Fix: [#23910] Heartline Twister Coaster track can draw over things above it (original bug).
- Fix: [#23939] Incorrect assertion when trying to load heightmap.
- Fix: [#23941] Underflow in “Repay loan and achieve a certain park value” objective when using Japanese.
- Fix: [#23949] Walls draw over sloped rear water edges and those edge sprites are misaligned (original bug).
- Fix: [#23960] Corner path fences can draw over adjacent sloped land (original bug).
- Fix: [#23961] Lamps and queue line tvs draw incorrectly on paths with fences.
- Fix: [#23983] Ordering files by size does not work and occasionally crashes the game.
- Fix: [#24009] [Plugin] The object manager API does not identify recently introduced object types.
- Fix: [#24028] Giga and LSM Launched Coaster booster sprites have pixels that draw over transparent pixels.
- Fix: [#24077] Track Designer crashes when clicking the park fence.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants