Class EntityAttributes
- Namespace
- ElectricDrill.AstraRpgFramework.Attributes
- Assembly
- com.electricdrill.astra-rpg-framework.Runtime.dll
Manages the attributes of an entity. This component calculates attribute values by combining base values, flat modifiers, percentage modifiers, and spent attribute points. It requires an ElectricDrill.AstraRpgFramework.Attributes.EntityAttributes.EntityCore component on the same GameObject.
[DisallowMultipleComponent]
[RequireComponent(typeof(EntityCore))]
public class EntityAttributes : MonoBehaviour, IHasAttributeSet, IValueProvider<AttributeSO, long>, IAttributeReader, IValueContainer<AttributeSO>, IHasEntity, IEventRegistrar
- Inheritance
-
objectEntityAttributes
- Implements
- Extension Methods
Properties
AttributeSet
Gets the AttributeSet used by this entity. The source of the attribute set depends on whether UseBaseAttributesFromClass is true. If true, it returns the attribute set from the EntityClass. Otherwise, it returns the ElectricDrill.AstraRpgFramework.Attributes.EntityAttributes._fixedBaseAttributeSet.
public virtual AttributeSetSO AttributeSet { get; }
Property Value
AvailableAttributePoints
Gets the number of attribute points currently available to spend.
public int AvailableAttributePoints { get; }
Property Value
- int
BonusAttributePoints
Gets the number of bonus attribute points granted outside of leveling (e.g. from items or quests). Unlike level points, these survive level-down and re-spec.
public int BonusAttributePoints { get; }
Property Value
- int
EntityClass
Gets the class for this entity. The class is used to determine base attributes when ElectricDrill.AstraRpgFramework.Attributes.EntityAttributes._useBaseAttributesFromClass is true.
public IClassSource EntityClass { get; }
Property Value
FixedAttributeValuesAsset
Gets or sets the asset-backed fixed attribute source used when UseFixedAttributeValuesAsset is true.
public FixedAttributeValuesSO FixedAttributeValuesAsset { get; set; }
Property Value
FlatModifiers
Gets the instance of flat modifiers for the attributes. Flat modifiers are added directly to the base attribute values.
protected virtual AttributeSetInstance FlatModifiers { get; }
Property Value
LevelAttributePoints
Gets the number of attribute points granted from leveling up.
public int LevelAttributePoints { get; }
Property Value
- int
OnAttributeChanged
Event raised when an Attribute changes.
public AttributeChangedGameEvent OnAttributeChanged { get; }
Property Value
PercentageModifiers
Gets the instance of percentage modifiers for the attributes. Percentage modifiers are applied after flat modifiers.
protected virtual AttributeSetInstance PercentageModifiers { get; }
Property Value
TotalAttributePoints
Gets the total number of attribute points, including both available and spent points.
public int TotalAttributePoints { get; }
Property Value
- int
UseBaseAttributesFromClass
Gets or sets whether to use base attributes from the entity's class. If true, base attributes are derived from the EntityClass. If false, fixed base attributes defined in this component are used.
public bool UseBaseAttributesFromClass { get; set; }
Property Value
- bool
UseFixedAttributeValuesAsset
Gets or sets whether fixed base attributes are sourced from FixedAttributeValuesAsset instead of the inline values. Only meaningful when UseBaseAttributesFromClass is false.
public bool UseFixedAttributeValuesAsset { get; set; }
Property Value
- bool
Methods
AddFlatModifier(AttributeSO, long)
Adds a flat modifier to an attribute.
public void AddFlatModifier(AttributeSO attribute, long value)
Parameters
attributeAttributeSOThe attribute to modify.
valuelongThe flat value to add.
AddPercentageModifier(AttributeSO, Percentage)
Adds a percentage modifier to an attribute.
public void AddPercentageModifier(AttributeSO attribute, Percentage value)
Parameters
attributeAttributeSOThe attribute to modify.
valuePercentageThe percentage value to add.
AddPermanentBonus(AttributeSO, long)
Adds amount (which may be negative, e.g. a curse) to the permanent bonus
already applied to attribute.
public void AddPermanentBonus(AttributeSO attribute, long amount)
Parameters
attributeAttributeSOThe attribute to modify.
amountlongThe amount to add to the existing permanent bonus.
BeginBulk()
Opens a bulk-update bracket. While the bracket is open, all attribute-changed events are deferred: each affected attribute is recorded in a dirty set with its pre-mutation snapshot, and a single OnAttributeChanged event (plus callback) is raised per genuinely-changed attribute when the outermost bracket disposes. Nested brackets are supported; flush happens only on the outermost dispose.
public EntityAttributes.BulkUpdateScope BeginBulk()
Returns
Remarks
Use this around broad mutations such as level-up/down, class swap, or RefundAll to collapse what would otherwise be many events into one per affected attribute. The dirty set and snapshot dictionary are reused across brackets — no per-bracket heap allocation.
ClearAllPermanentBonuses()
Removes every permanent bonus. Manual API only — no automatic path (level-down, re-spec, RefundAllSpentPoints) ever calls this.
public void ClearAllPermanentBonuses()
Remarks
This has no effect on spendable attribute points (level or bonus) — permanent bonuses were never drawn from a point budget, so clearing them never increases AvailableAttributePoints or BonusAttributePoints. To let a player re-spend points already invested, use RefundAllSpentPoints() instead.
ClearPermanentBonus(AttributeSO)
Removes the permanent bonus from a single attribute, if any. Manual API only — no automatic path (level-down, re-spec, RefundAllSpentPoints) ever calls this.
public void ClearPermanentBonus(AttributeSO attribute)
Parameters
attributeAttributeSOThe attribute to clear.
ComputeFinalAt(AttributeSO, int)
Computes the attribute's final value as it would be at the specified entity level, without touching the runtime cache. Used to snapshot old/new values around level changes and by scaling components that need per-level projections.
public long ComputeFinalAt(AttributeSO attribute, int level)
Parameters
attributeAttributeSOThe attribute to compute.
levelintThe level at which to evaluate the attribute.
Returns
- long
The clamped final value at the given level, or 0 if the component is disabled.
Remarks
Pure and cache-free: callers can interleave ComputeFinalAt(AttributeSO, int) with Get(AttributeSO) without poisoning cached state. Disabled components always return 0 for consistency with Get(AttributeSO).
Contains(AttributeSO)
Returns whether attribute is tracked by this component's attribute set.
public bool Contains(AttributeSO attribute)
Parameters
attributeAttributeSO
Returns
- bool
Get(AttributeSO)
Gets the final calculated value of a specific attribute. The final value includes base value, flat and percentage modifiers, and spent attribute points. The result is clamped to the attribute's min/max values.
public long Get(AttributeSO attribute)
Parameters
attributeAttributeSOThe attribute to retrieve.
Returns
- long
The final value of the attribute if the component is enabled (clamped to min/max values); otherwise, 0
GetAllPermanentBonuses()
Gets a read-only view of every attribute with a non-default permanent bonus. Allocates a copy.
public IReadOnlyDictionary<AttributeSO, long> GetAllPermanentBonuses()
Returns
- IReadOnlyDictionary<AttributeSO, long>
GetAllSpentPoints()
Gets a dictionary containing the number of attribute points spent on each attribute.
public Dictionary<AttributeSO, int> GetAllSpentPoints()
Returns
- Dictionary<AttributeSO, int>
A dictionary where keys are attributes and values are the points spent on each attribute.
GetBase(AttributeSO)
Gets the base value of an attribute at the entity's current level. Base attributes don't consider flat or percentage modifiers, nor spent attribute points.
public long GetBase(AttributeSO attribute)
Parameters
attributeAttributeSOThe attribute to retrieve the base value for.
Returns
- long
The base value of the attribute (clamped to its min/max values) if enabled; otherwise, 0
GetFixedBaseAttributeValues()
Reads back every fixed base attribute value, in the shape SetFixedAttributeSource(IReadOnlyDictionary<AttributeSO, long>) expects — the bulk getter that pairs with the bulk setter, so a save system does not have to walk AttributeSet and call GetBase(AttributeSO) itself. Allocates a copy.
public IReadOnlyDictionary<AttributeSO, long> GetFixedBaseAttributeValues()
Returns
- IReadOnlyDictionary<AttributeSO, long>
A read-only snapshot of the fixed base attribute values.
Remarks
Keyed on the attributes of the fixed base attribute set, and read through the source
currently backing them: the values in FixedAttributeValuesAsset when
UseFixedAttributeValuesAsset is on, the inline values otherwise. Unaffected by
UseBaseAttributesFromClass — class-derived base values are design-time data
owned by the ClassSO, and are not this component's state to hand out.
GetPermanentBonus(AttributeSO)
Gets the permanent bonus applied to a specific attribute (0 if none). Permanent bonuses are applied alongside invested points, before percentage modifiers, and are unaffected by level-down, re-spec, or RefundAllSpentPoints().
public long GetPermanentBonus(AttributeSO attribute)
Parameters
attributeAttributeSOThe attribute to query.
Returns
- long
GetSpentOn(AttributeSO)
Gets the number of attribute points spent on a specific attribute.
public int GetSpentOn(AttributeSO attribute)
Parameters
attributeAttributeSOThe attribute to check.
Returns
- int
The number of points spent on the attribute.
GrantBonusAttributePoints(int)
Grants extra spendable attribute points outside of leveling (e.g. from a consumed item or a completed quest). Unlike level points, bonus points survive level-down and re-spec.
public void GrantBonusAttributePoints(int amount)
Parameters
amountintThe number of bonus points to grant.
RefundAllSpentPoints()
Refunds all spent attribute points, making them available to spend again. Pre-snapshots each invested attribute's current value inside a bulk bracket, so the per-investment callbacks collapse into a single event per genuinely-changed attribute. Iterates the portfolio's zero-alloc enumerator to avoid copying the investments dictionary.
public void RefundAllSpentPoints()
RefundFrom(AttributeSO, int)
Refunds a certain amount of attribute points from a specific attribute. Event propagation is handled by the portfolio callback.
public void RefundFrom(AttributeSO attribute, int amount)
Parameters
attributeAttributeSOThe attribute to refund from.
amountintThe number of points to refund.
RefundPointsForAttribute(AttributeSO)
Refunds all spent attribute points for a specific attribute, making them available to spend again. Event propagation is handled by the portfolio callback.
public void RefundPointsForAttribute(AttributeSO attribute)
Parameters
attributeAttributeSOThe attribute to refund points for.
RemovePermanentBonus(AttributeSO, long)
Removes amount from the permanent bonus already applied to
attribute. Equivalent to AddPermanentBonus(AttributeSO, long) with a negated amount.
public void RemovePermanentBonus(AttributeSO attribute, long amount)
Parameters
attributeAttributeSOThe attribute to modify.
amountlongThe amount to subtract from the existing permanent bonus.
RevokeBonusAttributePoints(int)
Revokes previously granted bonus attribute points. If this would push spent points above the new budget, the configured ElectricDrill.AstraRpgFramework.Attributes.EntityAttributes._pointRemovalStrategy is used to refund investments first, exactly like a level-down.
public void RevokeBonusAttributePoints(int amount)
Parameters
amountintThe number of bonus points to revoke.
SetAllSpentPoints(IReadOnlyDictionary<AttributeSO, int>)
Replaces the points spent on every attribute in one bulk update, e.g. when restoring from save data. The setter that pairs with GetAllSpentPoints().
public void SetAllSpentPoints(IReadOnlyDictionary<AttributeSO, int> investments)
Parameters
investmentsIReadOnlyDictionary<AttributeSO, int>The points spent per attribute to restore.
Remarks
SpendOn(AttributeSO, int) and RefundFrom(AttributeSO, int) are incremental in-game transactions: each one validates against the state at that moment, so replaying a whole snapshot through them makes the result depend on the order the attributes are replayed in, and logs errors for every step that momentarily does not fit. This applies the snapshot in one assignment instead.
Restore the point budget first. The caller is responsible for having brought the budget up to at least the sum being restored — via SetTotalCurrentExp(long) for level points and SetBonusAttributePoints(int) for bonus points. A snapshot the budget cannot cover is rejected in full, with an error, rather than partially applied; nothing is written and no events are raised.
Attributes that are no longer part of the current AttributeSet — removed from
the game since the save was written — are skipped with a warning, and the rest still
applies. Attributes absent from investments end at zero, so this is a
replacement, not a merge.
Raises one OnAttributeChanged per attribute whose final value actually changed and at most one OnAttributePointsChangedCallback, using the same bulk-update bracket as SetPermanentBonuses(IReadOnlyDictionary<AttributeSO, long>) and RefundAllSpentPoints().
Exceptions
- ArgumentNullException
Thrown when
investmentsis null.
SetBonusAttributePoints(int)
Sets the bonus attribute points pool to an absolute value, e.g. when restoring from save data. If this would push spent points above the new budget, the configured ElectricDrill.AstraRpgFramework.Attributes.EntityAttributes._pointRemovalStrategy is used to refund investments first.
public void SetBonusAttributePoints(int amount)
Parameters
amountintThe absolute bonus point value.
SetFixed(AttributeSO, long)
Sets a fixed base value for a specific attribute. This is only applicable when UseBaseAttributesFromClass is false.
public void SetFixed(AttributeSO attribute, long value)
Parameters
attributeAttributeSOThe attribute to set.
valuelongThe fixed base value to assign.
SetFixedAttributeSet(AttributeSetSO)
Replaces the AttributeSetSO used for fixed (non-class) base attributes at runtime. Reconciles ElectricDrill.AstraRpgFramework.Attributes.EntityAttributes._fixedAttributeValues and the attribute-points portfolio to the new set's attributes (preserving values/investments for attributes present in both), and invalidates the cache. Does not raise per-attribute change events, matching the existing schema-change path taken when the AttributeSet getter itself detects a set change.
public void SetFixedAttributeSet(AttributeSetSO newAttributeSet)
Parameters
newAttributeSetAttributeSetSOThe attribute set to switch to.
SetFixedAttributeSource(IFixedAttributeSource)
Replaces every fixed base attribute value from source, applied
immediately. Only meaningful when UseBaseAttributesFromClass is false. Always
writes into the inline ElectricDrill.AstraRpgFramework.Attributes.EntityAttributes._fixedAttributeValues — never into
FixedAttributeValuesAsset, since that asset may be shared by other entities and
a per-entity runtime override should not leak into it.
source must cover every attribute in the current AttributeSet.
Snapshots every affected attribute's current value before mutating any of them, then raises
one OnAttributeChanged event per attribute whose final value actually changed —
reusing the same bulk-update machinery as OnLevelUp(EntityLevelChangedContext).
public void SetFixedAttributeSource(IFixedAttributeSource source)
Parameters
sourceIFixedAttributeSourceThe fixed attribute source to copy values from. Must not be null.
SetFixedAttributeSource(IReadOnlyDictionary<AttributeSO, long>)
Convenience overload of SetFixedAttributeSource(IFixedAttributeSource) for consumers supplying values as a plain dictionary (e.g. deserialized save data or imported balance data), without needing to implement IFixedAttributeSource themselves.
public void SetFixedAttributeSource(IReadOnlyDictionary<AttributeSO, long> values)
Parameters
valuesIReadOnlyDictionary<AttributeSO, long>The fixed base attribute values to apply.
SetPermanentBonus(AttributeSO, long)
Sets the permanent bonus applied to attribute to an absolute value, e.g.
when restoring from save data.
public void SetPermanentBonus(AttributeSO attribute, long amount)
Parameters
attributeAttributeSOThe attribute to modify.
amountlongThe absolute permanent bonus value.
SetPermanentBonuses(IReadOnlyDictionary<AttributeSO, long>)
Replaces every permanent bonus from bonuses in a single bulk update, e.g.
when restoring from save data. Attributes not present in bonuses keep
their current permanent bonus untouched.
public void SetPermanentBonuses(IReadOnlyDictionary<AttributeSO, long> bonuses)
Parameters
bonusesIReadOnlyDictionary<AttributeSO, long>The permanent bonus values to apply.
SpendOn(AttributeSO, int)
Spends a certain amount of attribute points on a specific attribute. Cache invalidation and change-event raising are driven by the portfolio's ElectricDrill.AstraRpgFramework.Attributes.PointsTracker.EntityPointsTracker.OnInvestmentChanged callback; the call to Get(AttributeSO) primes the cache so the callback handler can read the old value.
public void SpendOn(AttributeSO attribute, int amount)
Parameters
attributeAttributeSOThe attribute to increase.
amountintThe number of points to spend.
Subscribe<TEvent>(TEvent)
Registers gameEvent on the channel matching TEvent.
public void Subscribe<TEvent>(TEvent gameEvent) where TEvent : ScriptableObject
Parameters
gameEventTEvent
Type Parameters
TEvent
Exceptions
- ArgumentException
Thrown when no channel is registered for
TEvent.
TryGet(AttributeSO, out long)
Tries to get the final value of an attribute. Returns true if the attribute is contained in the attribute set; otherwise, false.
public bool TryGet(AttributeSO attribute, out long value)
Parameters
attributeAttributeSOThe attribute to get.
valuelongWhen this method returns, contains the final value of the attribute if the attribute is contained in the attribute set; otherwise, 0.
Returns
- bool
true if the attribute is contained in the attribute set; otherwise, false.
TryGetBase(AttributeSO, out long)
Tries to get the base value of an attribute (before any modifiers are applied). Returns true if the attribute is contained in the attribute set; otherwise, false.
public bool TryGetBase(AttributeSO attribute, out long value)
Parameters
attributeAttributeSOThe attribute to get the base value of.
valuelongWhen this method returns, contains the base value of the attribute if the attribute is contained in the attribute set; otherwise, 0.
Returns
- bool
true if the attribute is contained in the attribute set; otherwise, false.
Unsubscribe<TEvent>(TEvent)
Removes gameEvent from the channel matching TEvent.
public void Unsubscribe<TEvent>(TEvent gameEvent) where TEvent : ScriptableObject
Parameters
gameEventTEvent
Type Parameters
TEvent
Exceptions
- ArgumentException
Thrown when no channel is registered for
TEvent.
Events
OnAttributeChangedCallback
Entity-local C# event raised whenever an attribute value changes on this component. Fires alongside OnAttributeChanged (SO-based) for each attribute change. EntityStats subscribes to drive the attribute→stat cascade without scanning scaling SOs on every access.
public event Action<AttributeChangeInfo> OnAttributeChangedCallback
Event Type
- Action<AttributeChangeInfo>
OnAttributePointsChangedCallback
Entity-local C# event raised whenever the attribute-points budget changes (available and/or total moving) — from spending/refunding points, granting/revoking bonus points, or level changes. Coalesced under a BeginBulk() scope just like OnAttributeChangedCallback, so a multi-level ResetToLevelOne() raises a single event instead of one per level.
public event Action<AttributePointsChangeInfo> OnAttributePointsChangedCallback
Event Type
- Action<AttributePointsChangeInfo>