Unreal GAS: Influence of the GameplayEffect aggregator on gameplay attribute values - unreal-engine4

During analyzing the lifetime of a GameplayEffect modifier and execution, I've stumbled across attribute aggregators or GameplayEffect aggregators (both terms are used in source code). These are used to evaluate modified attribute values (they are modified by GameplayEffects).
However, I don't understand how those aggregators influence the actual GameplayAbilitySystem attributes which are attached (as part of an AttributeSet) to the actor:
Does an attribute/GameplayEffect aggregator FAggregator influence the base value or the current value of a gameplay attribute FGameplayAttributeData?
Is the base value of an attribute/GameplayEffect aggregator float FAggregator::BaseValue related to the base value of a gameplay attribute float FGameplayAttributeData::BaseValue?
The vital components of attribute/GameplayEffect aggregators are
so called gameplay modifier evaluation channels EGameplayModEvaluationChannel, which are used sequentially during value evaluation (the result of channel0 is passed as base value to channel1 etc)
storing modifiers (with its magnitude, operation, tags and link to the applying GameplayEffect) in certain channels, which define the actual numerical evaluation
Those are used for doing the evaluation of
a final value
a base value by evaluating a final value in reverse, attempting to determine the base value from the modifiers (deprecated b/c GAS now has struct-based attributes - according to documentation)
a bonus value (final value - base value)
(all of them are just return values of functions and are not member variables of the aggregator)
To notify other classes of an evaluation (or changes to the aggregator), two methods are used
a delegate FOnAggregatorDirty is broadcasted which contains a reference to the aggregator
every GameplayEffect, which is registered in the AbilitySystemComponent, updates the change to its affected attribute(s) (via FActiveGameplayEffectsContainer::UpdateAggregatorModMagnitudes()) by updating the aggregator FAggregator for the attribute (which is determined or set via FindOrCreateAttributeAggregator()) in FAggregator::UpdateAggregatorMod())
I don't see, how one or both of those notification methods update the actual attribute values.
(The official documentation/source code as well as the excellent GAS: Comprehensive Analysis and GAS and you unfortunately don't shed light on GameplayEffect aggregators.)

The attribute/GameplayEffect aggregator influences the current value of a gameplay attribute.
Partly yes. They are related in one direction: the base value of the gameplay attribute is used to set the base value of the attribute/GameplayEffect aggregator, but not the other way around. The aggregator does not change the attribute base value.
Explanation for (1)
I was on the right track by looking at the notification methods. In fact, both in conjunction are updating the gameplay attribute:
FActiveGameplayEffectsContainer::FindOrCreateAttributeAggregator() applies UAbilitySystemComponent::OnAttributeAggregatorDirty() to the OnDirty delegate (that delegate is executed when the aggregator changes as written in the question).
OnAttributeAggregatorDirty() calls FActiveGameplayEffectsContainer::InternalUpdateNumericalAttribute(), which calls
UAbilitySystemComponent::SetNumericAttribute_Internal(), which calls
FGameplayAttribute::SetNumericValueChecked(). That sets the current value of a gameplay attribute.
Explanation for (2)
The base value of the attribute/GameplayEffect aggregator is set only using the gameplay attribute base value FGameplayAttributeData::BaseValue in:
FActiveGameplayEffectsContainer::OnAttributeAggregatorDirty()
FActiveGameplayEffectsContainer::SetAttributeBaseValue()
The base value of the gameplay attribute is set by:
UAttributeSet::InitFromMetaDataTable()
FActiveGameplayEffectsContainer::SetAttributeBaseValue()
In both functions, the attribute base value has no relation to the base value of the aggregator.

Related

How to know which data type is being passed

I have a Select function in my block diagram. For the True and False statements I am passing two data types. The True statement is a is a Digital Reference data type to a numerical indicator in the front panel, and the False statement is a knob Reference data type to a gauge in the front panel as well. I am not sure what to put in the middle entry point for the Select function since it needs to have a True Boolean. Ideally I would just connect another Digital Reference data type and it would return the digital indicator in that case but the Select function only receives a boolean as an input.
Ideally I would just connect another Digital Reference data type and it would return the digital indicator in that case
In what case? You haven't defined any case. :-)
The Select node picks between two different values. When you wire the digital reference to one input and the knob reference to the other input, the output will be a control reference to one of those two controls. You have to wire a Bool in order to pick which control you're going to operate on downstream.
You say you want to wire another Digital Reference to the middle terminal, but that's just a reference to a control. It doesn't define a choice. Perhaps you want to read the Value property of that other control and do something on the value? If so, this is your code, where you put whatever test you want instead of the Equal Zero node.
Select function requires a boolean in the selector input. The other two inputs changes according to what you connect.
So, in your scenario:
Output type is the most lower common class between knob reference and numeric reference. It should be a Numeric reference.
the selector input must be a boolean type. You cannot connect any reference or any other data type. So, connect a boolean control or use the approach suggested by srm.
I found a solution by connecting an equal function to the middle boolean selector input of the select function. The equal function has two inputs, an either Knob Reference or Digital Reference for the first input and a Digital Reference for the second input. If those two are equal then the equal function passes true to the selector function and then the Digital Reference gets passed in this case.

Unique symbol value on type level

Is it possible to have some kind of unique symbol value on the type level, that could be used to distinct (tag) some record without the need to supply a unique string value?
In JS there is Symbol often used for such things. But I would like to have it without using Effect, in pure context.
Well, it could even like accessing Full qualified module name (which is quite unique for the task), but I'm not sure if this is a really relevant/possible thing in the Purescript context.
Example:
Say There is some module that exposes:
type Worker value state =
{ tag :: String
, work :: value -> state -> Effect state
}
makeWorker :: forall value state. Worker value state
performWork :: forall value state. woker -> Worker value state -> value -> Unit
This module is used to manage the state of workers, it passes them value and current state value, and gets Effect with new state value, and puts in state map where keys are tags.
Users of the module:
In one module:
worker = makeWorker { tag: "WorkerOne", work }
-- Then this tagged `worker` is used to performWork:
-- performWork worker "Some value"
In another module we use worker with another tag:
worker = makeWorker { tag: "WorkerTwo", work }
So it would be nice if there would be no need to supply a unique string ("WorkerOne", "WorkerTwo") as a tag but use some "generated" unique value. But the task is that worker should be created on the top level of the module in pure context.
Semantics of PureScript as such is pure and pretty much incompatible with this sort of thing. Same expression always produces same result. The results can be represented differently at a lower level, but in the language semantics they're the same.
And this is a feature, not a bug. In my experience, more often than not, a requirement like yours is an indication of a flawed design somewhere upstream.
An exception to this rule is FFI: if you have to interact with the underlying platform, there is no choice but to play by that platform's rules. One example I can give is React, which uses the JavaScript's implicit object identity as a way to tell components apart.
So the bottom line is: I urge you to reconsider the requirement. Chances are, you don't really need it. And even if you do, manually specified strings might actually be better than automatically generated ones, because they may help you troubleshoot later.
But if you really insist on doing it this way, good news: you can cheat! :-)
You can generate your IDs effectfully and then wrap them in unsafePerformEffect to make it look pure to the compiler. For example:
import Effect.Unsafe (unsafePerformEffect)
import Data.UUID (toString, genUUID)
workerTag :: String
workerTag = toString $ unsafePerformEffect genUUID

What is the difference in creating uvm_reg_field with or without get_full_name()

What is the difference between
this.ModuleEn=uvm_reg_field::type_id::create("ModuleEn");
and
this.ModuleEn=uvm_reg_field::type_id::create("ModuleEn",,get_full_name());
I don't see difference in simulation results.
The 2nd and 3rd arguments to create() affect the lookup of factory overrides. If you have no overrides (which is typical for RAL models), these arguments will not make any difference.
The second argument would be used to set the context of the override if you were creating this inside a uvm_component. The third argument is used to set a context via a string path, which in this case is being set by the register's path.

Tell IPython to use an object's `__str__` instead of `__repr__` for output

By default, when IPython displays an object, it seems to use __repr__.
__repr__ is supposed to produce a unique string which could be used to reconstruct an object, given the right environment.
This is distinct from __str__, which supposed to produce human-readable output.
Now suppose we've written a particular class and we'd like IPython to produce human readable output by default (i.e. without explicitly calling print or __str__).
We don't want to fudge it by making our class's __repr__ do __str__'s job.
That would be breaking the rules.
Is there a way to tell IPython to invoke __str__ by default for a particular class?
This is certainly possible; you just need implement the instance method _repr_pretty_(self). This is described in the documentation for IPython.lib.pretty. Its implementation could look something like this:
class MyObject:
def _repr_pretty_(self, p, cycle):
p.text(str(self) if not cycle else '...')
The p parameter is an instance of IPython.lib.pretty.PrettyPrinter, whose methods you should use to output the text representation of the object you're formatting. Usually you will use p.text(text) which just adds the given text verbatim to the formatted representation, but you can do things like starting and ending groups if your class represents a collection.
The cycle parameter is a boolean that indicates whether a reference cycle is detected - that is, whether you're trying to format the object twice in the same call stack (which leads to an infinite loop). It may or may not be necessary to consider it depending on what kind of object you're using, but it doesn't hurt.
As a bonus, if you want to do this for a class whose code you don't have access to (or, more accurately, don't want to) modify, or if you just want to make a temporary change for testing, you can use the IPython display formatter's for_type method, as shown in this example of customizing int display. In your case, you would use
get_ipython().display_formatter.formatters['text/plain'].for_type(
MyObject,
lambda obj, p, cycle: p.text(str(obj) if not cycle else '...')
)
with MyObject of course representing the type you want to customize the printing of. Note that the lambda function carries the same signature as _repr_pretty_, and works the same way.

How to update the visibility of an object based on a parameter

Connections have at least two important variables. The flow variable and not-flow variable (and then stream stuff but lets not talk about those). For clarity I will reference the Fluid connector and its variables m_flow (flow variable) and p (not flow variable).
When your building components it is important to specify if that component is setting the value for the m_flow or p. For example, you do not want to connect two pressure loss components (sets m_flow) together.
The fluid connectors in MSL are defined as port_a (design inlet) and port_b (design outlet). To specify if a port sets m_flow or not, DynamicPipe opts to use the PartialTwoPort component that has an object (black ellipse) in the icon layer that toggles its visibility based on a parameter (port_a_exposesState) which can be modified when PartialTwoPort is extended (i.e., PartialTwoPortFlow).
However, this feature does not work. The parameter will not change its display when the parameter is changed (i.e., the black ellipse on DynamicPipe never goes away).
Below is a simple example demonstrating the concept. When the model "RunMe" is simulated the parameter showBall = false because number <> 1. However, the ball is still visible.
Partial Model setting the object that should appear/disappear:
partial model ballIcon
// input Boolean showBall; // Tried this as well to no avail.
protected
parameter Boolean showBall = true;
annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={
Ellipse(
extent={{-40,40},{40,-40}},
lineColor={0,0,0},
fillPattern=FillPattern.HorizontalCylinder,
fillColor={255,255,0},
visible=showBall)}),
Diagram(coordinateSystem(
preserveAspectRatio=false)));
end ballIcon;
Extending model:
model extendsBallIcon
extends ballIcon(showBall=(number==1));
parameter Real number = 1;
end extendsBallIcon;
Model that should show a ball that appears or disappears based on "number":
model RunMe
extendsBallIcon Ball(number=3)
annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
end RunMe;
Is there something that can be corrected to this approach so the GUI of a component when used (i.e., on the diagram layer) will work? Or do connectors GUI need to capture the flow/not-flow element that is defined by a component to assist in model usage (i.e., change port_a from description design inlet to defined flow variable).
Using Dymola 2017 (tested with the same results on Dymola 2016 as well)
Update:
Knowing the simple case works using DynamicSelect leads me to a real application. The following change appears to cause the icon to not toggle its visiblity.
In extendsBallIcon replacing:
extends ballIcon(showBall=(number==1));
parameter Real number = 1;
with
// Boolean Example
extends ballIcon(showBall=(number==true));
final parameter Boolean number = (modelStructure==Modelica.Fluid.Types.ModelStructure.av_b);
parameter Modelica.Fluid.Types.ModelStructure modelStructure = Modelica.Fluid.Types.ModelStructure.av_b;
Modelica language specification states in section 18.6.6: "Any value (coordinates, color, text, etc) in graphical annotations can be dependent on class variables using the DynamicSelect expression." That is, visible=DynamicSelect(true, showBall) in your example will display the ellipse only if showBall is true.