Hello, I'm working on a little ECS for learning purpose.
I'm actually stuck on the system part :
This example work :
fn move_system((p, p1, p2, p3, p4) : (Position, Position1, Position2, Position3, Position4))
{
//Do some stuff
}
fn main()
{
let entity_capacity = 1383333;
let mut world = World::new(entity_capacity);
for n in 0..entity_capacity {
let f = n as f32;
//Spawn and register component if they are new
world.spawn((
Position { x: f, y: f, z: f }, Position1 { x: f, y: f, z: f }, Position2 { x: f, y: f, z: f },
Position3 { x: f, y: f, z: f }, Position4 { x: f, y: f, z: f },
));
}
world.add_system(move_system); //Register a function or a closure as a new system
world.run_once(); //Run all the registered system once, Working well
}
This one doesn't
fn move_system((p, p1, p2, p3, p4) : (&Position, Position1, Position2, Position3, Position4))
{
//Do some stuff
}
fn main()
{
let entity_capacity = 1383333;
let mut world = World::new(entity_capacity);
for n in 0..entity_capacity {
let f = n as f32;
//Spawn and register component if they are new
world.spawn((
Position { x: f, y: f, z: f }, Position1 { x: f, y: f, z: f }, Position2 { x: f, y: f, z: f },
Position3 { x: f, y: f, z: f }, Position4 { x: f, y: f, z: f },
));
}
world.add_system(move_system); //Register a function or a closure as a new system
world.run_once(); //Runtime error => STATUS_ACCESS_VIOLATION
}
After digging into my implementation, I understand why that STATUS_ACCESS_VIOLATION happend,
This is because my underlying function to get the data of each components look like this :
fn get_components_internal<T: Any + Component>(&self) -> Result<ManuallyDrop<Vec<T>>, String> {
let component_type = TypeId::of::<T>();
match self.component_types.get(&component_type) {
Some(t) => {
if let Some(data) = self.component_data.get(t) { // data is a Vec<u8> that contain all the data of this component type
let (ptr, len, cap) = (data.as_ptr(), data.len(), data.capacity());
let component_size = self.component_sizes.get(t).unwrap();
let rebuilt = unsafe {
Vec::from_raw_parts(ptr as *mut T, len / component_size, cap / component_size) //This line seems to be the root of the issue
};
return Ok(ManuallyDrop::new(rebuilt));
}
},
None => {}
}
return Err("This component type isn't register in this world".to_string());
}
So, this function work perfectly fine for value types :
if T == Position
Vec::from_raw_parts(ptr as *mut Position, len / component_size, cap / component_size)
//This is valid (vec<u8> to vec<T>)
but
if T == &Position
Vec::from_raw_parts(ptr as *mut &Position, len / component_size, cap / component_size)
//This is not valid, because I'm creating a vector of ref,
//onto a vector of u8 values which of course doesn't make sens (vec<u8> to vec<&T>).
//The runtime error occur later: vec[index] => STATUS_ACCESS_VIOLATION
So, I guess my question is:
Is it possible to create a vec<&T> from a vec<u8> ?
Maybe I should create first a vec<&T> of size len / component_size, but then how I'm suppose to assign these ref to the actual vec<u8> data?
I also wrote another implementation of get_components_internal that is able to know at runtime if T, is a Value, a Ref or a MutRef, but since I don't know how to convert a vec<u8> to a vec<&T>... This didn't solve my issue (but I could write a custom code for Ref and MutRef, and keep the actual code for values).
Hope my question make sens , this is my first try to implement an ECS, so I maybe not approching the subject correctly.