1use crate::reflect::{AssetKind, Field};
23use glam::Vec3;
24use serde::{Deserialize, Serialize};
25
26pub trait Param {
28 fn field<'a>(&'a mut self, name: &'static str) -> Option<Field<'a>>;
30}
31
32impl Param for f32 {
33 fn field<'a>(&'a mut self, name: &'static str) -> Option<Field<'a>> {
34 Some(Field::f32(name, self))
35 }
36}
37impl Param for i32 {
38 fn field<'a>(&'a mut self, name: &'static str) -> Option<Field<'a>> {
39 Some(Field::i32(name, self))
40 }
41}
42impl Param for u32 {
43 fn field<'a>(&'a mut self, name: &'static str) -> Option<Field<'a>> {
44 Some(Field::u32(name, self))
45 }
46}
47impl Param for bool {
48 fn field<'a>(&'a mut self, name: &'static str) -> Option<Field<'a>> {
49 Some(Field::bool(name, self))
50 }
51}
52impl Param for Vec3 {
53 fn field<'a>(&'a mut self, name: &'static str) -> Option<Field<'a>> {
54 Some(Field::vec3(name, self))
55 }
56}
57impl Param for String {
58 fn field<'a>(&'a mut self, name: &'static str) -> Option<Field<'a>> {
59 Some(Field::text(name, self))
60 }
61}
62impl<T: crate::reflect::Choice + 'static> Param for T {
63 fn field<'a>(&'a mut self, name: &'static str) -> Option<Field<'a>> {
64 Some(Field::choice(name, self))
65 }
66}
67
68#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
70pub struct Color(pub [f32; 4]);
71
72impl Default for Color {
73 fn default() -> Self {
74 Color([1.0; 4])
75 }
76}
77impl Param for Color {
78 fn field<'a>(&'a mut self, name: &'static str) -> Option<Field<'a>> {
79 Some(Field::color(name, &mut self.0))
80 }
81}
82
83#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
85pub struct EntityRef(pub String);
86
87impl EntityRef {
88 pub fn resolve(&self, ctx: &crate::script::Ctx) -> Option<kvas_ecs::Entity> {
90 (!self.0.is_empty()).then(|| ctx.find(&self.0)).flatten()
91 }
92}
93impl Param for EntityRef {
94 fn field<'a>(&'a mut self, name: &'static str) -> Option<Field<'a>> {
95 Some(Field::entity(name, &mut self.0))
96 }
97}
98
99#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
101pub struct MeshRef(pub String);
102
103impl Param for MeshRef {
104 fn field<'a>(&'a mut self, name: &'static str) -> Option<Field<'a>> {
105 Some(Field::asset(name, &mut self.0, AssetKind::Mesh))
106 }
107}
108
109#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
111pub struct TextureRef(pub String);
112
113impl Param for TextureRef {
114 fn field<'a>(&'a mut self, name: &'static str) -> Option<Field<'a>> {
115 Some(Field::asset(name, &mut self.0, AssetKind::Texture))
116 }
117}
118
119#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
121pub struct SoundRef(pub String);
122
123impl Param for SoundRef {
124 fn field<'a>(&'a mut self, name: &'static str) -> Option<Field<'a>> {
125 Some(Field::asset(name, &mut self.0, AssetKind::Audio))
126 }
127}
128
129#[derive(Clone, Copy, Debug, Default, PartialEq)]
131pub struct Local<T>(pub T);
132
133impl<T> Param for Local<T> {
134 fn field<'a>(&'a mut self, _name: &'static str) -> Option<Field<'a>> {
135 None
136 }
137}
138impl<T> std::ops::Deref for Local<T> {
139 type Target = T;
140 fn deref(&self) -> &T {
141 &self.0
142 }
143}
144impl<T> std::ops::DerefMut for Local<T> {
145 fn deref_mut(&mut self) -> &mut T {
146 &mut self.0
147 }
148}
149
150#[macro_export]
161macro_rules! script_params {
162 ($(#[$meta:meta])* $vis:vis struct $name:ident { $($(#[$fmeta:meta])* $field:ident : $ty:ty = $default:expr),* $(,)? }) => {
163 $(#[$meta])*
164 $vis struct $name { $($(#[$fmeta])* pub $field: $ty),* }
165 impl Default for $name {
166 fn default() -> Self { Self { $($field: $default),* } }
167 }
168 impl $name {
169 pub fn params(&mut self) -> Vec<$crate::reflect::Field<'_>> {
171 let mut out = Vec::new();
172 $(if let Some(f) = $crate::params::Param::field(&mut self.$field, stringify!($field)) { out.push(f); })*
173 out
174 }
175 }
176 };
177}
178
179#[macro_export]
195macro_rules! fields {
196 ($s:ident; $($f:ident),* $(,)?) => {{
197 #[allow(unused_mut)]
198 let mut out: Vec<$crate::reflect::Field<'_>> = Vec::new();
199 $(if let Some(field) = $crate::params::Param::field(&mut $s.$f, stringify!($f)) { out.push(field); })*
200 out
201 }};
202}
203
204#[macro_export]
236macro_rules! script {
237 (
238 $(#[$meta:meta])* $vis:vis struct $name:ident { $($body:tt)* }
239 $( $phase:ident ($s:ident, $c:ident) $blk:block )*
240 ) => {
241 $crate::script_params! { $(#[$meta])* $vis struct $name { $($body)* } }
242 impl $crate::script::Script for $name {
243 $( $crate::script!(@phase $phase $s $c $blk); )*
244 fn fields(&mut self) -> Vec<$crate::reflect::Field<'_>> { self.params() }
245 }
246 };
247 (@phase start $s:ident $c:ident $blk:block) => { fn start(&mut $s, $c: &mut $crate::script::Ctx) $blk };
248 (@phase update $s:ident $c:ident $blk:block) => { fn update(&mut $s, $c: &mut $crate::script::Ctx) $blk };
249 (@phase fixed_update $s:ident $c:ident $blk:block) => { fn fixed_update(&mut $s, $c: &mut $crate::script::Ctx) $blk };
250}