From 5ca236eb644f0e1b643c261ce89676b3ada217a7 Mon Sep 17 00:00:00 2001
From: Aksiome <54895777+aksiome@users.noreply.github.com>
Date: Wed, 14 May 2025 00:48:57 +0200
Subject: [PATCH 1/2] =?UTF-8?q?=E2=9C=A8=20feat(bs.spline):=20add=20linear?=
=?UTF-8?q?=20spline=20type?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/changelog/v3.1.0.md | 10 +-
docs/modules/spline.md | 103 ++++++++-
.../evaluate/evaluate_linear.mcfunction | 29 +++
.../function/sample/sample_linear.mcfunction | 29 +++
.../function/stream/stream_linear.mcfunction | 32 +++
.../utils/bezier/next_segment_2d.mcfunction | 4 +-
.../utils/bezier/next_segment_3d.mcfunction | 5 +-
.../utils/bspline/next_segment_2d.mcfunction | 4 +-
.../utils/bspline/next_segment_3d.mcfunction | 5 +-
.../catmull_rom/next_segment_2d.mcfunction | 4 +-
.../catmull_rom/next_segment_3d.mcfunction | 5 +-
.../utils/hermite/next_segment_2d.mcfunction | 4 +-
.../utils/hermite/next_segment_3d.mcfunction | 5 +-
.../utils/linear/get_segment.mcfunction | 19 ++
.../utils/linear/next_segment_1d.mcfunction | 26 +++
.../utils/linear/next_segment_2d.mcfunction | 35 +++
.../utils/linear/next_segment_3d.mcfunction | 42 ++++
.../tags/function/evaluate_linear.json | 20 ++
.../tags/function/sample_linear.json | 20 ++
.../tags/function/stream_linear.json | 20 ++
.../bs.spline/test/evaluate_linear.mcfunction | 86 +++++++
.../bs.spline/test/sample_linear.mcfunction | 218 ++++++++++++++++++
.../bs.spline/test/stream_linear.mcfunction | 74 ++++++
23 files changed, 777 insertions(+), 22 deletions(-)
create mode 100644 modules/bs.spline/data/bs.spline/function/evaluate/evaluate_linear.mcfunction
create mode 100644 modules/bs.spline/data/bs.spline/function/sample/sample_linear.mcfunction
create mode 100644 modules/bs.spline/data/bs.spline/function/stream/stream_linear.mcfunction
create mode 100644 modules/bs.spline/data/bs.spline/function/utils/linear/get_segment.mcfunction
create mode 100644 modules/bs.spline/data/bs.spline/function/utils/linear/next_segment_1d.mcfunction
create mode 100644 modules/bs.spline/data/bs.spline/function/utils/linear/next_segment_2d.mcfunction
create mode 100644 modules/bs.spline/data/bs.spline/function/utils/linear/next_segment_3d.mcfunction
create mode 100644 modules/bs.spline/data/bs.spline/tags/function/evaluate_linear.json
create mode 100644 modules/bs.spline/data/bs.spline/tags/function/sample_linear.json
create mode 100644 modules/bs.spline/data/bs.spline/tags/function/stream_linear.json
create mode 100644 modules/bs.spline/data/bs.spline/test/evaluate_linear.mcfunction
create mode 100644 modules/bs.spline/data/bs.spline/test/sample_linear.mcfunction
create mode 100644 modules/bs.spline/data/bs.spline/test/stream_linear.mcfunction
diff --git a/docs/changelog/v3.1.0.md b/docs/changelog/v3.1.0.md
index 110a456a8..d3d38258d 100644
--- a/docs/changelog/v3.1.0.md
+++ b/docs/changelog/v3.1.0.md
@@ -5,10 +5,16 @@
> *[Update Description]*
+### `🔬 bs.dump`
+
+- 🐛 **[#441](https://github.com/mcbookshelf/bookshelf/issues/441)** - Fixed `#bs.dump:var` incorrectly appending `undefined` to output.
+
+
### `🔦 bs.raycast`
- ✨ **[#445](https://github.com/mcbookshelf/bookshelf/issues/445)** - `#bs.raycast:run` now computes all lambda data before invoking callbacks.
-### `🔬 bs.dump`
-- 🐛 **[#441](https://github.com/mcbookshelf/bookshelf/issues/441)** - Fixed `#bs.dump:var` incorrectly appending `undefined` to output.
+### `🧣 bs.spline`
+
+- ✨ **[#417](https://github.com/mcbookshelf/bookshelf/issues/417)** - Added full support for **linear splines**.
diff --git a/docs/modules/spline.md b/docs/modules/spline.md
index 6e4d767ce..709d02218 100644
--- a/docs/modules/spline.md
+++ b/docs/modules/spline.md
@@ -145,6 +145,33 @@ function #bs.spline:evaluate_hermite
data get storage bs:out spline.evaluate_hermite
```
+::::
+::::{tab-item} Linear
+
+```{function} #bs.spline:evaluate_linear
+
+Evaluate a linear spline, which connects each pair of consecutive points with a straight segment. There is no curvature; the interpolation is piecewise linear.
+
+:Inputs:
+ **Storage `bs:in spline.evaluate_linear`**:
+ :::{treeview}
+ - {nbt}`compound` Arguments
+ - {nbt}`list` **points**: A list of coordinates (1D, 2D, or 3D). Each pair of consecutive points defines one linear segment.
+ - {nbt}`double` **time**: A normalized position between 0 and the number of segments. Each integer step moves to the next segment, and the fractional part represents interpolation within that segment.
+ :::
+
+:Outputs:
+ **Storage `bs:out spline.evaluate_linear`**: {nbt}`list` The interpolated point (1D, 2D, or 3D) on the spline at the given time.
+```
+
+*Example: Evaluate the midpoint between two positions in 2D space:*
+
+```mcfunction
+data modify storage bs:in spline.evaluate_linear set value {points:[[0,0],[4,2],[6,5]],time:0.5}
+function #bs.spline:evaluate_linear
+data get storage bs:out spline.evaluate_linear
+```
+
::::
:::::
@@ -164,7 +191,7 @@ Sample a Bézier spline composed of one or more segments. Each segment is define
:::{treeview}
- {nbt}`compound` Arguments
- {nbt}`list` **points**: A list of coordinates (1D, 2D, or 3D). Every group of 4 consecutive points defines one segment.
- - {nbt}`double` **step**: The interval at which the curve is sampled. Smaller values generate more points.
+ - {nbt}`double` **step**: The interval at which the spline is sampled. Smaller values generate more points.
:::
:Outputs:
@@ -191,7 +218,7 @@ Sample a B-Spline composed of one or more segments. Each segment is defined by f
:::{treeview}
- {nbt}`compound` Arguments
- {nbt}`list` **points**: A list of coordinates (1D, 2D, or 3D). Every group of 4 consecutive points defines one segment.
- - {nbt}`double` **step**: The interval at which the curve is sampled. Smaller values generate more points.
+ - {nbt}`double` **step**: The interval at which the spline is sampled. Smaller values generate more points.
:::
:Outputs:
@@ -218,7 +245,7 @@ Sample a Catmull-Rom spline composed of one or more segments. Each segment is de
:::{treeview}
- {nbt}`compound` Arguments
- {nbt}`list` **points**: A list of coordinates (1D, 2D, or 3D). Every group of 4 consecutive points defines one segment.
- - {nbt}`double` **step**: The interval at which the curve is sampled. Smaller values generate more points.
+ - {nbt}`double` **step**: The interval at which the spline is sampled. Smaller values generate more points.
:::
:Outputs:
@@ -245,7 +272,7 @@ Sample a Hermite spline composed of one or more segments. Each segment is define
:::{treeview}
- {nbt}`compound` Arguments
- {nbt}`list` **points**: A list of coordinates (1D, 2D, or 3D). Every group of 4 consecutive points defines one segment.
- - {nbt}`double` **step**: The interval at which the curve is sampled. Smaller values generate more points.
+ - {nbt}`double` **step**: The interval at which the spline is sampled. Smaller values generate more points.
:::
:Outputs:
@@ -260,6 +287,33 @@ function #bs.spline:sample_hermite
data get storage bs:out spline.sample_hermite
```
+::::
+::::{tab-item} Linear
+
+```{function} #bs.spline:sample_linear
+
+Sample a linear spline, which connects each pair of consecutive points with a straight segment.
+
+:Inputs:
+ **Storage `bs:in spline.sample_linear`**:
+ :::{treeview}
+ - {nbt}`compound` Arguments
+ - {nbt}`list` **points**: A list of coordinates (1D, 2D, or 3D). Each pair of consecutive points defines one linear segment.
+ - {nbt}`double` **step**: The interval at which the spline is sampled. Smaller values generate more points.
+ :::
+
+:Outputs:
+ **Storage `bs:out spline.sample_linear`**: {nbt}`list` The sampled points along the spline.
+```
+
+*Example: Sample evenly spaced points along a polyline in 2D space:*
+
+```mcfunction
+data modify storage bs:in spline.sample_linear set value {points:[[0,0],[4,2],[6,5]],step:0.25}
+function #bs.spline:sample_linear
+data get storage bs:out spline.sample_linear
+```
+
::::
:::::
@@ -279,8 +333,8 @@ Stream a Bézier spline composed of one or more segments. Each segment is define
:::{treeview}
- {nbt}`compound` Arguments
- {nbt}`list` **points**: A list of coordinates (1D, 2D, or 3D). Every group of 4 consecutive points defines one segment.
- - {nbt}`double` **step**: The interval at which the curve is sampled. Smaller values generate more points.
- - {nbt}`string` **run**: The command executed at each step of the curve sampling process. For each step, the following storage can be used:
+ - {nbt}`double` **step**: The interval at which the spline is sampled. Smaller values generate more points.
+ - {nbt}`string` **run**: The command executed at each step of the sampling process. For each step, the following storage can be used:
- **`bs:lambda spline.point`**: The evaluated point.
:::
```
@@ -304,8 +358,8 @@ Stream a B-Spline composed of one or more segments. Each segment is defined by f
:::{treeview}
- {nbt}`compound` Arguments
- {nbt}`list` **points**: A list of coordinates (1D, 2D, or 3D). Every group of 4 consecutive points defines one segment.
- - {nbt}`double` **step**: The interval at which the curve is sampled. Smaller values generate more points.
- - {nbt}`string` **run**: The command executed at each step of the curve sampling process. For each step, the following storage can be used:
+ - {nbt}`double` **step**: The interval at which the spline is sampled. Smaller values generate more points.
+ - {nbt}`string` **run**: The command executed at each step of the sampling process. For each step, the following storage can be used:
- **`bs:lambda spline.point`**: The evaluated point.
:::
```
@@ -329,8 +383,8 @@ Stream a Catmull-Rom spline composed of one or more segments. Each segment is de
:::{treeview}
- {nbt}`compound` Arguments
- {nbt}`list` **points**: A list of coordinates (1D, 2D, or 3D). Every group of 4 consecutive points defines one segment.
- - {nbt}`double` **step**: The interval at which the curve is sampled. Smaller values generate more points.
- - {nbt}`string` **run**: The command executed at each step of the curve sampling process. For each step, the following storage can be used:
+ - {nbt}`double` **step**: The interval at which the spline is sampled. Smaller values generate more points.
+ - {nbt}`string` **run**: The command executed at each step of the sampling process. For each step, the following storage can be used:
- **`bs:lambda spline.point`**: The evaluated point.
:::
```
@@ -354,8 +408,8 @@ Stream a Hermite spline composed of one or more segments. Each segment is define
:::{treeview}
- {nbt}`compound` Arguments
- {nbt}`list` **points**: A list of coordinates (1D, 2D, or 3D). Every group of 4 consecutive points defines one segment.
- - {nbt}`double` **step**: The interval at which the curve is sampled. Smaller values generate more points.
- - {nbt}`string` **run**: The command executed at each step of the curve sampling process. For each step, the following storage can be used:
+ - {nbt}`double` **step**: The interval at which the spline is sampled. Smaller values generate more points.
+ - {nbt}`string` **run**: The command executed at each step of the sampling process. For each step, the following storage can be used:
- **`bs:lambda spline.point`**: The evaluated point.
:::
```
@@ -367,6 +421,31 @@ data modify storage bs:in spline.stream_hermite set value {points:[[0,0],[1,2],[
function #bs.spline:stream_hermite
```
+::::
+::::{tab-item} Linear
+
+```{function} #bs.spline:stream_linear
+
+Stream a linear spline composed of one or more segments. Each segment connects two consecutive control points with a straight line. This function processes each step over multiple ticks.
+
+:Inputs:
+ **Storage `bs:in spline.stream_linear`**:
+ :::{treeview}
+ - {nbt}`compound` Arguments
+ - {nbt}`list` **points**: A list of coordinates (1D, 2D, or 3D). Every pair of consecutive points defines one linear segment.
+ - {nbt}`double` **step**: The interval at which the spline is sampled. Smaller values generate more points.
+ - {nbt}`string` **run**: The command executed at each step of the sampling process. For each step, the following storage can be used:
+ - **`bs:lambda spline.point`**: The evaluated point.
+ :::
+```
+
+*Example: Stream 10 points along a linear path in 2D space and execute a command at each step:*
+
+```mcfunction
+data modify storage bs:in spline.stream_linear set value {points:[[0,0],[1,2],[3,0]],step:0.1,run:'tellraw @a {"storage":"bs:lambda","nbt":"spline.point"}'}
+function #bs.spline:stream_linear
+```
+
::::
:::::
diff --git a/modules/bs.spline/data/bs.spline/function/evaluate/evaluate_linear.mcfunction b/modules/bs.spline/data/bs.spline/function/evaluate/evaluate_linear.mcfunction
new file mode 100644
index 000000000..c5b7c27fc
--- /dev/null
+++ b/modules/bs.spline/data/bs.spline/function/evaluate/evaluate_linear.mcfunction
@@ -0,0 +1,29 @@
+# ------------------------------------------------------------------------------------------------------------
+# Copyright (c) 2025 Gunivers
+#
+# This file is part of the Bookshelf project (https://github.com/mcbookshelf/bookshelf).
+#
+# This source code is subject to the terms of the Mozilla Public License, v. 2.0.
+# If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# Conditions:
+# - You may use this file in compliance with the MPL v2.0
+# - Any modifications must be documented and disclosed under the same license
+#
+# For more details, refer to the MPL v2.0.
+# ------------------------------------------------------------------------------------------------------------
+
+data modify storage bs:ctx _ set from storage bs:in spline.evaluate_linear
+data modify storage bs:out spline.evaluate_linear set value []
+
+execute store result score #s bs.ctx store result score #t bs.ctx run data get storage bs:ctx _.time 1000
+scoreboard players operation #s bs.ctx /= 1000 bs.const
+execute if score #s bs.ctx matches 1.. run function bs.spline:utils/linear/get_segment
+
+execute store result score #m bs.ctx if data storage bs:ctx _.points[]
+execute store result score #n bs.ctx if data storage bs:ctx _.points[][2]
+execute if score #n bs.ctx = #m bs.ctx run return run function bs.spline:evaluate/evaluate_3d {type:"linear"}
+execute store result score #n bs.ctx if data storage bs:ctx _.points[][1]
+execute if score #n bs.ctx = #m bs.ctx run return run function bs.spline:evaluate/evaluate_2d {type:"linear"}
+execute store result score #n bs.ctx if data storage bs:ctx _.points[][0]
+execute if score #n bs.ctx = #m bs.ctx run return run function bs.spline:evaluate/evaluate_1d {type:"linear"}
diff --git a/modules/bs.spline/data/bs.spline/function/sample/sample_linear.mcfunction b/modules/bs.spline/data/bs.spline/function/sample/sample_linear.mcfunction
new file mode 100644
index 000000000..3bf7ba86e
--- /dev/null
+++ b/modules/bs.spline/data/bs.spline/function/sample/sample_linear.mcfunction
@@ -0,0 +1,29 @@
+# ------------------------------------------------------------------------------------------------------------
+# Copyright (c) 2025 Gunivers
+#
+# This file is part of the Bookshelf project (https://github.com/mcbookshelf/bookshelf).
+#
+# This source code is subject to the terms of the Mozilla Public License, v. 2.0.
+# If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# Conditions:
+# - You may use this file in compliance with the MPL v2.0
+# - Any modifications must be documented and disclosed under the same license
+#
+# For more details, refer to the MPL v2.0.
+# ------------------------------------------------------------------------------------------------------------
+
+data modify storage bs:ctx _ set from storage bs:in spline.sample_linear
+data modify storage bs:out spline.sample_linear set value []
+
+scoreboard players set #t bs.ctx 1000
+execute store result score #s bs.ctx run data get storage bs:ctx _.step 1000
+scoreboard players operation #t bs.ctx -= #s bs.ctx
+
+execute store result score #m bs.ctx if data storage bs:ctx _.points[]
+execute store result score #n bs.ctx if data storage bs:ctx _.points[][2]
+execute if score #n bs.ctx = #m bs.ctx run return run function bs.spline:sample/sample_3d {type:"linear"}
+execute store result score #n bs.ctx if data storage bs:ctx _.points[][1]
+execute if score #n bs.ctx = #m bs.ctx run return run function bs.spline:sample/sample_2d {type:"linear"}
+execute store result score #n bs.ctx if data storage bs:ctx _.points[][0]
+execute if score #n bs.ctx = #m bs.ctx run return run function bs.spline:sample/sample_1d {type:"linear"}
diff --git a/modules/bs.spline/data/bs.spline/function/stream/stream_linear.mcfunction b/modules/bs.spline/data/bs.spline/function/stream/stream_linear.mcfunction
new file mode 100644
index 000000000..473b0aa86
--- /dev/null
+++ b/modules/bs.spline/data/bs.spline/function/stream/stream_linear.mcfunction
@@ -0,0 +1,32 @@
+# ------------------------------------------------------------------------------------------------------------
+# Copyright (c) 2025 Gunivers
+#
+# This file is part of the Bookshelf project (https://github.com/mcbookshelf/bookshelf).
+#
+# This source code is subject to the terms of the Mozilla Public License, v. 2.0.
+# If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# Conditions:
+# - You may use this file in compliance with the MPL v2.0
+# - Any modifications must be documented and disclosed under the same license
+#
+# For more details, refer to the MPL v2.0.
+# ------------------------------------------------------------------------------------------------------------
+
+data modify storage bs:ctx _ set from storage bs:in spline.stream_linear
+data modify storage bs:ctx _.type set value "linear"
+
+scoreboard players set #t bs.ctx 1000
+execute store result score #s bs.ctx run data get storage bs:ctx _.step 1000
+scoreboard players operation #t bs.ctx -= #s bs.ctx
+
+execute store result score #m bs.ctx if data storage bs:ctx _.points[]
+execute store result score #n bs.ctx if data storage bs:ctx _.points[][2]
+execute if score #n bs.ctx = #m bs.ctx run data modify storage bs:ctx _.coeffs set value [0,0,0,0]
+execute if score #n bs.ctx = #m bs.ctx run return run function bs.spline:stream/stream_3d with storage bs:ctx _
+execute store result score #n bs.ctx if data storage bs:ctx _.points[][1]
+execute if score #n bs.ctx = #m bs.ctx run data modify storage bs:ctx _.coeffs set value [0,0,0,0,0,0,0,0]
+execute if score #n bs.ctx = #m bs.ctx run return run function bs.spline:stream/stream_2d with storage bs:ctx _
+execute store result score #n bs.ctx if data storage bs:ctx _.points[][0]
+execute if score #n bs.ctx = #m bs.ctx run data modify storage bs:ctx _.coeffs set value [0,0,0,0,0,0,0,0,0,0,0,0]
+execute if score #n bs.ctx = #m bs.ctx run return run function bs.spline:stream/stream_1d with storage bs:ctx _
diff --git a/modules/bs.spline/data/bs.spline/function/utils/bezier/next_segment_2d.mcfunction b/modules/bs.spline/data/bs.spline/function/utils/bezier/next_segment_2d.mcfunction
index 868303cc0..5dd95ad78 100644
--- a/modules/bs.spline/data/bs.spline/function/utils/bezier/next_segment_2d.mcfunction
+++ b/modules/bs.spline/data/bs.spline/function/utils/bezier/next_segment_2d.mcfunction
@@ -14,7 +14,9 @@
# ------------------------------------------------------------------------------------------------------------
data modify storage bs:lambda spline.point set value [0d, 0d]
-execute store result score #x bs.ctx store result score #y bs.ctx run scoreboard players operation #t bs.ctx %= 1000 bs.const
+execute store result score #x bs.ctx \
+ store result score #y bs.ctx \
+ run scoreboard players operation #t bs.ctx %= 1000 bs.const
execute store result score #a bs.ctx run data get storage bs:ctx _.points[0][0] 1000
execute store result score #b bs.ctx run data get storage bs:ctx _.points[1][0] 1000
diff --git a/modules/bs.spline/data/bs.spline/function/utils/bezier/next_segment_3d.mcfunction b/modules/bs.spline/data/bs.spline/function/utils/bezier/next_segment_3d.mcfunction
index 874b6d609..8b0919ae9 100644
--- a/modules/bs.spline/data/bs.spline/function/utils/bezier/next_segment_3d.mcfunction
+++ b/modules/bs.spline/data/bs.spline/function/utils/bezier/next_segment_3d.mcfunction
@@ -14,7 +14,10 @@
# ------------------------------------------------------------------------------------------------------------
data modify storage bs:lambda spline.point set value [0d, 0d, 0d]
-execute store result score #x bs.ctx store result score #y bs.ctx store result score #z bs.ctx run scoreboard players operation #t bs.ctx %= 1000 bs.const
+execute store result score #x bs.ctx \
+ store result score #y bs.ctx \
+ store result score #z bs.ctx \
+ run scoreboard players operation #t bs.ctx %= 1000 bs.const
execute store result score #a bs.ctx run data get storage bs:ctx _.points[0][0] 1000
execute store result score #b bs.ctx run data get storage bs:ctx _.points[1][0] 1000
diff --git a/modules/bs.spline/data/bs.spline/function/utils/bspline/next_segment_2d.mcfunction b/modules/bs.spline/data/bs.spline/function/utils/bspline/next_segment_2d.mcfunction
index 19965f015..e8e007527 100644
--- a/modules/bs.spline/data/bs.spline/function/utils/bspline/next_segment_2d.mcfunction
+++ b/modules/bs.spline/data/bs.spline/function/utils/bspline/next_segment_2d.mcfunction
@@ -14,7 +14,9 @@
# ------------------------------------------------------------------------------------------------------------
data modify storage bs:lambda spline.point set value [0d, 0d]
-execute store result score #x bs.ctx store result score #y bs.ctx run scoreboard players operation #t bs.ctx %= 1000 bs.const
+execute store result score #x bs.ctx \
+ store result score #y bs.ctx \
+ run scoreboard players operation #t bs.ctx %= 1000 bs.const
execute store result score #a bs.ctx run data get storage bs:ctx _.points[0][0] 1000
execute store result score #c bs.ctx run data get storage bs:ctx _.points[1][0] 1000
diff --git a/modules/bs.spline/data/bs.spline/function/utils/bspline/next_segment_3d.mcfunction b/modules/bs.spline/data/bs.spline/function/utils/bspline/next_segment_3d.mcfunction
index 55f7776bc..e14ef251f 100644
--- a/modules/bs.spline/data/bs.spline/function/utils/bspline/next_segment_3d.mcfunction
+++ b/modules/bs.spline/data/bs.spline/function/utils/bspline/next_segment_3d.mcfunction
@@ -14,7 +14,10 @@
# ------------------------------------------------------------------------------------------------------------
data modify storage bs:lambda spline.point set value [0d, 0d, 0d]
-execute store result score #x bs.ctx store result score #y bs.ctx store result score #z bs.ctx run scoreboard players operation #t bs.ctx %= 1000 bs.const
+execute store result score #x bs.ctx \
+ store result score #y bs.ctx \
+ store result score #z bs.ctx \
+ run scoreboard players operation #t bs.ctx %= 1000 bs.const
execute store result score #a bs.ctx run data get storage bs:ctx _.points[0][0] 1000
execute store result score #c bs.ctx run data get storage bs:ctx _.points[1][0] 1000
diff --git a/modules/bs.spline/data/bs.spline/function/utils/catmull_rom/next_segment_2d.mcfunction b/modules/bs.spline/data/bs.spline/function/utils/catmull_rom/next_segment_2d.mcfunction
index 43a49b898..a1564d8b3 100644
--- a/modules/bs.spline/data/bs.spline/function/utils/catmull_rom/next_segment_2d.mcfunction
+++ b/modules/bs.spline/data/bs.spline/function/utils/catmull_rom/next_segment_2d.mcfunction
@@ -14,7 +14,9 @@
# ------------------------------------------------------------------------------------------------------------
data modify storage bs:lambda spline.point set value [0d, 0d]
-execute store result score #x bs.ctx store result score #y bs.ctx run scoreboard players operation #t bs.ctx %= 1000 bs.const
+execute store result score #x bs.ctx \
+ store result score #y bs.ctx \
+ run scoreboard players operation #t bs.ctx %= 1000 bs.const
execute store result score #a bs.ctx run data get storage bs:ctx _.points[0][0] 1000
execute store result score #c bs.ctx run data get storage bs:ctx _.points[1][0] 1000
diff --git a/modules/bs.spline/data/bs.spline/function/utils/catmull_rom/next_segment_3d.mcfunction b/modules/bs.spline/data/bs.spline/function/utils/catmull_rom/next_segment_3d.mcfunction
index 13493818a..05a7839bb 100644
--- a/modules/bs.spline/data/bs.spline/function/utils/catmull_rom/next_segment_3d.mcfunction
+++ b/modules/bs.spline/data/bs.spline/function/utils/catmull_rom/next_segment_3d.mcfunction
@@ -14,7 +14,10 @@
# ------------------------------------------------------------------------------------------------------------
data modify storage bs:lambda spline.point set value [0d, 0d, 0d]
-execute store result score #x bs.ctx store result score #y bs.ctx store result score #z bs.ctx run scoreboard players operation #t bs.ctx %= 1000 bs.const
+execute store result score #x bs.ctx \
+ store result score #y bs.ctx \
+ store result score #z bs.ctx \
+ run scoreboard players operation #t bs.ctx %= 1000 bs.const
execute store result score #a bs.ctx run data get storage bs:ctx _.points[0][0] 1000
execute store result score #c bs.ctx run data get storage bs:ctx _.points[1][0] 1000
diff --git a/modules/bs.spline/data/bs.spline/function/utils/hermite/next_segment_2d.mcfunction b/modules/bs.spline/data/bs.spline/function/utils/hermite/next_segment_2d.mcfunction
index f6182184b..a8572b2ea 100644
--- a/modules/bs.spline/data/bs.spline/function/utils/hermite/next_segment_2d.mcfunction
+++ b/modules/bs.spline/data/bs.spline/function/utils/hermite/next_segment_2d.mcfunction
@@ -14,7 +14,9 @@
# ------------------------------------------------------------------------------------------------------------
data modify storage bs:lambda spline.point set value [0d, 0d]
-execute store result score #x bs.ctx store result score #y bs.ctx run scoreboard players operation #t bs.ctx %= 1000 bs.const
+execute store result score #x bs.ctx \
+ store result score #y bs.ctx \
+ run scoreboard players operation #t bs.ctx %= 1000 bs.const
execute store result score #a bs.ctx run data get storage bs:ctx _.points[0][0] 1000
execute store result score #b bs.ctx run data get storage bs:ctx _.points[1][0] 1000
diff --git a/modules/bs.spline/data/bs.spline/function/utils/hermite/next_segment_3d.mcfunction b/modules/bs.spline/data/bs.spline/function/utils/hermite/next_segment_3d.mcfunction
index da2f58e36..f2b918b77 100644
--- a/modules/bs.spline/data/bs.spline/function/utils/hermite/next_segment_3d.mcfunction
+++ b/modules/bs.spline/data/bs.spline/function/utils/hermite/next_segment_3d.mcfunction
@@ -14,7 +14,10 @@
# ------------------------------------------------------------------------------------------------------------
data modify storage bs:lambda spline.point set value [0d, 0d, 0d]
-execute store result score #x bs.ctx store result score #y bs.ctx store result score #z bs.ctx run scoreboard players operation #t bs.ctx %= 1000 bs.const
+execute store result score #x bs.ctx \
+ store result score #y bs.ctx \
+ store result score #z bs.ctx \
+ run scoreboard players operation #t bs.ctx %= 1000 bs.const
execute store result score #a bs.ctx run data get storage bs:ctx _.points[0][0] 1000
execute store result score #b bs.ctx run data get storage bs:ctx _.points[1][0] 1000
diff --git a/modules/bs.spline/data/bs.spline/function/utils/linear/get_segment.mcfunction b/modules/bs.spline/data/bs.spline/function/utils/linear/get_segment.mcfunction
new file mode 100644
index 000000000..45d148385
--- /dev/null
+++ b/modules/bs.spline/data/bs.spline/function/utils/linear/get_segment.mcfunction
@@ -0,0 +1,19 @@
+# ------------------------------------------------------------------------------------------------------------
+# Copyright (c) 2025 Gunivers
+#
+# This file is part of the Bookshelf project (https://github.com/mcbookshelf/bookshelf).
+#
+# This source code is subject to the terms of the Mozilla Public License, v. 2.0.
+# If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# Conditions:
+# - You may use this file in compliance with the MPL v2.0
+# - Any modifications must be documented and disclosed under the same license
+#
+# For more details, refer to the MPL v2.0.
+# ------------------------------------------------------------------------------------------------------------
+
+data remove storage bs:ctx _.points[0]
+
+scoreboard players remove #s bs.ctx 1
+execute if score #s bs.ctx matches 1.. run function bs.spline:utils/linear/get_segment
diff --git a/modules/bs.spline/data/bs.spline/function/utils/linear/next_segment_1d.mcfunction b/modules/bs.spline/data/bs.spline/function/utils/linear/next_segment_1d.mcfunction
new file mode 100644
index 000000000..373203e2b
--- /dev/null
+++ b/modules/bs.spline/data/bs.spline/function/utils/linear/next_segment_1d.mcfunction
@@ -0,0 +1,26 @@
+# ------------------------------------------------------------------------------------------------------------
+# Copyright (c) 2025 Gunivers
+#
+# This file is part of the Bookshelf project (https://github.com/mcbookshelf/bookshelf).
+#
+# This source code is subject to the terms of the Mozilla Public License, v. 2.0.
+# If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# Conditions:
+# - You may use this file in compliance with the MPL v2.0
+# - Any modifications must be documented and disclosed under the same license
+#
+# For more details, refer to the MPL v2.0.
+# ------------------------------------------------------------------------------------------------------------
+
+data modify storage bs:lambda spline.point set value [0d]
+execute store result score #x bs.ctx run scoreboard players operation #t bs.ctx %= 1000 bs.const
+
+execute store result score #a bs.ctx run data get storage bs:ctx _.points[0][0] 1000
+execute store result score #b bs.ctx run data get storage bs:ctx _.points[1][0] 1000
+
+# Compute Lerp coefficients
+execute store result score #c bs.ctx run scoreboard players set #d bs.ctx 0
+scoreboard players operation #b bs.ctx -= #a bs.ctx
+
+data remove storage bs:ctx _.points[0]
diff --git a/modules/bs.spline/data/bs.spline/function/utils/linear/next_segment_2d.mcfunction b/modules/bs.spline/data/bs.spline/function/utils/linear/next_segment_2d.mcfunction
new file mode 100644
index 000000000..978934af2
--- /dev/null
+++ b/modules/bs.spline/data/bs.spline/function/utils/linear/next_segment_2d.mcfunction
@@ -0,0 +1,35 @@
+# ------------------------------------------------------------------------------------------------------------
+# Copyright (c) 2025 Gunivers
+#
+# This file is part of the Bookshelf project (https://github.com/mcbookshelf/bookshelf).
+#
+# This source code is subject to the terms of the Mozilla Public License, v. 2.0.
+# If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# Conditions:
+# - You may use this file in compliance with the MPL v2.0
+# - Any modifications must be documented and disclosed under the same license
+#
+# For more details, refer to the MPL v2.0.
+# ------------------------------------------------------------------------------------------------------------
+
+data modify storage bs:lambda spline.point set value [0d,0d]
+execute store result score #x bs.ctx \
+ store result score #y bs.ctx \
+ run scoreboard players operation #t bs.ctx %= 1000 bs.const
+
+execute store result score #a bs.ctx run data get storage bs:ctx _.points[0][0] 1000
+execute store result score #b bs.ctx run data get storage bs:ctx _.points[1][0] 1000
+
+execute store result score #e bs.ctx run data get storage bs:ctx _.points[0][1] 1000
+execute store result score #f bs.ctx run data get storage bs:ctx _.points[1][1] 1000
+
+# Compute Lerp coefficients
+execute store result score #c bs.ctx \
+ store result score #d bs.ctx \
+ store result score #g bs.ctx \
+ run scoreboard players set #h bs.ctx 0
+scoreboard players operation #b bs.ctx -= #a bs.ctx
+scoreboard players operation #f bs.ctx -= #e bs.ctx
+
+data remove storage bs:ctx _.points[0]
diff --git a/modules/bs.spline/data/bs.spline/function/utils/linear/next_segment_3d.mcfunction b/modules/bs.spline/data/bs.spline/function/utils/linear/next_segment_3d.mcfunction
new file mode 100644
index 000000000..420e34092
--- /dev/null
+++ b/modules/bs.spline/data/bs.spline/function/utils/linear/next_segment_3d.mcfunction
@@ -0,0 +1,42 @@
+# ------------------------------------------------------------------------------------------------------------
+# Copyright (c) 2025 Gunivers
+#
+# This file is part of the Bookshelf project (https://github.com/mcbookshelf/bookshelf).
+#
+# This source code is subject to the terms of the Mozilla Public License, v. 2.0.
+# If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# Conditions:
+# - You may use this file in compliance with the MPL v2.0
+# - Any modifications must be documented and disclosed under the same license
+#
+# For more details, refer to the MPL v2.0.
+# ------------------------------------------------------------------------------------------------------------
+
+data modify storage bs:lambda spline.point set value [0d,0d,0d]
+execute store result score #x bs.ctx \
+ store result score #y bs.ctx \
+ store result score #z bs.ctx \
+ run scoreboard players operation #t bs.ctx %= 1000 bs.const
+
+execute store result score #a bs.ctx run data get storage bs:ctx _.points[0][0] 1000
+execute store result score #b bs.ctx run data get storage bs:ctx _.points[1][0] 1000
+
+execute store result score #e bs.ctx run data get storage bs:ctx _.points[0][1] 1000
+execute store result score #f bs.ctx run data get storage bs:ctx _.points[1][1] 1000
+
+execute store result score #i bs.ctx run data get storage bs:ctx _.points[0][2] 1000
+execute store result score #j bs.ctx run data get storage bs:ctx _.points[1][2] 1000
+
+# Compute Lerp coefficients
+execute store result score #c bs.ctx \
+ store result score #d bs.ctx \
+ store result score #g bs.ctx \
+ store result score #h bs.ctx \
+ store result score #k bs.ctx \
+ run scoreboard players set #l bs.ctx 0
+scoreboard players operation #b bs.ctx -= #a bs.ctx
+scoreboard players operation #f bs.ctx -= #e bs.ctx
+scoreboard players operation #j bs.ctx -= #i bs.ctx
+
+data remove storage bs:ctx _.points[0]
diff --git a/modules/bs.spline/data/bs.spline/tags/function/evaluate_linear.json b/modules/bs.spline/data/bs.spline/tags/function/evaluate_linear.json
new file mode 100644
index 000000000..5e43a038f
--- /dev/null
+++ b/modules/bs.spline/data/bs.spline/tags/function/evaluate_linear.json
@@ -0,0 +1,20 @@
+{
+ "__bookshelf__": {
+ "feature": true,
+ "documentation": "https://docs.mcbookshelf.dev/en/latest/modules/spline.html#evaluate",
+ "authors": [
+ "Aksiome"
+ ],
+ "created": {
+ "date": "2025/05/14",
+ "minecraft_version": "1.21.5"
+ },
+ "updated": {
+ "date": "2025/05/14",
+ "minecraft_version": "1.21.5"
+ }
+ },
+ "values": [
+ "bs.spline:evaluate/evaluate_linear"
+ ]
+}
diff --git a/modules/bs.spline/data/bs.spline/tags/function/sample_linear.json b/modules/bs.spline/data/bs.spline/tags/function/sample_linear.json
new file mode 100644
index 000000000..774869c42
--- /dev/null
+++ b/modules/bs.spline/data/bs.spline/tags/function/sample_linear.json
@@ -0,0 +1,20 @@
+{
+ "__bookshelf__": {
+ "feature": true,
+ "documentation": "https://docs.mcbookshelf.dev/en/latest/modules/spline.html#sample",
+ "authors": [
+ "Aksiome"
+ ],
+ "created": {
+ "date": "2025/05/14",
+ "minecraft_version": "1.21.5"
+ },
+ "updated": {
+ "date": "2025/05/14",
+ "minecraft_version": "1.21.5"
+ }
+ },
+ "values": [
+ "bs.spline:sample/sample_linear"
+ ]
+}
diff --git a/modules/bs.spline/data/bs.spline/tags/function/stream_linear.json b/modules/bs.spline/data/bs.spline/tags/function/stream_linear.json
new file mode 100644
index 000000000..e4d250e09
--- /dev/null
+++ b/modules/bs.spline/data/bs.spline/tags/function/stream_linear.json
@@ -0,0 +1,20 @@
+{
+ "__bookshelf__": {
+ "feature": true,
+ "documentation": "https://docs.mcbookshelf.dev/en/latest/modules/spline.html#stream",
+ "authors": [
+ "Aksiome"
+ ],
+ "created": {
+ "date": "2025/05/14",
+ "minecraft_version": "1.21.5"
+ },
+ "updated": {
+ "date": "2025/05/14",
+ "minecraft_version": "1.21.5"
+ }
+ },
+ "values": [
+ "bs.spline:stream/stream_linear"
+ ]
+}
diff --git a/modules/bs.spline/data/bs.spline/test/evaluate_linear.mcfunction b/modules/bs.spline/data/bs.spline/test/evaluate_linear.mcfunction
new file mode 100644
index 000000000..1d0285f53
--- /dev/null
+++ b/modules/bs.spline/data/bs.spline/test/evaluate_linear.mcfunction
@@ -0,0 +1,86 @@
+# ------------------------------------------------------------------------------------------------------------
+# Copyright (c) 2025 Gunivers
+#
+# This file is part of the Bookshelf project (https://github.com/mcbookshelf/bookshelf).
+#
+# This source code is subject to the terms of the Mozilla Public License, v. 2.0.
+# If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# Conditions:
+# - You may use this file in compliance with the MPL v2.0
+# - Any modifications must be documented and disclosed under the same license
+#
+# For more details, refer to the MPL v2.0.
+# ------------------------------------------------------------------------------------------------------------
+
+data modify storage bs:in spline.evaluate_linear set value {points:[[-39.51, 99.914, 53.16], [-65.788, -99.526, -13.28], [-59.734, 82.879, -69.759], [-28.352, -50.677, 79.867]],time:0.124}
+function #bs.spline:evaluate_linear
+execute store result score #x bs.ctx run data get storage bs:out spline.evaluate_linear[0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.evaluate_linear[1] 1000
+execute store result score #z bs.ctx run data get storage bs:out spline.evaluate_linear[2] 1000
+assert score #x bs.ctx matches -42770..-42766
+assert score #y bs.ctx matches 75181..75185
+assert score #z bs.ctx matches 44919..44923
+
+data modify storage bs:in spline.evaluate_linear set value {points:[[-2.476, -97.226, -9.416], [51.826, -45.883, -54.268], [-24.309, -47.473, 46.058], [-82.18, -26.204, 42.502]],time:0.177}
+function #bs.spline:evaluate_linear
+execute store result score #x bs.ctx run data get storage bs:out spline.evaluate_linear[0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.evaluate_linear[1] 1000
+execute store result score #z bs.ctx run data get storage bs:out spline.evaluate_linear[2] 1000
+assert score #x bs.ctx matches 7133..7137
+assert score #y bs.ctx matches -88140..-88136
+assert score #z bs.ctx matches -17357..-17353
+
+data modify storage bs:in spline.evaluate_linear set value {points:[[-9.712, 47.595, -86.768], [-25.875, -29.768, -52.993], [27.22, -60.536, 8.376], [57.077, -84.618, 15.88]],time:0.797}
+function #bs.spline:evaluate_linear
+execute store result score #x bs.ctx run data get storage bs:out spline.evaluate_linear[0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.evaluate_linear[1] 1000
+execute store result score #z bs.ctx run data get storage bs:out spline.evaluate_linear[2] 1000
+assert score #x bs.ctx matches -22596..-22592
+assert score #y bs.ctx matches -14065..-14061
+assert score #z bs.ctx matches -59851..-59847
+
+data modify storage bs:in spline.evaluate_linear set value {points:[[-75.69, -26.617, -81.958], [37.627, -11.579, 51.195], [58.928, -41.345, -88.421], [-8.079, 99.256, 79.53]],time:0.015}
+function #bs.spline:evaluate_linear
+execute store result score #x bs.ctx run data get storage bs:out spline.evaluate_linear[0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.evaluate_linear[1] 1000
+execute store result score #z bs.ctx run data get storage bs:out spline.evaluate_linear[2] 1000
+assert score #x bs.ctx matches -73992..-73988
+assert score #y bs.ctx matches -26393..-26389
+assert score #z bs.ctx matches -79963..-79959
+
+data modify storage bs:in spline.evaluate_linear set value {points:[[-65.211, 94.008, 34.896], [-30.85, -91.129, 42.052], [-8.961, -88.462, -93.511], [25.096, -83.628, 1.18]],time:0.47}
+function #bs.spline:evaluate_linear
+execute store result score #x bs.ctx run data get storage bs:out spline.evaluate_linear[0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.evaluate_linear[1] 1000
+execute store result score #z bs.ctx run data get storage bs:out spline.evaluate_linear[2] 1000
+assert score #x bs.ctx matches -49063..-49059
+assert score #y bs.ctx matches 6992..6996
+assert score #z bs.ctx matches 38257..38261
+
+data modify storage bs:in spline.evaluate_linear set value {points:[[68.583, -25.938, -33.139], [-5.84, -98.794, 28.603], [35.048, -45.817, -34.14], [-21.087, 50.688, -37.148]],time:0.865}
+function #bs.spline:evaluate_linear
+execute store result score #x bs.ctx run data get storage bs:out spline.evaluate_linear[0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.evaluate_linear[1] 1000
+execute store result score #z bs.ctx run data get storage bs:out spline.evaluate_linear[2] 1000
+assert score #x bs.ctx matches 4205..4209
+assert score #y bs.ctx matches -88960..-88956
+assert score #z bs.ctx matches 20266..20270
+
+data modify storage bs:in spline.evaluate_linear set value {points:[[27.959, -82.031, -77.959], [2.009, 95.36, 35.831], [91.374, 30.945, 30.083], [29.334, -20.517, 99.017]],time:0.891}
+function #bs.spline:evaluate_linear
+execute store result score #x bs.ctx run data get storage bs:out spline.evaluate_linear[0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.evaluate_linear[1] 1000
+execute store result score #z bs.ctx run data get storage bs:out spline.evaluate_linear[2] 1000
+assert score #x bs.ctx matches 4836..4840
+assert score #y bs.ctx matches 76022..76026
+assert score #z bs.ctx matches 23426..23430
+
+data modify storage bs:in spline.evaluate_linear set value {points:[[37.603, 77.412, 34.733], [93.945, -9.934, 25.572], [75.079, -66.74, -68.449], [-64.827, 19.624, 93.37]],time:0.626}
+function #bs.spline:evaluate_linear
+execute store result score #x bs.ctx run data get storage bs:out spline.evaluate_linear[0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.evaluate_linear[1] 1000
+execute store result score #z bs.ctx run data get storage bs:out spline.evaluate_linear[2] 1000
+assert score #x bs.ctx matches 72871..72875
+assert score #y bs.ctx matches 22731..22735
+assert score #z bs.ctx matches 28996..29000
diff --git a/modules/bs.spline/data/bs.spline/test/sample_linear.mcfunction b/modules/bs.spline/data/bs.spline/test/sample_linear.mcfunction
new file mode 100644
index 000000000..640e6e91e
--- /dev/null
+++ b/modules/bs.spline/data/bs.spline/test/sample_linear.mcfunction
@@ -0,0 +1,218 @@
+# ------------------------------------------------------------------------------------------------------------
+# Copyright (c) 2025 Gunivers
+#
+# This file is part of the Bookshelf project (https://github.com/mcbookshelf/bookshelf).
+#
+# This source code is subject to the terms of the Mozilla Public License, v. 2.0.
+# If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# Conditions:
+# - You may use this file in compliance with the MPL v2.0
+# - Any modifications must be documented and disclosed under the same license
+#
+# For more details, refer to the MPL v2.0.
+# ------------------------------------------------------------------------------------------------------------
+
+data modify storage bs:in spline.sample_linear set value {points:[[-20.703, -91.215], [-40.79, 39.149], [-98.795, -1.819], [79.645, 99.66], [-58.935, 14.929], [-96.406, 49.072]],step:.25}
+function #bs.spline:sample_linear
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[0][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[0][1] 1000
+assert score #x bs.ctx matches -20705..-20701
+assert score #y bs.ctx matches -91217..-91213
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[1][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[1][1] 1000
+assert score #x bs.ctx matches -25727..-25723
+assert score #y bs.ctx matches -58626..-58622
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[2][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[2][1] 1000
+assert score #x bs.ctx matches -30748..-30744
+assert score #y bs.ctx matches -26035..-26031
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[3][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[3][1] 1000
+assert score #x bs.ctx matches -35770..-35766
+assert score #y bs.ctx matches 6556..6560
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[4][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[4][1] 1000
+assert score #x bs.ctx matches -40792..-40788
+assert score #y bs.ctx matches 39147..39151
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[5][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[5][1] 1000
+assert score #x bs.ctx matches -55293..-55289
+assert score #y bs.ctx matches 28905..28909
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[6][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[6][1] 1000
+assert score #x bs.ctx matches -69795..-69791
+assert score #y bs.ctx matches 18663..18667
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[7][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[7][1] 1000
+assert score #x bs.ctx matches -84296..-84292
+assert score #y bs.ctx matches 8421..8425
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[8][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[8][1] 1000
+assert score #x bs.ctx matches -98797..-98793
+assert score #y bs.ctx matches -1821..-1817
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[9][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[9][1] 1000
+assert score #x bs.ctx matches -54187..-54183
+assert score #y bs.ctx matches 23549..23553
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[10][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[10][1] 1000
+assert score #x bs.ctx matches -9577..-9573
+assert score #y bs.ctx matches 48918..48922
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[11][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[11][1] 1000
+assert score #x bs.ctx matches 35033..35037
+assert score #y bs.ctx matches 74288..74292
+
+data modify storage bs:in spline.sample_linear set value {points:[[32.583, 43.741], [52.832, -27.932], [58.595, -61.35], [38.229, -18.474], [53.707, 29.533], [74.161, 38.678]],step:.25}
+function #bs.spline:sample_linear
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[0][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[0][1] 1000
+assert score #x bs.ctx matches 32581..32585
+assert score #y bs.ctx matches 43739..43743
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[1][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[1][1] 1000
+assert score #x bs.ctx matches 37643..37647
+assert score #y bs.ctx matches 25821..25825
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[2][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[2][1] 1000
+assert score #x bs.ctx matches 42705..42709
+assert score #y bs.ctx matches 7903..7907
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[3][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[3][1] 1000
+assert score #x bs.ctx matches 47768..47772
+assert score #y bs.ctx matches -10016..-10012
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[4][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[4][1] 1000
+assert score #x bs.ctx matches 52830..52834
+assert score #y bs.ctx matches -27934..-27930
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[5][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[5][1] 1000
+assert score #x bs.ctx matches 54271..54275
+assert score #y bs.ctx matches -36288..-36284
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[6][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[6][1] 1000
+assert score #x bs.ctx matches 55711..55715
+assert score #y bs.ctx matches -44643..-44639
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[7][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[7][1] 1000
+assert score #x bs.ctx matches 57152..57156
+assert score #y bs.ctx matches -52997..-52993
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[8][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[8][1] 1000
+assert score #x bs.ctx matches 58593..58597
+assert score #y bs.ctx matches -61352..-61348
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[9][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[9][1] 1000
+assert score #x bs.ctx matches 53502..53506
+assert score #y bs.ctx matches -50633..-50629
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[10][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[10][1] 1000
+assert score #x bs.ctx matches 48410..48414
+assert score #y bs.ctx matches -39914..-39910
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[11][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[11][1] 1000
+assert score #x bs.ctx matches 43318..43322
+assert score #y bs.ctx matches -29195..-29191
+
+data modify storage bs:in spline.sample_linear set value {points:[[-70.04, -20.427], [76.424, 90.853], [21.805, -94.0], [-72.353, -82.029], [-42.101, -12.821], [-47.571, 99.002]],step:.25}
+function #bs.spline:sample_linear
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[0][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[0][1] 1000
+assert score #x bs.ctx matches -70042..-70038
+assert score #y bs.ctx matches -20429..-20425
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[1][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[1][1] 1000
+assert score #x bs.ctx matches -33426..-33422
+assert score #y bs.ctx matches 7391..7395
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[2][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[2][1] 1000
+assert score #x bs.ctx matches 3190..3194
+assert score #y bs.ctx matches 35211..35215
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[3][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[3][1] 1000
+assert score #x bs.ctx matches 39806..39810
+assert score #y bs.ctx matches 63031..63035
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[4][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[4][1] 1000
+assert score #x bs.ctx matches 76422..76426
+assert score #y bs.ctx matches 90851..90855
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[5][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[5][1] 1000
+assert score #x bs.ctx matches 62767..62771
+assert score #y bs.ctx matches 44638..44642
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[6][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[6][1] 1000
+assert score #x bs.ctx matches 49113..49117
+assert score #y bs.ctx matches -1576..-1572
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[7][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[7][1] 1000
+assert score #x bs.ctx matches 35458..35462
+assert score #y bs.ctx matches -47789..-47785
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[8][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[8][1] 1000
+assert score #x bs.ctx matches 21803..21807
+assert score #y bs.ctx matches -94002..-93998
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[9][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[9][1] 1000
+assert score #x bs.ctx matches -1737..-1733
+assert score #y bs.ctx matches -91009..-91005
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[10][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[10][1] 1000
+assert score #x bs.ctx matches -25276..-25272
+assert score #y bs.ctx matches -88016..-88012
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[11][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[11][1] 1000
+assert score #x bs.ctx matches -48815..-48811
+assert score #y bs.ctx matches -85024..-85020
+
+data modify storage bs:in spline.sample_linear set value {points:[[51.069, 87.558], [59.058, 50.079], [22.561, -34.019], [-86.042, -70.912], [8.413, -31.279], [24.203, 41.355]],step:.25}
+function #bs.spline:sample_linear
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[0][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[0][1] 1000
+assert score #x bs.ctx matches 51067..51071
+assert score #y bs.ctx matches 87556..87560
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[1][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[1][1] 1000
+assert score #x bs.ctx matches 53064..53068
+assert score #y bs.ctx matches 78186..78190
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[2][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[2][1] 1000
+assert score #x bs.ctx matches 55062..55066
+assert score #y bs.ctx matches 68817..68821
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[3][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[3][1] 1000
+assert score #x bs.ctx matches 57059..57063
+assert score #y bs.ctx matches 59447..59451
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[4][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[4][1] 1000
+assert score #x bs.ctx matches 59056..59060
+assert score #y bs.ctx matches 50077..50081
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[5][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[5][1] 1000
+assert score #x bs.ctx matches 49932..49936
+assert score #y bs.ctx matches 29052..29056
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[6][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[6][1] 1000
+assert score #x bs.ctx matches 40807..40811
+assert score #y bs.ctx matches 8027..8031
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[7][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[7][1] 1000
+assert score #x bs.ctx matches 31683..31687
+assert score #y bs.ctx matches -12996..-12992
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[8][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[8][1] 1000
+assert score #x bs.ctx matches 22559..22563
+assert score #y bs.ctx matches -34021..-34017
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[9][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[9][1] 1000
+assert score #x bs.ctx matches -4592..-4588
+assert score #y bs.ctx matches -43244..-43240
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[10][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[10][1] 1000
+assert score #x bs.ctx matches -31743..-31739
+assert score #y bs.ctx matches -52468..-52464
+execute store result score #x bs.ctx run data get storage bs:out spline.sample_linear[11][0] 1000
+execute store result score #y bs.ctx run data get storage bs:out spline.sample_linear[11][1] 1000
+assert score #x bs.ctx matches -58893..-58889
+assert score #y bs.ctx matches -61691..-61687
diff --git a/modules/bs.spline/data/bs.spline/test/stream_linear.mcfunction b/modules/bs.spline/data/bs.spline/test/stream_linear.mcfunction
new file mode 100644
index 000000000..99ccdaf7f
--- /dev/null
+++ b/modules/bs.spline/data/bs.spline/test/stream_linear.mcfunction
@@ -0,0 +1,74 @@
+# ------------------------------------------------------------------------------------------------------------
+# Copyright (c) 2025 Gunivers
+#
+# This file is part of the Bookshelf project (https://github.com/mcbookshelf/bookshelf).
+#
+# This source code is subject to the terms of the Mozilla Public License, v. 2.0.
+# If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# Conditions:
+# - You may use this file in compliance with the MPL v2.0
+# - Any modifications must be documented and disclosed under the same license
+#
+# For more details, refer to the MPL v2.0.
+# ------------------------------------------------------------------------------------------------------------
+
+data modify storage bs:in spline.stream_linear set value {points:[[-92.64], [-40.062], [55.003], [-81.721], [-25.817], [-89.297]],step:.25,run:"execute store result score #packtest.spline.linear bs.ctx run data get storage bs:lambda spline.point[0] 1000"}
+function #bs.spline:stream_linear
+await score #packtest.spline.linear bs.ctx matches -92642..-92638
+await score #packtest.spline.linear bs.ctx matches -79498..-79494
+await score #packtest.spline.linear bs.ctx matches -66353..-66349
+await score #packtest.spline.linear bs.ctx matches -53208..-53204
+await score #packtest.spline.linear bs.ctx matches -40064..-40060
+await score #packtest.spline.linear bs.ctx matches -16298..-16294
+await score #packtest.spline.linear bs.ctx matches 7469..7473
+await score #packtest.spline.linear bs.ctx matches 31235..31239
+await score #packtest.spline.linear bs.ctx matches 55001..55005
+await score #packtest.spline.linear bs.ctx matches 20820..20824
+await score #packtest.spline.linear bs.ctx matches -13361..-13357
+await score #packtest.spline.linear bs.ctx matches -47542..-47538
+
+data modify storage bs:in spline.stream_linear set value {points:[[91.374], [71.764], [84.778], [-56.856], [-6.578], [-95.789]],step:.25,run:"execute store result score #packtest.spline.linear bs.ctx run data get storage bs:lambda spline.point[0] 1000"}
+function #bs.spline:stream_linear
+await score #packtest.spline.linear bs.ctx matches 91372..91376
+await score #packtest.spline.linear bs.ctx matches 86469..86473
+await score #packtest.spline.linear bs.ctx matches 81567..81571
+await score #packtest.spline.linear bs.ctx matches 76664..76668
+await score #packtest.spline.linear bs.ctx matches 71762..71766
+await score #packtest.spline.linear bs.ctx matches 75015..75019
+await score #packtest.spline.linear bs.ctx matches 78269..78273
+await score #packtest.spline.linear bs.ctx matches 81523..81527
+await score #packtest.spline.linear bs.ctx matches 84776..84780
+await score #packtest.spline.linear bs.ctx matches 49368..49372
+await score #packtest.spline.linear bs.ctx matches 13959..13963
+await score #packtest.spline.linear bs.ctx matches -21450..-21446
+
+data modify storage bs:in spline.stream_linear set value {points:[[68.362], [88.245], [-78.759], [78.669], [-73.135], [42.038]],step:.25,run:"execute store result score #packtest.spline.linear bs.ctx run data get storage bs:lambda spline.point[0] 1000"}
+function #bs.spline:stream_linear
+await score #packtest.spline.linear bs.ctx matches 68360..68364
+await score #packtest.spline.linear bs.ctx matches 73331..73335
+await score #packtest.spline.linear bs.ctx matches 78301..78305
+await score #packtest.spline.linear bs.ctx matches 83272..83276
+await score #packtest.spline.linear bs.ctx matches 88243..88247
+await score #packtest.spline.linear bs.ctx matches 46492..46496
+await score #packtest.spline.linear bs.ctx matches 4741..4745
+await score #packtest.spline.linear bs.ctx matches -37010..-37006
+await score #packtest.spline.linear bs.ctx matches -78761..-78757
+await score #packtest.spline.linear bs.ctx matches -39404..-39400
+await score #packtest.spline.linear bs.ctx matches -47..-43
+await score #packtest.spline.linear bs.ctx matches 39310..39314
+
+data modify storage bs:in spline.stream_linear set value {points:[[-5.661], [52.884], [34.418], [27.569], [-43.304], [63.433]],step:.25,run:"execute store result score #packtest.spline.linear bs.ctx run data get storage bs:lambda spline.point[0] 1000"}
+function #bs.spline:stream_linear
+await score #packtest.spline.linear bs.ctx matches -5663..-5659
+await score #packtest.spline.linear bs.ctx matches 8973..8977
+await score #packtest.spline.linear bs.ctx matches 23609..23613
+await score #packtest.spline.linear bs.ctx matches 38246..38250
+await score #packtest.spline.linear bs.ctx matches 52882..52886
+await score #packtest.spline.linear bs.ctx matches 48265..48269
+await score #packtest.spline.linear bs.ctx matches 43649..43653
+await score #packtest.spline.linear bs.ctx matches 39032..39036
+await score #packtest.spline.linear bs.ctx matches 34416..34420
+await score #packtest.spline.linear bs.ctx matches 32704..32708
+await score #packtest.spline.linear bs.ctx matches 30991..30995
+await score #packtest.spline.linear bs.ctx matches 29279..29283
From fac854b99f86ac59badf4dd20fb06361f82cc6b6 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 13 May 2025 22:50:01 +0000
Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8F=20chore:=20update=20g?=
=?UTF-8?q?enerated=20metadata?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
data/manifest.json | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/data/manifest.json b/data/manifest.json
index 3b41b09d4..e8e72cdaf 100644
--- a/data/manifest.json
+++ b/data/manifest.json
@@ -3561,6 +3561,21 @@
"minecraft_version": "1.21.5"
}
},
+ {
+ "id": "#bs.spline:evaluate_linear",
+ "documentation": "https://docs.mcbookshelf.dev/en/latest/modules/spline.html#evaluate",
+ "authors": [
+ "Aksiome"
+ ],
+ "created": {
+ "date": "2025/05/14",
+ "minecraft_version": "1.21.5"
+ },
+ "updated": {
+ "date": "2025/05/14",
+ "minecraft_version": "1.21.5"
+ }
+ },
{
"id": "#bs.spline:sample_bezier",
"documentation": "https://docs.mcbookshelf.dev/en/latest/modules/spline.html#sample",
@@ -3621,6 +3636,21 @@
"minecraft_version": "1.21.5"
}
},
+ {
+ "id": "#bs.spline:sample_linear",
+ "documentation": "https://docs.mcbookshelf.dev/en/latest/modules/spline.html#sample",
+ "authors": [
+ "Aksiome"
+ ],
+ "created": {
+ "date": "2025/05/14",
+ "minecraft_version": "1.21.5"
+ },
+ "updated": {
+ "date": "2025/05/14",
+ "minecraft_version": "1.21.5"
+ }
+ },
{
"id": "#bs.spline:stream_bezier",
"documentation": "https://docs.mcbookshelf.dev/en/latest/modules/spline.html#stream",
@@ -3680,6 +3710,21 @@
"date": "2025/04/21",
"minecraft_version": "1.21.5"
}
+ },
+ {
+ "id": "#bs.spline:stream_linear",
+ "documentation": "https://docs.mcbookshelf.dev/en/latest/modules/spline.html#stream",
+ "authors": [
+ "Aksiome"
+ ],
+ "created": {
+ "date": "2025/05/14",
+ "minecraft_version": "1.21.5"
+ },
+ "updated": {
+ "date": "2025/05/14",
+ "minecraft_version": "1.21.5"
+ }
}
]
},