@@ -2,7 +2,11 @@ use std::marker::PhantomData;
2
2
3
3
use bevy_utils:: { tracing:: warn, HashSet } ;
4
4
5
- use crate :: { component:: ComponentId , prelude:: Bundle , world:: World } ;
5
+ use crate :: {
6
+ component:: { ComponentId , Components } ,
7
+ prelude:: Bundle ,
8
+ world:: World ,
9
+ } ;
6
10
7
11
/// A rule about which [`Component`](crate::component::Component)s can coexist on entities.
8
12
///
@@ -236,6 +240,15 @@ impl UntypedArchetypeInvariant {
236
240
) ;
237
241
}
238
242
}
243
+
244
+ /// Returns formatted string describing this archetype invariant
245
+ pub fn display ( & self , components : & Components ) -> String {
246
+ format ! (
247
+ "{{Premise: {}, Consequence: {}}}" ,
248
+ self . premise. display( components) ,
249
+ self . consequence. display( components)
250
+ )
251
+ }
239
252
}
240
253
241
254
/// A type-erased version of [`ArchetypeStatement`].
@@ -270,6 +283,31 @@ impl UntypedArchetypeStatement {
270
283
}
271
284
}
272
285
286
+ /// Returns formatted string describing this archetype invariant
287
+ ///
288
+ /// For Rust types, the names should match the type name.
289
+ /// If any [`ComponentId`]s in the invariant have not been registered in the world,
290
+ /// then the raw component id will be returned instead.
291
+ pub fn display ( & self , components : & Components ) -> String {
292
+ let component_names: String = self
293
+ . component_ids ( )
294
+ . iter ( )
295
+ . map ( |id| match components. get_info ( * id) {
296
+ Some ( info) => info. name ( ) . to_owned ( ) ,
297
+ None => format ! ( "{:?}" , id) ,
298
+ } )
299
+ . reduce ( |acc, s| format ! ( "{}, {}" , acc, s) )
300
+ . unwrap_or ( "" . to_owned ( ) ) ;
301
+
302
+ match self {
303
+ UntypedArchetypeStatement :: AllOf ( _) => format ! ( "AllOf({component_names})" ) ,
304
+ UntypedArchetypeStatement :: AnyOf ( _) => format ! ( "AnyOf({component_names})" ) ,
305
+ UntypedArchetypeStatement :: AtMostOneOf ( _) => format ! ( "AtMostOneOf({component_names})" ) ,
306
+ UntypedArchetypeStatement :: NoneOf ( _) => format ! ( "NoneOf({component_names})" ) ,
307
+ UntypedArchetypeStatement :: Only ( _) => format ! ( "Only({component_names})" ) ,
308
+ }
309
+ }
310
+
273
311
/// Test if this statement is true for the provided set of [`ComponentId`]s.
274
312
pub fn test ( & self , component_ids : & HashSet < ComponentId > ) -> bool {
275
313
match self {
@@ -342,7 +380,11 @@ impl ArchetypeInvariants {
342
380
/// # Panics
343
381
///
344
382
/// Panics if any archetype invariant is violated.
345
- pub fn test_archetype ( & self , component_ids_of_archetype : impl Iterator < Item = ComponentId > ) {
383
+ pub fn test_archetype (
384
+ & self ,
385
+ component_ids_of_archetype : impl Iterator < Item = ComponentId > ,
386
+ components : & Components ,
387
+ ) {
346
388
let component_ids_of_archetype: HashSet < ComponentId > = component_ids_of_archetype. collect ( ) ;
347
389
348
390
for invariant in & self . raw_list {
@@ -359,10 +401,24 @@ impl ArchetypeInvariants {
359
401
}
360
402
}
361
403
404
+ let archetype_component_names: Vec < String > = component_ids_of_archetype
405
+ . into_iter ( )
406
+ . map ( |id| match components. get_info ( id) {
407
+ Some ( info) => info. name ( ) . to_owned ( ) ,
408
+ None => format ! ( "{:?}" , id) ,
409
+ } )
410
+ . collect ( ) ;
411
+
412
+ let failed_invariant_names: String = failed_invariants
413
+ . into_iter ( )
414
+ . map ( |invariant| invariant. display ( components) )
415
+ . reduce ( |acc, s| format ! ( "{}\n {}" , acc, s) )
416
+ . unwrap ( ) ;
417
+
362
418
panic ! (
363
- "Archetype invariant violated! The following invariants were violated for archetype {:?}:\n {:? }" ,
364
- component_ids_of_archetype ,
365
- failed_invariants ,
419
+ "Archetype invariant violated! The following invariants were violated for archetype {:?}:\n {}" ,
420
+ archetype_component_names ,
421
+ failed_invariant_names ,
366
422
)
367
423
}
368
424
}
0 commit comments