Editor¶
The track editor. Pieces are identified by int ids. An id stops working once its piece is deleted: the functions
taking it return false or skip it. Positions are in game units (x, y, z, with z up), rotations in degrees.
Select, DuplicateSelection and RotatePieces do their work through the game's editor. The game's time for
that doesn't count against the plugin's time budget (up to 5 seconds a frame).
IsOpen¶
bool Editor::IsOpen()
Whether the track editor is running.
Example
section.visible = Editor::IsOpen();
if (!Editor::IsOpen())
return;
IsTesting¶
bool Editor::IsTesting()
Whether a test run of the track being edited is on (the editor's play buttons), as opposed to editing it. Requires host 0.15.2.
Example
if (Editor::IsTesting() && !wasTesting)
StartPath();
Selection¶
array<int>@ Editor::Selection()
The selected pieces.
Example
array<int>@ selected = Editor::Selection();
Log::Info(selected.length() + " pieces selected");
Placed¶
array<int>@ Editor::Placed()
Pieces placed from the palette this frame. Pastes and duplicates aren't included.
Example
// Put every new piece on whole-unit coordinates
array<int>@ placed = Editor::Placed();
for (uint i = 0; i < placed.length(); i++)
{
double x, y, z;
if (Editor::GetLocation(placed[i], x, y, z))
Editor::SetLocation(placed[i], Round(x), Round(y), Round(z));
}
GetLocation¶
bool Editor::GetLocation(int, double &out, double &out, double &out)
A piece's position. Returns false if the piece no longer exists.
Example
double x, y, z;
if (Editor::GetLocation(id, x, y, z))
Log::Info("at " + x + ", " + y + ", " + z);
GetRotation¶
bool Editor::GetRotation(int, double &out, double &out, double &out)
A piece's rotation in degrees: pitch, yaw, roll. Returns false if the piece no longer exists.
Example
double pitch, yaw, roll;
Editor::GetRotation(id, pitch, yaw, roll);
SetLocation¶
bool Editor::SetLocation(int, double, double, double)
Moves a piece. After moving selected pieces, call Select with them so the editor's gizmo follows. Piece ids are the
open editor's placed pieces only (host 0.23.4 and newer): anything else, or any id during a test run or outside the
editor, is refused.
Example
Editor::SetLocation(id, x + 100, y, z); // 100 units along X
Editor::Select(Editor::Selection());
SetRotation¶
bool Editor::SetRotation(int, double, double, double)
Rotates a piece to an absolute rotation in degrees: pitch, yaw, roll.
Example
// Face the other way
double pitch, yaw, roll;
Editor::GetRotation(id, pitch, yaw, roll);
Editor::SetRotation(id, pitch, yaw + 180, roll);
ViewForward¶
void Editor::ViewForward(double &out, double &out, double &out)
The direction the editor camera is looking, as a unit vector.
Example
// 500 units in front of the camera
double fx, fy, fz;
Editor::ViewForward(fx, fy, fz);
Editor::SetLocation(id, x + fx * 500, y + fy * 500, z + fz * 500);
ScreenPosition¶
bool Editor::ScreenPosition(int, float &out, float &out)
Where a piece's middle (the centre of its bounds) is on screen, in the units of Input::MousePosition. Returns false
when it's behind the camera. Requires host 0.13.0.
Example
// the pieces whose middle is inside a box on screen
array<int> inside;
array<int>@ pieces = Editor::Pieces();
for (uint i = 0; i < pieces.length(); i++)
{
float x, y;
if (Editor::ScreenPosition(pieces[i], x, y) && x >= left && x <= right && y >= top && y <= bottom)
inside.insertLast(pieces[i]);
}
SetOutline¶
bool Editor::SetOutline(int, bool)
Draws or removes the editor's yellow selection outline on a piece without selecting it, for showing what an action will affect. Selecting or deselecting the piece resets it. Returns false if the piece has no mesh to outline. Requires host 0.13.0.
Example
Editor::SetOutline(piece, true); // about to be selected
Select¶
void Editor::Select(const array<int>@)
Selects exactly these pieces, with the editor's own highlight and gizmo.
Example
// Select the copies after duplicating
Editor::Select(copies);
DuplicateSelection¶
array<int>@ Editor::DuplicateSelection()
Copies the selected pieces in place and returns the copies, which are left selected.
Example
array<int>@ copies = Editor::DuplicateSelection();
if (copies.length() == 0)
Log::Warn("nothing selected to copy");
RotatePieces¶
void Editor::RotatePieces(const array<int>@, double, double, double, double, double, double)
Turns pieces about a point by the given degrees around the world X, Y and Z axes (X first, then Y, then Z). Both their positions and their rotations turn.
Example
// Turn the selection 90 degrees around the vertical axis through its centre
array<int>@ ids = Editor::Selection();
double cx = 0, cy = 0, cz = 0;
for (uint i = 0; i < ids.length(); i++)
{
double x, y, z;
Editor::GetLocation(ids[i], x, y, z);
cx += x / ids.length(); cy += y / ids.length(); cz += z / ids.length();
}
Editor::RotatePieces(ids, cx, cy, cz, 0, 0, 90);
Editor::Select(ids);
SetTabCycling¶
void Editor::SetTabCycling(bool)
While on, Tab and Shift+Tab move between the nine transform boxes in the details panel (location, rotation, scale; X, Y, Z).
Example
// On only while the editor is open
Editor::SetTabCycling(Editor::IsOpen());
SetRotateAroundCenter¶
void Editor::SetRotateAroundCenter(bool)
While on, rotating two or more pieces turns them about the centre of the selection instead of the last selected
piece. The same as SetRotateMode(Editor::RotateAroundCenter) (on) or SetRotateMode(Editor::RotateDefault) (off).
Example
[Setting name="Rotate multiple pieces around their centre"]
bool RotateAroundCenter = false;
void OnSettingsChanged()
{
Editor::SetRotateAroundCenter(RotateAroundCenter);
}
SetRotateMode¶
void Editor::SetRotateMode(RotateMode)
How rotating two or more pieces works: Editor::RotateDefault (the editor's own: about the last selected piece),
Editor::RotateAroundCenter (about the centre of the selection) or Editor::RotateMirrored (each piece turns in
place, and the pieces on the two sides of the selection's centre turn opposite ways, as mirror images; the side of
the last selected piece turns the way you drag).
Example
Editor::SetRotateMode(Editor::RotateMirrored);
GetRotateMode¶
RotateMode Editor::GetRotateMode()
The rotate mode in use (SetRotateMode).
Example
if (Editor::GetRotateMode() == Editor::RotateMirrored)
Log::Info("mirrored");
NextClick¶
bool Editor::NextClick(int &out, int &out, bool &out)
The next click on the world (not on the editor's panels) since the last call, oldest first, as the editor handled it:
the piece clicked (-1 for none; found by the editor's own pick), the keys held (Editor::ClickShift, ClickCtrl, ClickAlt, and
ClickOnGizmo when the click was on the move/rotate/scale gizmo) and whether that piece was selected before the
click. The game's own clicks: a plain click selects just that piece; Shift and Ctrl add it; neither removes.
Returns false when there are none left.
A click usually arrives while the mouse button is still down, and a press may be the start of a drag. Changing the
selection then (Editor::Select) ends that drag, so only select when the selection really has to change.
Example
// Shift/Ctrl on a selected piece takes it out of the selection
int piece, keys;
bool wasSelected;
while (Editor::NextClick(piece, keys, wasSelected))
{
if (piece < 0 || (keys & Editor::ClickOnGizmo) != 0)
continue;
if ((keys & (Editor::ClickShift | Editor::ClickCtrl)) != 0 && wasSelected)
{
array<int>@ selection = Editor::Selection();
selection.removeAt(selection.find(piece));
Editor::Select(selection);
}
}
Pieces¶
array<int>@ Editor::Pieces()
Every piece of the open map.
Example
Log::Info(Editor::Pieces().length() + " pieces");
PieceClass¶
string Editor::PieceClass(int)
What kind of piece it is (its class name, e.g. BP_Ramp_Curve1_C), or "" if it no longer exists. With the
position, enough to find a piece again when the map is opened later (ids only last while it is open).
Example
string kind = Editor::PieceClass(id);
MapName¶
string Editor::MapName()
The name of the map open in the editor, as its header shows it; "" for a new map before it is saved.
Example
string key = "groups:" + Editor::MapName();
Typing¶
bool Editor::Typing()
Whether a text box has the keyboard (the map name, a transform box, a search box, or a plugin's text input): keys pressed now are being typed, so hotkeys should leave them alone.
Example
if (Input::Pressed(Input::G) && !Editor::Typing())
GroupSelection();
AddToolbarChoice¶
int Editor::AddToolbarChoice(const string &in, const array<string>@, int = 0)
Adds a button to the editor's toolbar, after the world/local toggle (the globe), in the toolbar's own style: an icon
and a dropdown of options, starting at selected. The icon is a game texture ("/Game/...") or a PNG in your
plugin's folder. Returns its number for ToolbarChoice. The button is removed when the plugin stops.
Example
int rotateChoice = Editor::AddToolbarChoice("/Game/Art/UI/Textures/Editor/t_rotateIcon.t_rotateIcon",
{"default", "center", "mirrored"}, 0);
ToolbarChoice¶
int Editor::ToolbarChoice(int)
The option a toolbar button shows now (its index), or -1 if there is no such button.
Example
int chosen = Editor::ToolbarChoice(rotateChoice);
SetToolbarChoice¶
void Editor::SetToolbarChoice(int, int)
Shows another option on a toolbar button.
Example
Editor::SetToolbarChoice(rotateChoice, 0);
AddHotkey¶
void Editor::AddHotkey(const string &in, const string &in, const string &in = "")
Adds a row to the editor's key list (the panel the info button shows), after the game's single-key rows: a key image (a game texture "/Game/..." or a PNG in your plugin's folder) and what the key does. Handling the key is up to the plugin. Removed when the plugin stops. With a third argument, a second image, the row reads "first + second" (a modifier and a key or mouse button).
Example
Editor::AddHotkey(Plugins::Folder() + "keyboard_g.png", "group");
Editor::AddHotkey("/Game/Art/UI/Textures/KeyboardMouse/keyboard_alt.keyboard_alt", "select one piece",
"/Game/Art/UI/Textures/KeyboardMouse/mouse_left.mouse_left");
BudgetLimit¶
int Editor::BudgetLimit()
The track editor's piece budget limit (the game's setting is 300), or -1 if it can't be read. Since the game's 2026-10-06 update the editor has no piece budget, so nothing is limited by it. Requires host 0.16.1.
Example
Log::Info("pieces: " + Editor::BudgetUsed() + " of " + Editor::BudgetLimit());
BudgetUsed¶
int Editor::BudgetUsed()
How much of the piece budget the map in the editor uses (each piece counts 1, checkpoints 0), or -1 outside the editor. The host counts the pieces itself (the game stopped counting them in its 2026-10-06 update). Requires host 0.16.1.
Example
if (Editor::BudgetUsed() > Editor::BudgetLimit() - 10)
Log::Warn("nearly out of pieces");
SetBudgetLimit¶
bool Editor::SetBudgetLimit(int)
Changes the piece budget limit for the session. 0 gives the game's own back, as does the plugin stopping. False if
it couldn't be changed. Since the game's 2026-10-06 update the editor has no piece budget, so this no longer changes
how many pieces can be placed. Requires host 0.16.1.
Example
Editor::SetBudgetLimit(1000); // room for 1000 pieces
Editor::SetBudgetLimit(0); // the game's own again
HideByMaterial¶
int Editor::HideByMaterial(const string &in)
Stops drawing every piece of the map that uses this material (a material path such as
/Game/Art/Materials/Masters/M_Empty, or any material instance made from it) in any of its slots, and returns how
many pieces that is. Only the drawing stops: the pieces keep their collision, so the ball still rolls on them, and
they can still be clicked in the editor. Works in the editor, during its test run (the run plays on the same
pieces) and in a race of one of the player's own never-published maps (Tracks::OpenLocal), where its pieces are the
race level's own; in a race of any other map (a live workshop map) it hides nothing and returns 0. One call goes through every piece natively (about 40,000 pieces in one go is fine). Pieces that appear later
(another map opened, a paste, new pieces) are drawn until you call it again; calling it again for pieces already
hidden costs little and counts them again. Everything a plugin hid is drawn again when it stops. Requires host 0.26.0.
Example
// a map whose pieces are only collision, drawn over by a model of its own
int hidden = Editor::HideByMaterial("/Game/Art/Materials/Masters/M_Empty");
Log::Info(hidden + " pieces not drawn");
ShowAll¶
int Editor::ShowAll()
Draws again every piece your plugin hid with HideByMaterial, and returns how many parts of pieces that was.
Requires host 0.26.0.
Example
Editor::ShowAll();
Editor::RotateMode¶
Editor::RotateDefault, Editor::RotateAroundCenter, Editor::RotateMirrored
Editor::ClickFlag¶
Editor::ClickShift, Editor::ClickCtrl, Editor::ClickAlt, Editor::ClickOnGizmo