Crate bevy_stat_query
source ·Expand description
An over-engineered RPG stat system for the bevy engine.
§Qualified Stats
We describe each stat as a Qualifier and a Stat.
Stat is a concrete stat noun like Strength, Magic, etc.
Qualifier is a flags based adjective that describes
what this Stat can be applied to.
For example in FireMagicDamage, Fire|Magic is the qualifier,
Damage is the Stat.
What this means if an effect boosts Fire|Damage, Magic|Damage,
or simply just Damage, the effect will be applied to the stat,
but an effect on Sword|Damage or Fire|Range won’t be applied to the stat.
§Qualifier
Qualifier is tied to effects, and provides the aforementioned all_of.
In addition any_of is provided for modelling conditional effects like
Elemental|Damage, which means Fire or Water Damage instead of Fire and Water Damage.
Each Qualifier can only have one group of any_of which is a limitation currently.
§Examples
let fire = Qualifier::all_of(Flag::Fire);
let fire_magic = Qualifier::all_of(Flag::Fire|Flag::Magic);
let elemental = Qualifier::any_of(Fire|Water|Air|Earth);
let elemental_magic = Qualifier::any_of(Fire|Water|Air|Earth)
.and_all_of(Magic);§QualifierQuery
QualifierQuery matches all Qualifiers on our character that
qualifies as the query we are looking for.
QualifierQuery::Aggregate collects all qualifiers that matches the query.
For example, suppose we are looking for (Fire|Burn|Magic, Damage):
((), Damage)qualifies.(Fire, Damage)qualifies.(Fire|Magic, Damage)qualifies.(Fire|Burn|Magic, Damage)qualifies.(Elemental, Damage)qualifies.(Fire|Sword, Damage)does not qualify.(Fire|Burn|Magic, Defense)does not qualify.
QualifierQuery::Exact allows us to deny
more generalized qualifiers.
For example, in order to model a statement like so:
Add 50% of the character's magic damage to physical damage.
Querying (Magic, Damage), which contains ((), Damage),
and adding to (Physical, Damage) would cause a duplication.
Therefore the query should be:
QualifierQuery::Exact {
any_of: None,
all_of: Magic,
}- What do you mean? My
DarkFireandFireare totally different things and should be independent.
Create a new qualifier DarkFire instead of Dark|Fire.
§Getting Started
Add marker component StatEntity to an Entity.
If you need caching, add a StatCache as well.
You need to manually clear the cache when the state is changed, however.
- Implement
IntrinsicStreamto make components on the entity queryable. - Implement
ExternalStreamto make components on child entities queryable.
For example we can add BaseStatMap to the Entity as base stats, if we include
it in the intrinsic section of the querier! macro.
§Querier
StatQuerier is the SystemParam to query stats, it is quite difficult to
define one manually so the recommended way is to define a type with the
querier! macro. Additionally we can also use the StatExtension with World access
for similar functionalities.
§Example
querier!(pub UnitStatQuerier {
qualifier: MyQualifier,
intrinsic: {
Allegiance,
Position
},
external: {
Weapon,
Ability,
Effect,
Potion,
}
});§Unordered StatStream
bevy_stat_query uses unordered operations to build up stats. This includes
add, multiply, min, max and or. This ensures no explicit ordering is
ever needed when querying for stats.
Each stat has its components form StatValue, e.g. (12 * 4).min(99).max(0),
and its evaluated form, e.g. 48. StatOperation stores a single operation
that can be written to a StatValue.
§Stat Relation
We can create relations between different
stats using either their components form or their evaluated form.
StatStreams are allowed to query other stats or other entities.
Since stat operations are unordered, dependency cycles cannot be resolved.
If a cycle is detected, an error will be thrown.
§Entity Relation
IntrinsicStream can be used to provide bi-entity relationship
like distance or allegiance. This can be used to model range based effects.
You may find StatOnce useful in implementing these.
§Note
-
StatQuerierrequires read access to all components in the stat system so we cannot mutate anything while having it as a parameter. Using system piping or some kind of deferred command queue for mutations might be advisable in this case. -
The crate heavily utilizes dynamic dispatch under the hood, and is therefore not fully reflect compatible. The supported serialization method is through the
bevy_serde_projectcrate, Check out that crate for more information.
Re-exports§
pub use types::StatValue;
Modules§
Macros§
- Construct a
StatQueriertype alias from arguments. The result can be used as aSystemParam.
Structs§
- A map containing associated output value of stats.
- Represents a fractional number.
- A map containing associated
StatValueof stats. - Data side qualifier for a stat.
- Erased querier with a typed interface.
- This component acts as a cache to stats.
- The core marker component. Stat querying is only allowed on entities marked as
StatEntity. - A map containing associated
StatOperations of stats. - A
SystemParamthat allows the user to query stats byEntity. - Opaque type that contains a stat and a mutable value.
- An unqualified view of a stat map.
Enums§
Traits§
- Component and context based stat streams on children of
StatEntity. - A type that can be treated as flags.
- Trait for a floating point number or a
Fraction. - Trait for an integer.
- An item that can be used to generate stats when directly added to
StatEntity. - A flags like
Qualifierfor stats, normallybitflagsor a set. - Alias for
Shareable + Serialize + DeserializeOwned + TypePath. - Alias for
Clone + Debug + Send + Sync + 'static. - Implement this on your types to qualify them as a
Stat. - A generalized object safe stat relation.
- A generalized object safe stat relation.
- A generalized object safe stat relation that can be serialized.