-
-
Notifications
You must be signed in to change notification settings - Fork 451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
When using components in a relationship pair, data is mixed if writing to first or second for the same pair #1384
Comments
I thought this was documented somewhere. For a relationship pair:
There is no type check in place because I don't know if that's possible in Flecs. Components only store size+alignment so if you were to read/write it as the incorrect type, which you're doing here, then that's really just a programmer error? |
Yes, what you mention is documented here: https://www.flecs.dev/flecs/md_docs_2Relationships.html#relationship-components I understand this is a programmer error, but no warning or error is given, other than receiving garbage data in queries, which is confusing. |
From what I understand, Flecs can figure out the type of a pair given two type parameters, so in theory it could be possible to assert that, which would require using a And I also don't believe it would be possible to get any sort of compile time type checking in a query through the chained |
Well, I was not expecting a compile-time error, but at least some sort of runtime-error / abort. Actually, I found out that: auto ti = ecs_get_type_info(ecs, ecs_pair(a, b));
std::cout << "name:" << ti->name << std::endl; Prints e2.set_second<B>(a, {.value = 4}); should crash. Perhaps assert( ecs_get_type_info(ecs, ecs_pair(first, second))->component == first ); and set_second should check: assert( ecs_get_type_info(ecs, ecs_pair(first, second))->component == second ); at runtime. |
You're right. It may be worth considering runtime debug asserts for this. |
Something worth considering, what the Rust API does for flecs, I panic when calling a bunch of functions like
when referencing a generic/templated parameter this because rust has to be type safe by default code in question: fn check_term_access_validity<'a>(term: &impl TermBuilderImpl<'a>) {
if term.current_term_index() < term.count_generic_terms()
&& term.current_term_ref_mode() != TermRefMode::Src
{
panic!("This function should only be used on terms that are not part of the generic type signature. ")
}
}
/// * C++ API: `term_builder_i::first`
fn set_first<T: ComponentId>(&mut self) -> &mut Self {
check_term_access_validity(self);
self.set_first_id(T::id(self.world()))
}
query<Position> // 1 count_generic_terms
query<Position, Velocity> // 2 count_generic_terms
query<Position,Velocity,Mass> // 3 count_generic_terms so the ecs.query_builder<const Pair<A,B>>() which would select the correct type for you with the same functionality |
this of course comes with a performance penalty, but in this case, for building systems and queries, it really shouldn't matter. |
@jpeletier the behavior that determines which type a pair assumes is documented here: https://www.flecs.dev/flecs/md_docs_2Relationships.html#relationship-components I think this can be caught early by an assert. Will take a look. |
Yes, I am aware of that. Every now and then come back to re-read it! :-) I wonder if the solution is too expensive, I can't think of anything other than:
assert( ecs_get_type_info(ecs, ecs_pair(first, second))->component == first ); and assert( ecs_get_type_info(ecs, ecs_pair(first, second))->component == second ); But that implies bringing over type info at a performance penalty. Is there any bitmask wizardry that could return the pair's type? |
Unfortunately not, the asserts you're suggesting would be the right way to do it. It would add performance overhead in debug mode, though it shouldn't be prohibitive. |
@jpeletier the rust API does the same pub fn set_id<T>(self, data: T, id: impl IntoId) -> Self
{
let world = self.world.world_ptr_mut();
let id = *id.into();
let data_id = T::id(self.world);
let id_data_id = unsafe { sys::ecs_get_typeid(world, id) };
if data_id != id_data_id {
panic!("Data type does not match id type. For pairs this is the first element occurrence that is not a zero-size
} pub fn set_first<First>(self, first: First, second: impl Into<Entity>) -> Self
{
let world_ptr = self.world.world_ptr_mut();
let first_id = First::id(self.world);
let second_id = *second.into();
let pair_id = ecs_pair(first_id, second_id);
let data_id = unsafe { sys::ecs_get_typeid(world_ptr, pair_id) };
if data_id != first_id {
panic!("First type does not match id data type. For pairs this is the first element occurrence that is not a zero-
} |
most (hopefully all) of these safety regards, have been solved in the rust API, since rust requires it, so feel free to take a peek there or ask me |
Fixed! |
Describe the bug
When both elements of a pair are components and different entities are set with data in either first or second, data is put in the same column and considered the same in queries. Flecs detects when components are of different size and aborts, but if both happen to be of the same size, execution continues but data is reinterpreted.
To Reproduce
Output is:
Expected behavior
I was expecting the following at first:
But really, I think that if data has been already set on the first element of a given pair, the pair should acquire the type of the first element during the lifetime of the world; and therefore any subsequent set must be also on the first element. If the condition is not satisfied, the program should abort as may be this is a programming error:
Perhaps this is a non-issue. Nevertheless I believe it should at least be documented somewhere, as a caveat or possible pitfall and wanted to let everyone know just in case :-)
EDIT:
ecs_get_type_info(ecs, ecs_pair(a, b));
resolves the tie and returnsA
as the underlying type for this particular example, therefore I would actually expect:to crash outright, since the underlying type for the pair is
A
, this operation should not be allowed.The text was updated successfully, but these errors were encountered: