From c1f1b76b0eb7c56e0fdd7bcbce83d5392cc955b3 Mon Sep 17 00:00:00 2001 From: Ryan Barlow <7389646+ryanbarlow97@users.noreply.github.com> Date: Sat, 26 Sep 2026 00:20:00 +0000 Subject: [PATCH 1/2] docs: joins keep train direction, dig guards dropped turnouts Co-Authored-By: Claude Opus 5.5 (1M context) --- projects/VehicleFramework/docs/trains.md | 4 ++-- projects/VehicleFramework/docs/using-trains.md | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/projects/VehicleFramework/docs/trains.md b/projects/VehicleFramework/docs/trains.md index 3013ff6..ecdb673 100644 --- a/projects/VehicleFramework/docs/trains.md +++ b/projects/VehicleFramework/docs/trains.md @@ -65,10 +65,10 @@ Track items, lay rules, and train debug logging live in [`trains.yml`](https://g One spline per track (no stored sections). A **stroke** is one lay with the configured layer item (`item-layer`, default `m.utils.train_track_layer`): - Left-click: **start location** (block or existing track). Click an existing end to join that track. -- Right-click: **end location**. New track is a straight line in XZ from start to end (player look is ignored). Click within `join-distance` of an existing **end** to join: same track extends, or **two tracks link into one** if start is on one end and end is on another. Join curves from the **track** heading. Crossing the middle of a track still refuses (use the junction item for a turnout). +- Right-click: **end location**. New track is a straight line in XZ from start to end (player look is ignored). Click within `join-distance` of an existing **end** to join: same track extends, or **two tracks link into one** if start is on one end and end is on another. Join curves from the **track** heading. Crossing the middle of a track still refuses (use the junction item for a turnout). Joins keep the direction (`+s`) of any track a train is on, because trains face `+s`: closing a loop never reverses the track, and linking two tracks reverses at most one track that has no train and is not a branch. Linking two occupied tracks start to start, or end to end, is refused. - **Creative / spectator:** the spline is saved, then displays rebake in one step. One place sound + particles at the last sample (`build` in `trains.yml`). - **Survival / adventure:** same save, but displays grow along the new stroke one sample every `build.interval-ticks` (default 4, five per second). Prefix rebakes so collinear runs become medium then large. Each step plays `build.sound` and particles at the new sample, and swings the main hand if `build.swing` is true. Set `build.interval-ticks` to `0` to always place instantly. Connecting two tracks or closing a loop is still instant plus one burst. -- Remover item (`item-remover`, default `m.utils.train_track_remover`): left-click **digs** a sample (interior dig **splits** into two tracks). On a branch, digging any part of the **initial turnout lay** (stored as `turnoutS` on the junction) removes the whole turnout (junction, switch, and that stub). Digging past that initial lay uses normal dig/split rules; a longer branch extension is kept as plain track. The through stem stays. The remover refuses to dig track that a bound consist occupies, measured from each car out to its couplers. When a dig or lay rebuilds a spline, trains on it keep their world position on the new spline or pieces. +- Remover item (`item-remover`, default `m.utils.train_track_remover`): left-click **digs** a sample (interior dig **splits** into two tracks). On a branch, digging any part of the **initial turnout lay** (stored as `turnoutS` on the junction) removes the whole turnout (junction, switch, and that stub). Digging past that initial lay uses normal dig/split rules; a longer branch extension is kept as plain track. The through stem stays. The remover refuses to dig track that a bound consist occupies, measured from each car out to its couplers. That includes a branch turnout the dig would drop because its frog ends up on a piece shorter than `min-lay-distance`. When a dig or lay rebuilds a spline, trains on it keep their world position on the new spline or pieces. - Junction item (`item-junction`, default `m.utils.train_track_junction`): right-click **existing track** (interior allowed) to start a junction (nothing is saved yet). Then layer **right-click** lays **one** turnout from that frog. The junction is saved only if that branch lays. Through stays the original spline. Layer **left-click** while a junction is pending cancels it and marks a normal start. The stem must be at least `min-lay-distance` (default 8) long; loops are exempt. After a split, a junction rehomed onto a piece shorter than that is dropped with its branch. - `min-junction-spacing` (default 16) along stem arc `s` (loop wrap). One branch per junction (no 3-way). Joining a branch tip into another track is not shipped. - `max-junction-length` (default 32): the turnout from frog to click cannot be longer than that (straight-line or along the laid curve). diff --git a/projects/VehicleFramework/docs/using-trains.md b/projects/VehicleFramework/docs/using-trains.md index 63782d6..9173b0a 100644 --- a/projects/VehicleFramework/docs/using-trains.md +++ b/projects/VehicleFramework/docs/using-trains.md @@ -43,6 +43,7 @@ Left-click with the layer item to set the start. Right-click to set the end. The - Click an existing end to extend that track, or to join two tracks into one when the start and end are on different tracks. - Ends within `join-distance` (default 1.5) can join. A join that turns more than `max-turn-degrees` (default 35) is refused. +- Joining never turns a train round. If both tracks have trains on them and one would have to run the other way, the join is refused; move a train first. - A new stroke shorter than `min-lay-distance` (default 8) is refused. Loops are exempt. - Grade stays flat, then climbs at `desired-grade-degrees` (default 6) and never steeper than `max-grade-degrees` (default 10). - The corridor is 3 blocks wide and 3 tall. Solids and overlapping track refuse the lay. Plants do not. @@ -50,7 +51,7 @@ Left-click with the layer item to set the start. Right-click to set the end. The Right-click existing track with the junction item to start a turnout, then right-click with the layer to lay one branch. Left-click with the layer cancels the pending junction. One branch per junction. Branches cannot be longer than `max-junction-length` (default 32). Junctions along the same track must be at least `min-junction-spacing` (default 16) apart. -The remover digs a sample. Digging the middle splits the track. Digging the initial turnout lay removes that turnout. Track past that first lay stays. You cannot dig track under a train; move the train first. Trains elsewhere on the track stay where they are. +The remover digs a sample. Digging the middle splits the track. Digging the initial turnout lay removes that turnout. Track past that first lay stays. You cannot dig track under a train, or next to a junction when that would remove a turnout a train is on; move the train first. Trains elsewhere on the track stay where they are. ## Driving From bbe0574df154fbdbe96b46a7b3b0491bc774bf96 Mon Sep 17 00:00:00 2001 From: Ryan Barlow <7389646+ryanbarlow97@users.noreply.github.com> Date: Sat, 26 Sep 2026 00:29:38 +0000 Subject: [PATCH 2/2] docs: unloaded trains re-find their track on load Co-Authored-By: Claude Opus 5.5 (1M context) --- projects/VehicleFramework/docs/trains.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/VehicleFramework/docs/trains.md b/projects/VehicleFramework/docs/trains.md index ecdb673..e6e8e80 100644 --- a/projects/VehicleFramework/docs/trains.md +++ b/projects/VehicleFramework/docs/trains.md @@ -65,10 +65,10 @@ Track items, lay rules, and train debug logging live in [`trains.yml`](https://g One spline per track (no stored sections). A **stroke** is one lay with the configured layer item (`item-layer`, default `m.utils.train_track_layer`): - Left-click: **start location** (block or existing track). Click an existing end to join that track. -- Right-click: **end location**. New track is a straight line in XZ from start to end (player look is ignored). Click within `join-distance` of an existing **end** to join: same track extends, or **two tracks link into one** if start is on one end and end is on another. Join curves from the **track** heading. Crossing the middle of a track still refuses (use the junction item for a turnout). Joins keep the direction (`+s`) of any track a train is on, because trains face `+s`: closing a loop never reverses the track, and linking two tracks reverses at most one track that has no train and is not a branch. Linking two occupied tracks start to start, or end to end, is refused. +- Right-click: **end location**. New track is a straight line in XZ from start to end (player look is ignored). Click within `join-distance` of an existing **end** to join: same track extends, or **two tracks link into one** if start is on one end and end is on another. Join curves from the **track** heading. Crossing the middle of a track still refuses (use the junction item for a turnout). Joins keep the direction (`+s`) of any track a train is on, because trains face `+s`: closing a loop never reverses the track, and linking two tracks reverses at most one track that has no train and is not a branch. Linking two occupied tracks start to start, or end to end, is refused. Trains saved in unloaded chunks count as occupying their track. - **Creative / spectator:** the spline is saved, then displays rebake in one step. One place sound + particles at the last sample (`build` in `trains.yml`). - **Survival / adventure:** same save, but displays grow along the new stroke one sample every `build.interval-ticks` (default 4, five per second). Prefix rebakes so collinear runs become medium then large. Each step plays `build.sound` and particles at the new sample, and swings the main hand if `build.swing` is true. Set `build.interval-ticks` to `0` to always place instantly. Connecting two tracks or closing a loop is still instant plus one burst. -- Remover item (`item-remover`, default `m.utils.train_track_remover`): left-click **digs** a sample (interior dig **splits** into two tracks). On a branch, digging any part of the **initial turnout lay** (stored as `turnoutS` on the junction) removes the whole turnout (junction, switch, and that stub). Digging past that initial lay uses normal dig/split rules; a longer branch extension is kept as plain track. The through stem stays. The remover refuses to dig track that a bound consist occupies, measured from each car out to its couplers. That includes a branch turnout the dig would drop because its frog ends up on a piece shorter than `min-lay-distance`. When a dig or lay rebuilds a spline, trains on it keep their world position on the new spline or pieces. +- Remover item (`item-remover`, default `m.utils.train_track_remover`): left-click **digs** a sample (interior dig **splits** into two tracks). On a branch, digging any part of the **initial turnout lay** (stored as `turnoutS` on the junction) removes the whole turnout (junction, switch, and that stub). Digging past that initial lay uses normal dig/split rules; a longer branch extension is kept as plain track. The through stem stays. The remover refuses to dig track that a bound consist occupies, measured from each car out to its couplers. That includes a branch turnout the dig would drop because its frog ends up on a piece shorter than `min-lay-distance`. When a dig or lay rebuilds a spline, trains on it keep their world position on the new spline or pieces. A train in an unloaded chunk checks its saved spline and `s` against where it respawns, and re-finds the track under it (or unbinds if the track is gone). - Junction item (`item-junction`, default `m.utils.train_track_junction`): right-click **existing track** (interior allowed) to start a junction (nothing is saved yet). Then layer **right-click** lays **one** turnout from that frog. The junction is saved only if that branch lays. Through stays the original spline. Layer **left-click** while a junction is pending cancels it and marks a normal start. The stem must be at least `min-lay-distance` (default 8) long; loops are exempt. After a split, a junction rehomed onto a piece shorter than that is dropped with its branch. - `min-junction-spacing` (default 16) along stem arc `s` (loop wrap). One branch per junction (no 3-way). Joining a branch tip into another track is not shipped. - `max-junction-length` (default 32): the turnout from frog to click cannot be longer than that (straight-line or along the laid curve).