@@ -457,10 +457,11 @@ export class Archetype {
457457 componentTypes : T ,
458458 componentDataSources : ( any [ ] | EntityId < any > [ ] | undefined ) [ ] ,
459459 entityIndex : number ,
460+ entityId : EntityId ,
460461 ) : ComponentTuple < T > {
461462 return componentDataSources . map ( ( dataSource , i ) => {
462463 const compType = componentTypes [ i ] ! ;
463- return this . buildSingleComponent ( compType , dataSource , entityIndex ) ;
464+ return this . buildSingleComponent ( compType , dataSource , entityIndex , entityId ) ;
464465 } ) as ComponentTuple < T > ;
465466 }
466467
@@ -471,12 +472,19 @@ export class Archetype {
471472 compType : ComponentType < any > ,
472473 dataSource : any [ ] | EntityId < any > [ ] | undefined ,
473474 entityIndex : number ,
475+ entityId : EntityId ,
474476 ) : any {
475477 const optional = isOptionalEntityId ( compType ) ;
476478 const actualType = optional ? compType . optional : compType ;
477479
478480 if ( getIdType ( actualType ) === "wildcard-relation" ) {
479- return this . buildWildcardRelationValue ( dataSource , entityIndex , optional ) ;
481+ return this . buildWildcardRelationValue (
482+ actualType as WildcardRelationId < any > ,
483+ dataSource ,
484+ entityIndex ,
485+ entityId ,
486+ optional ,
487+ ) ;
480488 } else {
481489 return this . buildRegularComponentValue ( dataSource , entityIndex , optional ) ;
482490 }
@@ -486,27 +494,54 @@ export class Archetype {
486494 * Build wildcard relation value from matching relations
487495 */
488496 private buildWildcardRelationValue (
497+ wildcardRelationType : WildcardRelationId < any > ,
489498 dataSource : any [ ] | EntityId < any > [ ] | undefined ,
490499 entityIndex : number ,
500+ entityId : EntityId ,
491501 optional : boolean ,
492502 ) : any {
493- if ( dataSource === undefined ) {
494- if ( optional ) {
495- return undefined ;
496- }
497- throw new Error ( `No matching relations found for mandatory wildcard relation component type` ) ;
498- }
499-
500- const matchingRelations = dataSource as EntityId < any > [ ] ;
503+ const matchingRelations = ( dataSource as EntityId < any > [ ] ) || [ ] ;
501504 const relations : [ EntityId < unknown > , any ] [ ] = [ ] ;
502505
506+ // Add regular archetype relations
503507 for ( const relType of matchingRelations ) {
504508 const dataArray = this . getComponentData ( relType ) ;
505509 const data = dataArray [ entityIndex ] ;
506510 const decodedRel = decodeRelationId ( relType as RelationId < any > ) ;
507511 relations . push ( [ decodedRel . targetId , data === MISSING_COMPONENT ? undefined : data ] ) ;
508512 }
509513
514+ // Add dontFragment relations for this entity
515+ // Get the component ID from the wildcard relation type
516+ const wildcardDecoded = decodeRelationId ( wildcardRelationType ) ;
517+ const targetComponentId = wildcardDecoded . componentId ;
518+
519+ const dontFragmentData = this . dontFragmentRelations . get ( entityId ) ;
520+ if ( dontFragmentData ) {
521+ // Check dontFragment relations for matching component ID
522+ for ( const [ relType , data ] of dontFragmentData ) {
523+ const relDetailed = getDetailedIdType ( relType ) ;
524+ if (
525+ ( relDetailed . type === "entity-relation" || relDetailed . type === "component-relation" ) &&
526+ relDetailed . componentId === targetComponentId
527+ ) {
528+ relations . push ( [ relDetailed . targetId , data ] ) ;
529+ }
530+ }
531+ }
532+
533+ // If no relations found and not optional, this entity doesn't match
534+ if ( relations . length === 0 ) {
535+ if ( ! optional ) {
536+ const wildcardDecoded = decodeRelationId ( wildcardRelationType ) ;
537+ throw new Error (
538+ `No matching relations found for mandatory wildcard relation component ${ wildcardDecoded . componentId } on entity ${ entityId } ` ,
539+ ) ;
540+ }
541+ // For optional, return undefined when there are no relations
542+ return undefined ;
543+ }
544+
510545 return optional ? { value : relations } : relations ;
511546 }
512547
@@ -570,7 +605,7 @@ export class Archetype {
570605 for ( let entityIndex = 0 ; entityIndex < this . entities . length ; entityIndex ++ ) {
571606 const entity = this . entities [ entityIndex ] ! ;
572607
573- const components = this . buildComponentsForIndex ( componentTypes , componentDataSources , entityIndex ) ;
608+ const components = this . buildComponentsForIndex ( componentTypes , componentDataSources , entityIndex , entity ) ;
574609
575610 yield [ entity , ...components ] ;
576611 }
@@ -593,7 +628,7 @@ export class Archetype {
593628 const entity = this . entities [ entityIndex ] ! ;
594629
595630 // Direct array access for each component type using pre-cached sources
596- const components = this . buildComponentsForIndex ( componentTypes , componentDataSources , entityIndex ) ;
631+ const components = this . buildComponentsForIndex ( componentTypes , componentDataSources , entityIndex , entity ) ;
597632
598633 callback ( entity , ...components ) ;
599634 }
@@ -613,4 +648,41 @@ export class Archetype {
613648 callback ( this . entities [ i ] ! , components ) ;
614649 }
615650 }
651+
652+ /**
653+ * Check if any entity in this archetype has a relation matching the given component ID
654+ * This includes both regular relations in componentTypes and dontFragment relations
655+ * @param componentId The component ID to match
656+ * @returns true if any entity has a matching relation
657+ */
658+ hasRelationWithComponentId ( componentId : EntityId < any > ) : boolean {
659+ // Check regular archetype components
660+ for ( const componentType of this . componentTypes ) {
661+ const detailedType = getDetailedIdType ( componentType ) ;
662+ if (
663+ ( detailedType . type === "entity-relation" || detailedType . type === "component-relation" ) &&
664+ detailedType . componentId === componentId
665+ ) {
666+ return true ;
667+ }
668+ }
669+
670+ // Check dontFragment relations for any entity in this archetype
671+ for ( const entityId of this . entities ) {
672+ const entityDontFragmentRelations = this . dontFragmentRelations . get ( entityId ) ;
673+ if ( entityDontFragmentRelations ) {
674+ for ( const relationType of entityDontFragmentRelations . keys ( ) ) {
675+ const detailedType = getDetailedIdType ( relationType ) ;
676+ if (
677+ ( detailedType . type === "entity-relation" || detailedType . type === "component-relation" ) &&
678+ detailedType . componentId === componentId
679+ ) {
680+ return true ;
681+ }
682+ }
683+ }
684+ }
685+
686+ return false ;
687+ }
616688}
0 commit comments