Skip to main content

sl_types/
lsl.rs

1//! LSL types and parsers/printers to use LSL format for them
2
3use crate::serde_helpers::impl_bitfield_serde;
4
5#[cfg(feature = "chumsky")]
6use chumsky::{Parser, prelude::just, text::whitespace};
7
8#[cfg(feature = "chumsky")]
9use crate::utils::f32_parser;
10
11/// LSL Vector of 3 float components
12#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
13pub struct Vector {
14    /// x component
15    pub x: f32,
16    /// y component
17    pub y: f32,
18    /// z component
19    pub z: f32,
20}
21
22/// parse an LSL vector
23///
24/// "<1.234,3.456,4.567>"
25///
26/// # Errors
27///
28/// returns an error if the string could not be parsed
29#[cfg(feature = "chumsky")]
30#[must_use]
31pub fn vector_parser<'src>()
32-> impl Parser<'src, &'src str, Vector, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
33    just('<')
34        .then(whitespace().or_not())
35        .ignore_then(f32_parser())
36        .then_ignore(whitespace().or_not())
37        .then_ignore(just(','))
38        .then_ignore(whitespace().or_not())
39        .then(f32_parser())
40        .then_ignore(whitespace().or_not())
41        .then_ignore(just(','))
42        .then_ignore(whitespace().or_not())
43        .then(f32_parser())
44        .then_ignore(whitespace().or_not())
45        .then_ignore(just('>'))
46        .map(|((x, y), z)| Vector { x, y, z })
47}
48
49impl From<crate::map::RegionCoordinates> for Vector {
50    fn from(value: crate::map::RegionCoordinates) -> Self {
51        Self {
52            x: value.x(),
53            y: value.y(),
54            z: value.z(),
55        }
56    }
57}
58
59/// LSL Rotation (quaternion) of 4 float components
60#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
61pub struct Rotation {
62    /// x component
63    pub x: f32,
64    /// y component
65    pub y: f32,
66    /// z component
67    pub z: f32,
68    /// s component
69    pub s: f32,
70}
71
72/// parse an LSL rotation
73///
74/// "<1.234,3.456,4.567,5.678>"
75///
76/// # Errors
77///
78/// returns an error if the string could not be parsed
79#[cfg(feature = "chumsky")]
80#[must_use]
81pub fn rotation_parser<'src>()
82-> impl Parser<'src, &'src str, Rotation, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
83    just('<')
84        .then(whitespace().or_not())
85        .ignore_then(f32_parser())
86        .then_ignore(whitespace().or_not())
87        .then_ignore(just(','))
88        .then_ignore(whitespace().or_not())
89        .then(f32_parser())
90        .then_ignore(whitespace().or_not())
91        .then_ignore(just(','))
92        .then_ignore(whitespace().or_not())
93        .then(f32_parser())
94        .then_ignore(whitespace().or_not())
95        .then_ignore(just(','))
96        .then_ignore(whitespace().or_not())
97        .then(f32_parser())
98        .then_ignore(whitespace().or_not())
99        .then_ignore(just('>'))
100        .map(|(((x, y), z), s)| Rotation { x, y, z, s })
101}
102
103/// The permissions an in-world script may request via `llRequestPermissions`, a
104/// bitfield shared by the `ScriptQuestion` (request) and `ScriptAnswerYes`
105/// (grant) messages. The flag values match the LSL `PERMISSION_*` constants.
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
107pub struct ScriptPermissions(pub i32);
108
109impl ScriptPermissions {
110    /// Debit the agent's account (`PERMISSION_DEBIT`).
111    pub const DEBIT: i32 = 1 << 1;
112    /// Take control inputs (`PERMISSION_TAKE_CONTROLS`).
113    pub const TAKE_CONTROLS: i32 = 1 << 2;
114    /// Trigger animations on the agent (`PERMISSION_TRIGGER_ANIMATION`).
115    pub const TRIGGER_ANIMATION: i32 = 1 << 4;
116    /// Attach to the agent (`PERMISSION_ATTACH`).
117    pub const ATTACH: i32 = 1 << 5;
118    /// Change link-set membership (`PERMISSION_CHANGE_LINKS`).
119    pub const CHANGE_LINKS: i32 = 1 << 7;
120    /// Track the agent's camera (`PERMISSION_TRACK_CAMERA`).
121    pub const TRACK_CAMERA: i32 = 1 << 10;
122    /// Control the agent's camera (`PERMISSION_CONTROL_CAMERA`).
123    pub const CONTROL_CAMERA: i32 = 1 << 11;
124    /// Teleport the agent (`PERMISSION_TELEPORT`).
125    pub const TELEPORT: i32 = 1 << 12;
126    /// Participate in an experience (`PERMISSION_EXPERIENCE`).
127    pub const EXPERIENCE: i32 = 1 << 13;
128    /// Silently manage estate access (`PERMISSION_SILENT_ESTATE_MANAGEMENT`).
129    pub const SILENT_ESTATE_MANAGEMENT: i32 = 1 << 14;
130    /// Override the agent's animations (`PERMISSION_OVERRIDE_ANIMATIONS`).
131    pub const OVERRIDE_ANIMATIONS: i32 = 1 << 15;
132    /// Return objects (`PERMISSION_RETURN_OBJECTS`).
133    pub const RETURN_OBJECTS: i32 = 1 << 16;
134
135    /// Whether all of the bits in `mask` are granted/requested.
136    #[must_use]
137    pub const fn contains(self, mask: i32) -> bool {
138        self.0 & mask == mask
139    }
140}
141
142impl_bitfield_serde!(
143    ScriptPermissions,
144    i32,
145    "DEBIT" => ScriptPermissions::DEBIT,
146    "TAKE_CONTROLS" => ScriptPermissions::TAKE_CONTROLS,
147    "TRIGGER_ANIMATION" => ScriptPermissions::TRIGGER_ANIMATION,
148    "ATTACH" => ScriptPermissions::ATTACH,
149    "CHANGE_LINKS" => ScriptPermissions::CHANGE_LINKS,
150    "TRACK_CAMERA" => ScriptPermissions::TRACK_CAMERA,
151    "CONTROL_CAMERA" => ScriptPermissions::CONTROL_CAMERA,
152    "TELEPORT" => ScriptPermissions::TELEPORT,
153    "EXPERIENCE" => ScriptPermissions::EXPERIENCE,
154    "SILENT_ESTATE_MANAGEMENT" => ScriptPermissions::SILENT_ESTATE_MANAGEMENT,
155    "OVERRIDE_ANIMATIONS" => ScriptPermissions::OVERRIDE_ANIMATIONS,
156    "RETURN_OBJECTS" => ScriptPermissions::RETURN_OBJECTS,
157);