openrct2-ridecreation-api
OpenRCT2 Ride Creation API Documentation
Overview
The Ride Creation API is a TCP-based JSON API that allows programmatic control of ride construction in OpenRCT2. It was designed specifically for reinforcement learning agents to build roller coasters and evaluate their performance using in-game ratings.
Features
- Create and manage rides programmatically
- Place track pieces with automatic validation
- Undo/delete last placed track piece for backtracking
- Manual entrance/exit placement for stations (via placeEntranceExit endpoint)
- Circuit completion detection
- Real-time ride statistics (excitement, intensity, nausea)
- Chain lift support for slopes
- Banking and turn support
Connection Details
- Protocol: TCP
- Port: 8080
- Host: localhost
- Message Format: JSON with newline delimiter
Protocol
Request Format
{
"endpoint": "endpointName",
"params": {
"param1": "value1",
"param2": "value2"
}
}
Each request must be terminated with a newline character (\n
).
Response Format
{
"success": true,
"payload": {
// Response data
}
}
Error responses:
{
"success": false,
"error": "Error description"
}
API Endpoints
1. createRide
Creates a new ride and initializes its state for track placement.
Request
{
"endpoint": "createRide",
"params": {
"rideType": 52, // 52 = Wooden Roller Coaster
"rideObject": 0, // Ride object variant
"entranceObject": 0, // Entrance style
"colour1": 0, // Primary color
"colour2": 1 // Secondary color
}
}
Response
{
"success": true,
"payload": {
"rideId": 0 // Unique ride identifier
}
}
2. placeTrackPiece
Places a track piece at specified coordinates with validation and automatic features.
Request
{
"endpoint": "placeTrackPiece",
"params": {
"tileCoordinateX": 67, // X position in tiles
"tileCoordinateY": 66, // Y position in tiles
"tileCoordinateZ": 14, // Z position (height) in height units
"direction": 0, // 0=west, 1=north, 2=east, 3=south
"ride": 0, // Ride ID from createRide
"trackType": 2, // See Track Types Reference
"rideType": 52, // Must match ride's type
"brakeSpeed": 0, // Brake speed (0 for no brake)
"colour": 0, // Track color scheme
"seatRotation": 0, // Seat rotation angle
"trackPlaceFlags": 0, // Placement flags
"isFromTrackDesign": true,// Design mode flag
"hasChainLift": false // Add chain lift (slopes only)
}
}
Response
{
"success": true,
"payload": {
"message": "Track piece placed for ride 0",
"nextEndpoint": {
"x": 66, // Next placement X
"y": 66, // Next placement Y
"z": 14, // Next placement Z
"direction": 0 // Next placement direction
},
"isCircuitComplete": false, // True when track loops back
"circuitMessage": "Continue building...",
"debug": {
"placedAt": {"x": 67, "y": 66, "z": 14},
"trackType": 2,
"elemDirection": 0
},
"stationDetected": true // Indicates a station piece was placed
}
}
Special Features:
- Station Pieces: Station pieces are tracked, use
placeEntranceExit
endpoint after building station - Chain Lift Support: Set
hasChainLift: true
for upward slopes (types 4, 5, 6) - Circuit Detection: Automatically detects when track completes a circuit back to the station
3. placeEntranceExit
Places entrance and exit for a ride's station. Call this after placing all station pieces.
Request
{
"endpoint": "placeEntranceExit",
"params": {
"rideId": 0 // Ride ID from createRide
}
}
Response (Success)
{
"success": true,
"payload": {
"entrance": {"x": 67, "y": 65, "direction": 3},
"exit": {"x": 67, "y": 67, "direction": 1},
"message": "Successfully placed entrance and exit"
}
}
Response (Partial Success)
{
"success": true,
"payload": {
"entrance": {"x": 67, "y": 65, "direction": 3},
"exit": null,
"warning": "Only partially successful - Could not place exit."
}
}
Notes:
- Automatically finds all station pieces in the ride
- Tries to place entrance and exit next to each station piece until both are successfully placed
- Places entrance and exit perpendicular to the track direction
- If space next to first station piece is blocked, it will try subsequent station pieces
- Must be called after placing station pieces
- Returns error if no station pieces are found
4. getValidNextPieces
Returns valid track pieces that can be placed at the current position based on track validation rules.
Request
{
"endpoint": "getValidNextPieces",
"params": {
"rideId": 0 // Ride ID to check
}
}
Response
{
"success": true,
"payload": {
"validPieces": [0, 6, 12, 16, 17, 42, 43], // Valid track type IDs
"lastTrackType": 2, // Previously placed type
"stateCategory": "station", // Current state category
"position": {
"x": 66,
"y": 66,
"z": 14,
"direction": 0
}
}
}
5. getRideStats
Returns the ride's ratings after testing is complete.
Request
{
"endpoint": "getRideStats",
"params": {
"rideId": 0
}
}
Response
{
"success": true,
"payload": {
"excitement": 6.54, // Excitement rating (0-10+)
"intensity": 5.23, // Intensity rating (0-10+)
"nausea": 3.12 // Nausea rating (0-10+)
}
}
6. startRideTest
Starts the ride in test mode to calculate ratings.
Request
{
"endpoint": "startRideTest",
"params": {
"rideId": 0
}
}
Response
{
"success": true,
"payload": "Ride 0 started in test mode."
}
7. listAllRides
Lists all rides currently in the park.
Request
{
"endpoint": "listAllRides"
}
Response
{
"success": true,
"payload": [
{
"id": 0,
"name": "Ride 1",
"type": 52
}
]
}
8. deleteLastTrackPiece
Removes the most recently placed track piece from a ride. Useful for backtracking when the RL agent detects collisions or wants to try a different path.
Note: This endpoint only removes track pieces, not entrances/exits. Entrances and exits are managed separately through the placeEntranceExit
endpoint.
Request
{
"endpoint": "deleteLastTrackPiece",
"params": {
"rideId": 0 // ID of the ride to remove track from
}
}
Response (when pieces remain)
{
"success": true,
"payload": {
"message": "Track piece removed from ride 0",
"piecesRemaining": 5, // Number of pieces still on the track
"nextEndpoint": { // Where to continue building from
"x": 65,
"y": 66,
"z": 14,
"direction": 0
},
"lastTrackType": 2 // Type of the now-last piece
}
}
Response (when no pieces remain)
{
"success": true,
"payload": {
"message": "Track piece removed from ride 0",
"piecesRemaining": 0,
"nextEndpoint": null, // No pieces left to build from
"lastTrackType": null
}
}
Error Response
{
"success": false,
"error": "No track pieces to delete for ride 0"
}
9. deleteAllRides
Deletes all rides from the park and clears their states.
Request
{
"endpoint": "deleteAllRides"
}
Response
{
"success": true,
"payload": "Deleted all rides."
}
10. getAllTrackSegments
Returns information about all available track segment types.
Request
{
"endpoint": "getAllTrackSegments"
}
Response
{
"success": true,
"payload": [
{
"type": 0,
"description": "Flat",
"trackGroup": "flat",
"length": 1,
"beginZ": 0,
"endZ": 0,
"beginDirection": 0,
"endDirection": 0,
"beginBank": 0,
"endBank": 0
}
// ... more segments
]
}
Track Types Reference
Basic Track Pieces
ID | Type | Description | Chain Lift Support |
---|---|---|---|
0 | Flat | Straight flat piece | No |
1 | EndStation | End of station | No |
2 | BeginStation | Beginning of station (triggers entrance/exit) | No |
3 | MiddleStation | Middle station piece | No |
Slopes
ID | Type | Description | Chain Lift Support |
---|---|---|---|
4 | Up25 | 25° upward slope | Yes |
5 | Up60 | 60° upward slope | Yes |
10 | Down25 | 25° downward slope | No |
11 | Down60 | 60° downward slope | No |
Slope Transitions
ID | Type | Description | Chain Lift Support |
---|---|---|---|
6 | FlatToUp25 | Transition from flat to 25° up | Yes |
7 | Up25ToUp60 | Transition from 25° to 60° up | No |
8 | Up60ToUp25 | Transition from 60° to 25° up | No |
9 | Up25ToFlat | Transition from 25° up to flat | No |
12 | FlatToDown25 | Transition from flat to 25° down | No |
13 | Down25ToDown60 | Transition from 25° to 60° down | No |
14 | Down60ToDown25 | Transition from 60° to 25° down | No |
15 | Down25ToFlat | Transition from 25° down to flat | No |
Turns
ID | Type | Description |
---|---|---|
16 | LeftQuarterTurn5Tiles | Large left turn |
17 | RightQuarterTurn5Tiles | Large right turn |
42 | LeftQuarterTurn3Tiles | Small left turn |
43 | RightQuarterTurn3Tiles | Small right turn |
Banking
ID | Type | Description |
---|---|---|
18 | FlatToLeftBank | Transition to left bank |
19 | FlatToRightBank | Transition to right bank |
20 | LeftBankToFlat | Left bank to flat |
21 | RightBankToFlat | Right bank to flat |
32 | LeftBank | Left banked piece |
33 | RightBank | Right banked piece |
Banked Turns
ID | Type | Description |
---|---|---|
22 | BankedLeftQuarterTurn5Tiles | Large banked left turn |
23 | BankedRightQuarterTurn5Tiles | Large banked right turn |
44 | LeftBankedQuarterTurn3Tiles | Small banked left turn |
45 | RightBankedQuarterTurn3Tiles | Small banked right turn |
Track Validation Rules
The API enforces track connection rules based on the current track state:
State Categories
- station: Station pieces
- flat: Flat straight pieces
- up25: 25° upward slope
- up60: 60° upward slope
- down25: 25° downward slope
- down60: 60° downward slope
- turn: Turn pieces
- left_bank: Left banking
- right_bank: Right banking
- flat_to_left_bank: Transitioning to left bank
- flat_to_right_bank: Transitioning to right bank
Station Placement
Important: Station pieces can only be placed:
- At the beginning of a ride (when no track exists)
- From other station pieces (to extend the station)
Once you've built past the station, you cannot build another station. This prevents RL agents from creating multiple stations which would be invalid.
Connection Rules
From Station
- ✅ Can connect to: EndStation, MiddleStation only
From End Station
- ✅ Can connect to: flat, slope transitions, turns, banking transitions
From Flat
- ✅ Can connect to: flat, slope transitions, turns, banking transitions
From Up25
- ✅ Can connect to: continue up25, transition to flat, transition to up60
From Up60
- ✅ Can connect to: continue up60, transition to up25
From Down25
- ✅ Can connect to: continue down25, transition to flat, transition to down60
From Down60
- ✅ Can connect to: continue down60, transition to down25
From Turn
- ✅ Can connect to: flat, turns, gentle transitions, banking starts
From Banking States
- ✅ Left Bank: continue left bank, left-bank-to-flat, banked left turns
- ✅ Right Bank: continue right bank, right-bank-to-flat, banked right turns
Example Usage (Python)
Basic Connection
import socket
import json
def send_request(sock, request):
message = json.dumps(request) + "\n"
sock.sendall(message.encode("utf-8"))
file_obj = sock.makefile("r")
line = file_obj.readline()
return json.loads(line)
# Connect to API
sock = socket.create_connection(("localhost", 8080))
Create Ride and Build Track
# Create ride
req = {
"endpoint": "createRide",
"params": {
"rideType": 52,
"rideObject": 0,
"entranceObject": 0,
"colour1": 0,
"colour2": 1
}
}
resp = send_request(sock, req)
ride_id = resp["payload"]["rideId"]
# Place station pieces
for i in range(3): # Place 3 station pieces
track_type = 2 if i == 0 else 3 # BeginStation, then MiddleStation
req = {
"endpoint": "placeTrackPiece",
"params": {
"tileCoordinateX": 67 - i, # Move left for each piece
"tileCoordinateY": 66,
"tileCoordinateZ": 14,
"direction": 0,
"ride": ride_id,
"trackType": track_type,
"rideType": 52,
"brakeSpeed": 0,
"colour": 0,
"seatRotation": 0,
"trackPlaceFlags": 0,
"isFromTrackDesign": True
}
}
resp = send_request(sock, req)
next_pos = resp["payload"]["nextEndpoint"]
# Place entrance and exit after station is complete
req = {
"endpoint": "placeEntranceExit",
"params": {
"rideId": ride_id
}
}
resp = send_request(sock, req)
print(f"Entrance/exit placed: {resp['payload']}")
# Get valid pieces for next position
req = {
"endpoint": "getValidNextPieces",
"params": {"rideId": ride_id}
}
resp = send_request(sock, req)
valid_pieces = resp["payload"]["validPieces"]
# Place upward slope with chain lift
req = {
"endpoint": "placeTrackPiece",
"params": {
"tileCoordinateX": next_pos["x"],
"tileCoordinateY": next_pos["y"],
"tileCoordinateZ": next_pos["z"],
"direction": next_pos["direction"],
"ride": ride_id,
"trackType": 6, # FlatToUp25
"rideType": 52,
"brakeSpeed": 0,
"colour": 0,
"seatRotation": 0,
"trackPlaceFlags": 0,
"isFromTrackDesign": True,
"hasChainLift": True # Add chain lift
}
}
resp = send_request(sock, req)
# Example: Delete last piece if we detect a collision
if track_would_collide: # Your collision detection logic
req = {
"endpoint": "deleteLastTrackPiece",
"params": {"rideId": ride_id}
}
resp = send_request(sock, req)
if resp["success"]:
next_pos = resp["payload"]["nextEndpoint"]
print(f"Removed piece, can rebuild from: {next_pos}")
# Check if circuit is complete
if resp["payload"]["isCircuitComplete"]:
print("Circuit complete! Ready for testing.")
# Start ride test
req = {
"endpoint": "startRideTest",
"params": {"rideId": ride_id}
}
send_request(sock, req)
# Get ratings (after test completes)
req = {
"endpoint": "getRideStats",
"params": {"rideId": ride_id}
}
resp = send_request(sock, req)
stats = resp["payload"]
print(f"Excitement: {stats['excitement']}")
print(f"Intensity: {stats['intensity']}")
print(f"Nausea: {stats['nausea']}")
Error Handling
Common Errors
- "Missing endpoint" - Request doesn't include endpoint field
- "Missing parameter: X" - Required parameter X not provided
- "Ride not found" - Invalid ride ID
- "Track has no valid next position" - Track piece doesn't connect properly
- "Failed to place track piece" - Invalid placement (collision, invalid position)
Best Practices
- Always check
success
field in responses - Use
getValidNextPieces
before placing to ensure valid connections - Store
nextEndpoint
from each placement for the next piece - Check
isCircuitComplete
to know when track is ready for testing - Use
deleteLastTrackPiece
to backtrack when collision detection triggers - Delete all rides before starting a new training session
Manual Station Management
Entrance/Exit Placement
After placing all station pieces, use the placeEntranceExit
endpoint to add entrance and exit:
- Automatically finds all station pieces in the ride
- Attempts to place entrance and exit next to each station piece
- Places entrance on one side perpendicular to track
- Places exit on the opposite side
- Directions are set to face appropriately (entrance towards station, exit away)
- If space next to a station piece is blocked, automatically tries the next station piece
- Continues until both entrance and exit are successfully placed or all station pieces have been tried
- Placement adjusts based on track direction to avoid blocking the track path
Circuit Completion Detection
The API automatically detects when a track completes a circuit:
- Checks if next placement position matches station start
- Verifies direction alignment
- Returns
isCircuitComplete: true
when circuit is ready - Provides status message for user feedback
State Management
- Track states are maintained per ride
- States are cleared when rides are deleted
- Prevents state conflicts when ride IDs are reused
Reinforcement Learning Integration
This API is designed for RL agents with the following considerations:
State Space
- Current track position (x, y, z, direction)
- Valid next pieces list
- Track state category
- Circuit completion status
Action Space
- Select from valid track pieces only
- Binary decision for chain lift on slopes
Reward Function
- Use ride ratings (excitement, intensity, nausea) after testing
- Bonus for completing circuit
- Penalty for invalid placements
Episode Management
- Call
deleteAllRides
to reset environment - Create new ride with
createRide
- Build track until circuit completes or max steps
- Test ride and get ratings for reward
- Repeat for next episode
Version History
- v0.1 - Initial API with basic track placement, validation, automatic entrance/exit placement, and circuit detection