1use crate::define_components;
47use crate::ecs::{BlobAssetDef, Component, PayloadLocator};
48use crate::result::CnResult;
49
50#[macro_export]
58macro_rules! for_each_component {
59 ($cb:ident) => { $crate::for_each_component!($cb;); };
60 ($cb:ident; $($extra:tt)*) => {
61 $cb! {
62 $($extra)*
63 stored: {
68 Window => $crate::components::Window { gen, external, singleton, consumed },
69 GraphicsConfig => $crate::components::GraphicsConfig { gen, external, singleton, renders, consumed },
70 Shader => $crate::components::Shader { manual, external, compiled, consumed },
71 Camera3D => $crate::components::Camera3D { manual, external, useful_blank, live, args: Camera3D },
72 FrameInput => $crate::components::FrameInput { gen, runtime },
73 Prop => $crate::components::Prop { gen, external, id, renders, validate: prop, refs: [("model", "Model"), ("material", "Material"), ("texture", "Texture"), ("scene", "Scene"), ("parent", "Prop")], consumed: PropInstance },
74 RigidBody => $crate::components::RigidBody { gen, external, validate: rigid_body },
75 PropBody => $crate::components::PropBody { gen, external, consumed },
76 Room => $crate::components::Room { manual, external, compiled, useful_blank, args: Room, refs: [("texture", "Texture"), ("wall_texture", "Texture"), ("floor_texture", "Texture"), ("ceiling_texture", "Texture")], consumed },
77 DirectionalLight => $crate::components::DirectionalLight { gen, external, useful_blank, validate: directional_light },
78 PointLight => $crate::components::PointLight { gen, external, useful_blank, validate: point_light },
79 SpotLight => $crate::components::SpotLight { gen, external, useful_blank, validate: spot_light },
80 RectAreaLight => $crate::components::RectAreaLight { gen, external, useful_blank, validate: rect_area_light },
81 ProceduralMesh => $crate::components::ProceduralMesh { gen, external, compiled, id },
82 Model => $crate::components::Model { gen, external, id, consumed },
83 Scene => $crate::components::Scene { gen, external, id, refs: [("camera_shot", "Camera3D")], consumed },
84 TextLabel => $crate::components::TextLabel { gen, external, id, useful_blank, renders, live, refs: [("font", "Font"), ("screen", "Screen")] },
85 HitRegion => $crate::components::HitRegion { gen, external, useful_blank, refs: [("label", "TextLabel"), ("screen", "Screen")], consumed },
86 File => $crate::components::File { manual, external, compiled, args: File, consumed },
87 BlockType => $crate::components::BlockType { gen, external, id, useful_blank, consumed },
88 VoxelChunk => $crate::components::VoxelChunk { gen, external, compiled, id, validate: voxel_chunk, consumed },
89 InstancedProp => $crate::components::InstancedProp { gen, external, id, renders, validate: instanced_prop, refs: [("material", "Material"), ("texture", "Texture")], consumed },
90 PostProcessConfig => $crate::components::PostProcessConfig { manual, external, singleton, consumed },
91 Animation => $crate::components::Animation { gen, external, id, consumed },
92 SkeletonPose => $crate::components::SkeletonPose { runtime, build: skeleton_pose },
93 StreamingConfig => $crate::components::StreamingConfig { gen, external, singleton, consumed },
94 VoxelWorld => $crate::components::VoxelWorld { gen, external, renders, refs: [("material", "Material")], consumed },
95 AudioEmitter => $crate::components::AudioEmitter { gen, external, useful_blank, refs: [("clip", "AudioClip"), ("prop", "Prop")] },
96 Sprite => $crate::components::Sprite { gen, external, id, useful_blank, renders, live, refs: [("texture", "Texture"), ("screen", "Screen")] },
97 KeyBinding => $crate::components::KeyBinding { gen, external, useful_blank, refs: [("screen", "Screen")], consumed },
98 Screen => $crate::components::Screen { gen, external, id, useful_blank, refs: [("focus", "TextInput")], consumed },
99 Decal => $crate::components::Decal { gen, external, id, useful_blank, validate: decal, refs: [("texture", "Texture")], consumed },
100 VolumetricFog => $crate::components::VolumetricFog { gen, external, useful_blank, validate: volumetric_fog, consumed },
101 PhysicsJoint => $crate::components::PhysicsJoint { gen, external, id, validate: joint, refs: [("body_a", "Prop"), ("body_b", "Prop")], consumed },
102 ParticleEmitter => $crate::components::ParticleEmitter { gen, external, id, useful_blank, validate: particle_emitter, refs: [("texture", "Texture")], consumed },
103 WaterSurface => $crate::components::WaterSurface { gen, external, id, useful_blank, renders, validate: water_surface, consumed },
104 SdfVolume => $crate::components::SdfVolume { manual, external, compiled, renders, validate: sdf_volume, consumed },
105 GlassPanel => $crate::components::GlassPanel { gen, external, id, useful_blank, validate: glass_panel, consumed },
106 LayoutContainer => $crate::components::LayoutContainer { gen, external, renders, live },
107 PhysicsConfig => $crate::components::PhysicsConfig { gen, external, singleton },
108 FpsCounter => $crate::components::FpsCounter { gen, external, useful_blank, refs: [("label", "TextLabel")] },
109 StatHud => $crate::components::StatHud { gen, external, renders, refs: [("fps_label", "TextLabel"), ("vram_label", "TextLabel"), ("ram_label", "TextLabel"), ("ev_label", "TextLabel"), ("edr_label", "TextLabel")] },
110 ScrollPanel => $crate::components::ScrollPanel { gen, external, refs: [("screen", "Screen")], consumed },
111 ReflectionProbe => $crate::components::ReflectionProbe { gen, external, useful_blank, validate: reflection_probe },
112 Transform => $crate::components::Transform { runtime },
113 PropInstance => $crate::components::PropInstance { runtime },
114 MeshRenderer => $crate::components::MeshRenderer { runtime },
115 ModelRenderer => $crate::components::ModelRenderer { runtime },
116 Collider => $crate::components::Collider { runtime },
117 BodyDynamics => $crate::components::BodyDynamics { runtime },
118 Interactable => $crate::components::Interactable { runtime },
119 Pickup => $crate::components::Pickup { runtime },
120 Parent => $crate::components::Parent { runtime },
121 Children => $crate::components::Children { runtime },
122 SceneMember => $crate::components::SceneMember { runtime },
123 GlobalTransform => $crate::components::GlobalTransform { runtime },
124 RenderHandle => $crate::components::RenderHandle { runtime },
125 Held => $crate::components::Held { runtime },
126 Lifetime => $crate::components::Lifetime { runtime },
127 Spawner => $crate::components::Spawner { manual, external, args: Spawner },
128 DebugHud => $crate::components::DebugHud { gen, external, renders, refs: [("passes_label", "TextLabel"), ("mouse_label", "TextLabel"), ("camera_label", "TextLabel"), ("sys_label", "TextLabel")] },
129 AudioCue => $crate::components::AudioCue { gen, external, useful_blank, refs: [("clip", "AudioClip"), ("screen", "Screen")] },
130 Story => $crate::components::Story { gen, external, id },
131 AppConfig => $crate::components::AppConfig { manual, external, singleton, args: AppConfig },
132 AnimationGraph => $crate::components::AnimationGraph { gen, external, id, consumed },
133 AnimationParams => $crate::components::AnimationParams { runtime, build: anim_params },
134 CharacterRig => $crate::components::CharacterRig { runtime, build: character_rig },
135 GroundProbes => $crate::components::GroundProbes { runtime },
136 CameraProbe => $crate::components::CameraProbe { runtime },
137 TextInput => $crate::components::TextInput { gen, external, id, useful_blank, renders, live, refs: [("font", "Font"), ("screen", "Screen")] },
138 Behavior => $crate::components::Behavior { gen, external, id, useful_blank, live },
139 Variables => $crate::components::Variables { gen, external, singleton, live },
140 TriggerVolume => $crate::components::TriggerVolume { gen, external, id, useful_blank },
141 Hidden => $crate::components::Hidden { runtime },
142 LoadingOverlay => $crate::components::LoadingOverlay { gen, external, singleton, renders, refs: [("screen", "Screen"), ("backdrop", "Sprite"), ("track", "Sprite"), ("fill", "Sprite"), ("label", "TextLabel")] },
143 AudioOcclusionProbe => $crate::components::AudioOcclusionProbe { runtime },
144 CharacterShape => $crate::components::CharacterShape { gen, external, id, refs: [("target", "SkinnedMesh")] },
145 },
146
147 resource: {
152 AudioClip => $crate::components::AudioClip { resource: AudioClip, compiled },
153 Texture => $crate::components::Texture { resource: Texture, compiled },
154 CubemapTexture => $crate::components::CubemapTexture { resource: CubemapTexture, compiled },
155 EnvironmentMap => $crate::components::EnvironmentMap { resource: EnvironmentMap, compiled, renders },
156 ColorLut => $crate::components::ColorLut { resource: ColorLut, compiled },
157 Font => $crate::components::Font { resource: Font, compiled, useful_blank },
158 Material => $crate::components::Material { resource: Material, data, useful_blank, refs: [("albedo", "Texture"), ("normal_map", "Texture"), ("emissive_map", "Texture"), ("orm_map", "Texture"), ("albedo_secondary", "Texture"), ("normal_secondary", "Texture"), ("shader", "Shader")] },
159 Mesh => $crate::components::Mesh { resource: Mesh, compiled },
160 SkinnedMesh => $crate::components::SkinnedMesh { resource: SkinnedMesh, compiled, renders },
161 },
162 }
163 };
164}
165
166crate::for_each_component!(define_components);
170
171macro_rules! cn_impl_components {
220 (
223 stored: { $( $variant:ident => $ty:path { $($meta:tt)* } ),+ $(,)? },
224 resource: { $( $rvariant:ident => $rty:path { $($rmeta:tt)* } ),+ $(,)? } $(,)?
225 ) => {
226 $( cn_impl_components!(@one $variant $ty { $($meta)* }); )+
227 };
228
229 (@one $variant:ident $ty:path { manual $($rest:tt)* }) => {};
231
232 (@one $variant:ident $ty:path { gen $($flags:tt)* }) => {
236 cn_impl_components!(@munch $variant $ty [] $($flags)*);
237 };
238
239 (@one $variant:ident $ty:path { runtime $($rest:tt)* }) => {
242 impl $crate::ecs::Component for $ty {
243 const NAME: &'static str = stringify!($variant);
244 }
245 };
246
247 (@munch $variant:ident $ty:path [$($body:tt)*] , compiled $($rest:tt)*) => {
248 cn_impl_components!(@munch $variant $ty
249 [$($body)*
250 fn inject_locator(&mut self, locator: $crate::ecs::PayloadLocator) {
251 self.locator = Some(locator);
252 }]
253 $($rest)*);
254 };
255 (@munch $variant:ident $ty:path [$($body:tt)*] , id $($rest:tt)*) => {
256 cn_impl_components!(@munch $variant $ty
257 [$($body)* fn inject_name(&mut self, id: $crate::ecs::asset_id::AssetId) {
258 self.asset_id = id;
259 }]
260 $($rest)*);
261 };
262 (@munch $variant:ident $ty:path [$($body:tt)*] , validate: $f:ident $($rest:tt)*) => {
264 cn_impl_components!(@munch $variant $ty [$($body)*] $($rest)*);
265 };
266 (@munch $variant:ident $ty:path [$($body:tt)*] , refs: [ $( ($fld:literal, $tgt:literal) ),+ $(,)? ] $($rest:tt)*) => {
267 cn_impl_components!(@munch $variant $ty [$($body)*] $($rest)*);
268 };
269 (@munch $variant:ident $ty:path [$($body:tt)*] , consumed: $surviving:ident $($rest:tt)*) => {
270 cn_impl_components!(@munch $variant $ty [$($body)*] $($rest)*);
271 };
272 (@munch $variant:ident $ty:path [$($body:tt)*] , $flag:ident $($rest:tt)*) => {
273 cn_impl_components!(@munch $variant $ty [$($body)*] $($rest)*);
274 };
275
276 (@munch $variant:ident $ty:path [$($body:tt)*]) => {
279 impl $crate::ecs::Component for $ty {
280 const NAME: &'static str = stringify!($variant);
281 $($body)*
282 fn from_baked(bytes: &[u8]) -> Result<Self, $crate::result::CnResult> {
283 Ok($crate::blob::decode_exact(bytes)?)
284 }
285 }
286 };
287}
288
289crate::for_each_component!(cn_impl_components);
295
296#[cfg(test)]
297mod tests {
298 use crate::ecs::ComponentTag;
299
300 #[test]
301 fn an_undrained_component_survives_as_itself() {
302 assert_eq!(
303 ComponentTag::Transform.surviving_tag(),
304 Some(ComponentTag::Transform)
305 );
306 assert_eq!(
307 ComponentTag::Behavior.surviving_tag(),
308 Some(ComponentTag::Behavior)
309 );
310 }
311
312 #[test]
313 fn a_consumed_component_survives_as_nothing() {
314 assert_eq!(ComponentTag::Screen.surviving_tag(), None);
315 assert_eq!(ComponentTag::PropBody.surviving_tag(), None);
316 }
317
318 #[test]
321 fn a_consumed_component_can_name_its_replacement() {
322 assert_eq!(
323 ComponentTag::Prop.surviving_tag(),
324 Some(ComponentTag::PropInstance)
325 );
326 }
327}