Skip to main content

gizmo_core/
component.rs

1use std::any::Any;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum StorageType {
5    Table,
6    SparseSet,
7}
8
9pub trait Component: 'static + Any + Send + Sync + Clone {
10    fn storage_type() -> StorageType {
11        StorageType::Table
12    }
13}
14
15#[macro_export]
16macro_rules! impl_component {
17    ($($t:ty),+ $(,)?) => {
18        $(
19            impl $crate::Component for $t {}
20        )+
21    };
22    ($($t:ty),+ ; $storage:expr) => {
23        $(
24            impl $crate::Component for $t {
25                fn storage_type() -> $crate::component::StorageType {
26                    $storage
27                }
28            }
29        )+
30    };
31}
32
33// --- Hiyerarşi (Scene Graph) Bileşenleri ---
34#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
35pub struct Parent(pub u32);
36
37#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
38pub struct Children(pub Vec<u32>);
39
40#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
41pub struct EntityName(pub String);
42
43impl EntityName {
44    pub fn new(name: &str) -> Self {
45        Self(name.to_string())
46    }
47}
48
49#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
50pub struct IsHidden;
51
52#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
53pub struct IsDeleted;
54
55#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
56pub struct PrefabRequest(pub String);
57
58impl PrefabRequest {
59    pub fn new(name: &str) -> Self {
60        Self(name.to_string())
61    }
62    pub fn name(&self) -> &str {
63        &self.0
64    }
65}
66
67impl std::fmt::Display for EntityName {
68    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        write!(f, "{}", self.0)
70    }
71}
72
73#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
74pub struct MeshSource(pub String);
75
76#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
77pub struct MaterialSource {
78    pub albedo: [f32; 4],
79    pub roughness: f32,
80    pub metallic: f32,
81    pub unlit: f32,
82    pub texture_source: Option<String>,
83}
84
85impl_component!(Parent, Children, EntityName, IsHidden, PrefabRequest, IsDeleted, MeshSource, MaterialSource);
86
87// ============================================================
88//  Bundle Trait
89// ============================================================
90
91pub trait Bundle {
92    fn get_infos() -> Vec<crate::archetype::ComponentInfo>;
93    /// # Safety
94    /// `arch`, `Self::get_infos()`'un döndürdüğü bileşen sütunlarını içermeli ve `_row`
95    /// bu arketipte ayrılmış geçerli bir satır olmalıdır. Veriler ham olarak kopyalanır;
96    /// sahiplik arketipe devredilir.
97    unsafe fn write_to_archetype(self, arch: &mut crate::archetype::Archetype, _row: usize, tick: u32);
98    fn apply(self, _world: &mut crate::world::World, _entity: crate::entity::Entity) where Self: Sized {}
99}
100
101pub struct DynamicBundle<B: Bundle, C: Component> {
102    pub bundle: B,
103    pub component: C,
104}
105
106impl<B: Bundle, C: Component> Bundle for DynamicBundle<B, C> {
107    fn get_infos() -> Vec<crate::archetype::ComponentInfo> {
108        let mut infos = B::get_infos();
109        infos.push(crate::archetype::ComponentInfo::of::<C>());
110        infos
111    }
112
113    unsafe fn write_to_archetype(self, arch: &mut crate::archetype::Archetype, row: usize, tick: u32) {
114        self.bundle.write_to_archetype(arch, row, tick);
115        let col = arch.get_column_mut(std::any::TypeId::of::<C>()).unwrap();
116        if col.len() <= row {
117            col.push_raw(&self.component as *const _ as *const u8, tick);
118            std::mem::forget(self.component);
119        } else {
120            let ptr = col.get_mut_ptr(row) as *mut C;
121            std::ptr::write(ptr, self.component);
122            *col.ticks_ptr_mut().add(row) = crate::archetype::ComponentTicks::new(tick);
123        }
124    }
125}
126
127pub trait BundleExt: Bundle + Sized {
128    fn with<C: Component>(self, component: C) -> DynamicBundle<Self, C> {
129        DynamicBundle { bundle: self, component }
130    }
131}
132
133impl<T: Bundle> BundleExt for T {}
134
135impl<T: Component> Bundle for T {
136    fn get_infos() -> Vec<crate::archetype::ComponentInfo> {
137        vec![crate::archetype::ComponentInfo::of::<T>()]
138    }
139
140    fn apply(self, world: &mut crate::world::World, entity: crate::entity::Entity) {
141        world.add_component(entity, self);
142    }
143
144    unsafe fn write_to_archetype(self, arch: &mut crate::archetype::Archetype, row: usize, tick: u32) {
145        let col = arch.get_column_mut(std::any::TypeId::of::<T>()).unwrap_or_else(|| {
146            panic!(
147                "Component column for `{}` missing in Archetype. The bundle fast-path \
148                 (write_to_archetype) only handles Table-storage components; SparseSet \
149                 components must be routed via World::add_component. spawn_batch already \
150                 falls back for sparse bundles — reaching here means another bundle path \
151                 wrote a sparse component into the archetype.",
152                std::any::type_name::<T>()
153            )
154        });
155        if col.len() <= row {
156            col.push_raw(&self as *const _ as *const u8, tick);
157            std::mem::forget(self);
158        } else {
159            let ptr = col.get_mut_ptr(row) as *mut T;
160            std::ptr::write(ptr, self);
161            *col.ticks_ptr_mut().add(row) = crate::archetype::ComponentTicks::new(tick);
162        }
163    }
164}
165
166macro_rules! impl_bundle_tuple {
167    ($($name:ident),*) => {
168        #[allow(non_snake_case)]
169        impl<$($name: crate::component::Bundle),*> Bundle for ($($name,)*) {
170            fn get_infos() -> Vec<crate::archetype::ComponentInfo> {
171                let mut infos = Vec::new();
172                $(
173                    infos.extend(<$name as crate::component::Bundle>::get_infos());
174                )*
175                infos
176            }
177
178            fn apply(self, world: &mut crate::world::World, entity: crate::entity::Entity) {
179                let ($($name,)*) = self;
180                $(
181                    $name.apply(world, entity);
182                )*
183            }
184
185            unsafe fn write_to_archetype(self, arch: &mut crate::archetype::Archetype, row: usize, tick: u32) {
186                let ($($name,)*) = self;
187                $(
188                    $name.write_to_archetype(arch, row, tick);
189                )*
190            }
191        }
192    };
193}
194
195impl_bundle_tuple!(A);
196impl_bundle_tuple!(A, B);
197impl_bundle_tuple!(A, B, C);
198impl_bundle_tuple!(A, B, C, D);
199impl_bundle_tuple!(A, B, C, D, E);
200impl_bundle_tuple!(A, B, C, D, E, F);
201impl_bundle_tuple!(A, B, C, D, E, F, G);
202impl_bundle_tuple!(A, B, C, D, E, F, G, H);
203impl_bundle_tuple!(A, B, C, D, E, F, G, H, I);
204impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J);
205impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K);
206impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
207impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
208impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
209impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
210impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);