@@ -75,6 +75,9 @@ pub enum ArchetypeStatement<B: Bundle> {
75
75
/// The entity has at least one component in the bundle `B`, and may have all of them.
76
76
/// When using a single-component bundle, `AllOf` is preferred.
77
77
AtLeastOneOf ( PhantomData < B > ) ,
78
+ /// The entity has zero or one of the components in the bundle `B`, and may have all of them.
79
+ /// When using a single-component bundle, this is a tautology.
80
+ AtMostOneOf ( PhantomData < B > ) ,
78
81
/// The entity has none of the components in the bundle `B`
79
82
NoneOf ( PhantomData < B > ) ,
80
83
}
@@ -95,6 +98,7 @@ impl<B: Bundle> ArchetypeStatement<B> {
95
98
}
96
99
UntypedArchetypeStatement :: AtLeastOneOf ( component_ids)
97
100
}
101
+ ArchetypeStatement :: AtMostOneOf ( _) => UntypedArchetypeStatement :: AtMostOneOf ( component_ids) ,
98
102
ArchetypeStatement :: NoneOf ( _) => UntypedArchetypeStatement :: NoneOf ( component_ids) ,
99
103
}
100
104
}
@@ -111,6 +115,12 @@ impl<B: Bundle> ArchetypeStatement<B> {
111
115
ArchetypeStatement :: AtLeastOneOf ( PhantomData )
112
116
}
113
117
118
+ /// Constructs a new [`ArchetypeStatement::AtMostOneOf`] variant for all components stored in the bundle `B`
119
+ #[ inline]
120
+ pub const fn at_most_one_of ( ) -> Self {
121
+ ArchetypeStatement :: AtMostOneOf ( PhantomData )
122
+ }
123
+
114
124
/// Constructs a new [`ArchetypeStatement::NoneOf`] variant for all components stored in the bundle `B`
115
125
#[ inline]
116
126
pub const fn none_of ( ) -> Self {
@@ -119,6 +129,7 @@ impl<B: Bundle> ArchetypeStatement<B> {
119
129
}
120
130
121
131
/// A type-erased version of [`ArchetypeInvariant`].
132
+ ///
122
133
/// Intended to be used with dynamic components that cannot be represented with Rust types.
123
134
/// Prefer [`ArchetypeInvariant`] when possible.
124
135
#[ derive( Clone , Debug , PartialEq ) ]
@@ -160,8 +171,11 @@ pub enum UntypedArchetypeStatement {
160
171
/// Evaluates to true if and only if the entity has all of the components present in the set
161
172
AllOf ( HashSet < ComponentId > ) ,
162
173
/// The entity has at least one component in the set, and may have all of them.
163
- /// When using a single-component bundle , `AllOf` is preferred
174
+ /// When using a single-component set , `AllOf` is preferred
164
175
AtLeastOneOf ( HashSet < ComponentId > ) ,
176
+ /// The entity has zero or one of the components in the set, and may have all of them.
177
+ /// When using a single-component set, this is a tautology.
178
+ AtMostOneOf ( HashSet < ComponentId > ) ,
165
179
/// The entity has none of the components in the set
166
180
NoneOf ( HashSet < ComponentId > ) ,
167
181
}
@@ -172,6 +186,7 @@ impl UntypedArchetypeStatement {
172
186
match self {
173
187
UntypedArchetypeStatement :: AllOf ( set)
174
188
| UntypedArchetypeStatement :: AtLeastOneOf ( set)
189
+ | UntypedArchetypeStatement :: AtMostOneOf ( set)
175
190
| UntypedArchetypeStatement :: NoneOf ( set) => set,
176
191
}
177
192
}
@@ -195,6 +210,19 @@ impl UntypedArchetypeStatement {
195
210
}
196
211
false
197
212
}
213
+ UntypedArchetypeStatement :: AtMostOneOf ( exclusive_ids) => {
214
+ let mut found_previous = false ;
215
+ for exclusive_id in exclusive_ids {
216
+ if component_ids. contains ( exclusive_id) {
217
+ if found_previous {
218
+ return false
219
+ } else {
220
+ found_previous = true ;
221
+ }
222
+ }
223
+ }
224
+ true
225
+ }
198
226
UntypedArchetypeStatement :: NoneOf ( forbidden_ids) => {
199
227
for forbidden_id in forbidden_ids {
200
228
if component_ids. contains ( forbidden_id) {
0 commit comments