engine_macros/
lib.rs

1extern crate proc_macro;
2use proc_macro::TokenStream;
3use quote::quote;
4use syn::{parse::Parser, parse_macro_input, DeriveInput};
5
6#[proc_macro_attribute]
7pub fn objectinit_without_implements(_args: TokenStream, input: TokenStream) -> TokenStream {
8    let mut ast = parse_macro_input!(input as DeriveInput);
9    match &mut ast.data {
10        syn::Data::Struct(ref mut struct_data) => {
11            if let syn::Fields::Named(fields) = &mut struct_data.fields {
12                fields.named.push(
13                    syn::Field::parse_named
14                        .parse2(quote! {
15                            pub transform: let_engine::Transform
16                        })
17                        .expect("transform failed"),
18                );
19                fields.named.push(
20                    syn::Field::parse_named
21                        .parse2(quote! {
22                            parent_transform: let_engine::Transform
23                        })
24                        .expect("public transform failed"),
25                );
26                fields.named.push(
27                    syn::Field::parse_named
28                        .parse2(quote! {
29                            pub appearance: let_engine::objects::Appearance
30                        })
31                        .expect("appearance failed"),
32                );
33                fields.named.push(
34                    syn::Field::parse_named
35                        .parse2(quote! {
36                            id: usize
37                        })
38                        .expect("id failed"),
39                );
40                fields.named.push(
41                    syn::Field::parse_named
42                        .parse2(quote! {
43                            reference: Option<let_engine::WeakObject>
44                        })
45                        .expect("weak object failed"),
46                );
47                fields.named.push(
48                    syn::Field::parse_named
49                        .parse2(quote! {
50                            physics: let_engine::physics::ObjectPhysics
51                        })
52                        .expect("collider failed"),
53                );
54            }
55        }
56        _ => panic!("`object` has to be used with structs."),
57    };
58
59    quote! {
60        #[derive(Clone)]
61        #ast
62    }
63    .into()
64}
65
66/// Implements GameObject on a struct and automaically adds the fields transform, appearance, id
67/// and layer to update from and to.
68/// Also adds 2 functions. Update and Sync.
69/// Update updates the object from the layer system and sync syncs the object to the layer.
70/// Those functions panic when the object isn't initialized to the layer yet.
71#[proc_macro_attribute]
72pub fn object(_args: TokenStream, input: TokenStream) -> TokenStream {
73    let ast = parse_macro_input!(input as DeriveInput);
74    let name = &ast.ident;
75
76    quote! {
77        #[let_engine::objectinit_without_implements]
78        #ast
79        impl let_engine::objects::GameObject for #name {
80            fn transform(&self) -> Transform {
81                self.transform
82            }
83            fn set_isometry(&mut self, position: let_engine::Vec2, rotation: f32) {
84                self.transform.position = position;
85                self.transform.rotation = rotation;
86            }
87            fn public_transform(&self) -> Transform {
88                self.transform.combine(self.parent_transform)
89            }
90            fn set_parent_transform(&mut self, transform: Transform) {
91                self.parent_transform = transform;
92            }
93            fn appearance(&self) -> &let_engine::objects::Appearance {
94                &self.appearance
95            }
96            fn id(&self) -> usize {
97                self.id
98            }
99            fn init_to_layer(&mut self, id: usize, parent: &let_engine::NObject, mut rigid_body_parent: let_engine::objects::RigidBodyParent, layer: &let_engine::Layer) -> let_engine::NObject {
100                self.id = id;
101                self.physics.physics = Some(layer.physics.clone());
102                self.parent_transform = self.physics.update(&self.transform, parent, &mut rigid_body_parent, id as u128);
103                let node: let_engine::NObject = std::sync::Arc::new(let_engine::Mutex::new(let_engine::objects::Node{
104                    object: Box::new(self.clone()),
105                    parent: Some(std::sync::Arc::downgrade(parent)),
106                    rigid_body_parent: rigid_body_parent.clone(),
107                    children: vec![],
108                }));
109                if let Some(value) = &rigid_body_parent {
110                    if value.is_none() && self.physics.rigid_body.is_some() {
111                        layer.rigid_body_roots.lock().insert(id, node.clone());
112                    }
113                }
114
115                self.reference = Some(std::sync::Arc::downgrade(&node));
116                node
117            }
118            fn remove_event(&mut self) {
119                self.physics.remove()
120            }
121            fn as_any(&self) -> &dyn std::any::Any {
122                self
123            }
124            fn as_node(&self) -> let_engine::NObject {
125                self.reference.as_ref().unwrap().upgrade().unwrap()
126            }
127            fn rigidbody_handle(&self) -> Option<let_engine::rapier2d::dynamics::RigidBodyHandle> {
128                self.physics.rigid_body_handle
129            }
130            fn collider_handle(&self) -> Option<let_engine::rapier2d::geometry::ColliderHandle> {
131                self.physics.collider_handle
132            }
133        }
134        impl #name {
135            pub fn update(&mut self) { // receive
136                if let Some(arc) = self.reference.clone().unwrap().upgrade() {
137                    let object = &arc.lock().object;
138                    self.transform = object.transform();
139                    self.appearance = object.appearance().clone();
140                } else {
141                    Self::remove_event(self);
142                }
143            }
144            pub fn sync(&mut self) { // send
145                // update public position of all children recursively
146                let node = self.reference.clone().unwrap().upgrade().unwrap();
147                {
148                    let mut node = node.lock();
149                    self.parent_transform = self.physics.update(
150                        &self.transform,
151                        &node.parent.clone().unwrap().upgrade().unwrap(),
152                        &mut node.rigid_body_parent, self.id as u128
153                    );
154                }
155                node.lock().update_children_position(Self::public_transform(self));
156                let arc = self.reference.clone().unwrap().upgrade().unwrap();
157                let mut object = arc.lock();
158                object.object = Box::new(self.clone());
159            }
160            pub fn collider(&self) -> Option<&let_engine::physics::Collider> {
161                self.physics.collider.as_ref()
162            }
163            pub fn set_collider(&mut self, collider: Option<let_engine::physics::Collider>) {
164                self.physics.collider = collider;
165            }
166            pub fn collider_mut(&mut self) -> &mut Option<let_engine::physics::Collider> {
167                &mut self.physics.collider
168            }
169            pub fn rigid_body(&self) -> Option<&let_engine::physics::RigidBody> {
170                self.physics.rigid_body.as_ref()
171            }
172            pub fn set_rigid_body(&mut self, rigid_body: Option<let_engine::physics::RigidBody>) {
173                self.physics.rigid_body = rigid_body;
174            }
175            pub fn rigid_body_mut(&mut self) -> &mut Option<let_engine::physics::RigidBody> {
176                &mut self.physics.rigid_body
177            }
178            pub fn local_collider_position(&self) -> let_engine::Vec2 {
179                self.physics.local_collider_position
180            }
181            pub fn set_local_collider_position(&mut self, pos: let_engine::Vec2) {
182                self.physics.local_collider_position = pos;
183            }
184        }
185    }
186    .into()
187}