45. PreAttributeChange

This commit is contained in:
Edward R. Gonzalez 2024-04-24 18:18:26 -04:00
parent 035ad8de6f
commit ef002ccf53
7 changed files with 182 additions and 83 deletions

Binary file not shown.

View File

@ -8,9 +8,9 @@
UGasaAttributeSet::UGasaAttributeSet()
{
InitHealth( 50.f );
InitHealth( 100.f );
InitMaxHealth( 100.f );
InitMana( 25.f );
InitMana( 50.f );
InitMaxMana( 50.f );
}
@ -41,6 +41,27 @@ void UGasaAttributeSet::Client_OnRep_MaxMana( FGameplayAttributeData& PrevMaxMan
}
#pragma endregion Rep Notifies
void UGasaAttributeSet::PreAttributeChange( FGameplayAttribute const& Attribute, float& NewValue )
{
Super::PreAttributeChange( Attribute, NewValue );
if ( Attribute == GetHealthAttribute() )
{
NewValue = FMath::Clamp( NewValue, 0, GetMaxHealth() );
}
if ( Attribute == GetMaxHealthAttribute() )
{
NewValue = FMath::Clamp( NewValue, 0, 99999.000000 );
}
if ( Attribute == GetManaAttribute() )
{
NewValue = FMath::Clamp( NewValue, 0, GetMaxMana() );
}
if ( Attribute == GetMaxManaAttribute() )
{
NewValue = FMath::Clamp( NewValue, 0, 99999.000000 );
}
}
void UGasaAttributeSet::GetLifetimeReplicatedProps( TArray<FLifetimeProperty>& OutLifetimeProps ) const
{
Super::GetLifetimeReplicatedProps( OutLifetimeProps );

View File

@ -9,20 +9,16 @@ class GASA_API UGasaAttributeSet : public UAttributeSet
{
GENERATED_BODY()
public:
UPROPERTY( ReplicatedUsing = Client_OnRep_Health, EditAnywhere, BlueprintReadWrite, Category = "Attributes" )
FGameplayAttributeData Health;
UPROPERTY( ReplicatedUsing = Client_OnRep_MaxHealth, EditAnywhere, BlueprintReadWrite, Category = "Attributes" )
FGameplayAttributeData MaxHealth;
UPROPERTY( ReplicatedUsing = Client_OnRep_Mana, EditAnywhere, BlueprintReadWrite, Category = "Attributes" )
FGameplayAttributeData Mana;
UPROPERTY( ReplicatedUsing = Client_OnRep_MaxMana, EditAnywhere, BlueprintReadWrite, Category = "Attributes" )
FGameplayAttributeData MaxMana;
UGasaAttributeSet();
UPROPERTY( ReplicatedUsing = Client_OnRep_Health, EditAnywhere, BlueprintReadWrite, Category = "Attributes" )
FGameplayAttributeData Health;
UPROPERTY( ReplicatedUsing = Client_OnRep_MaxHealth, EditAnywhere, BlueprintReadWrite, Category = "Attributes" )
FGameplayAttributeData MaxHealth;
UPROPERTY( ReplicatedUsing = Client_OnRep_Mana, EditAnywhere, BlueprintReadWrite, Category = "Attributes" )
FGameplayAttributeData Mana;
UPROPERTY( ReplicatedUsing = Client_OnRep_MaxMana, EditAnywhere, BlueprintReadWrite, Category = "Attributes" )
FGameplayAttributeData MaxMana;
UFUNCTION()
void Client_OnRep_Health( FGameplayAttributeData& PrevHealth );
@ -62,8 +58,7 @@ public:
#pragma endregion Getters
#pragma region Setters
FORCEINLINE void
SetHealth( float NewVal );
FORCEINLINE void SetHealth( float NewVal );
FORCEINLINE void SetMaxHealth( float NewVal );
FORCEINLINE void SetMana( float NewVal );
FORCEINLINE void SetMaxMana( float NewVal );
@ -90,8 +85,11 @@ public:
}
#pragma endregion Setters
#pragma region AttributeSet
void PreAttributeChange( const FGameplayAttribute& Attribute, float& NewValue ) override;
#pragma endregion AttributeSet
#pragma region UObject
void
GetLifetimeReplicatedProps( TArray<FLifetimeProperty>& OutLifetimeProps ) const override;
void GetLifetimeReplicatedProps( TArray<FLifetimeProperty>& OutLifetimeProps ) const override;
#pragma endregion UObject
};

View File

@ -77,6 +77,9 @@ CodeBody parse_file( char const* path ) {
return code;
}
// inline
// CodeConstructor find_constructor( StrC parent_name, )
inline
void format_file( char const* path )
{

View File

@ -4,11 +4,12 @@
#include "gen.hpp"
#include "gen.builder.hpp"
#include "GasaGenCommon.cpp"
#include "GasaGen_UGasaAttributeSet.cpp"
#endif
void gen_UHostWidgetController()
{
Array<StringCached> attribute_fields = get_gasa_attribute_fields();
Array<GAS_AttributeEntry> attribute_fields = get_gasa_attribute_fields();
CodeBody ori_HostWidgetController_header = parse_file(path_gasa_ui "HostWidgetController.h");
{
@ -64,21 +65,21 @@ void gen_UHostWidgetController()
for ( s32 id = 0; id < attribute_fields.num(); ++id )
{
StringCached attribute_field = attribute_fields[id];
GAS_AttributeEntry attribute_field = attribute_fields[id];
attribute_events.append( code_str(
UPROPERTY(BlueprintAssignable, Category = "Attributes")
));
attribute_events.append(fmt_newline);
attribute_events.append( parse_variable(
token_fmt( "field", (StrC) attribute_field, stringize( FAttributeFloatChangedSig Event_On<field>Changed; ))
token_fmt( "field", (StrC) attribute_field.Name, stringize( FAttributeFloatChangedSig Event_On<field>Changed; ))
));
attribute_events.append(fmt_newline);
}
for ( s32 id = 0; id < attribute_fields.num(); ++id )
{
StringCached attribute_field = attribute_fields[id];
StringCached attribute_field = attribute_fields[id].Name;
attribute_events.append( parse_function(
token_fmt( "field", (StrC) attribute_field, stringize( void <field>Changed(FOnAttributeChangeData const& Data); ))
@ -154,9 +155,9 @@ void gen_UHostWidgetController()
CodeFn BroadcastInitialValues = NoCode;
{
CodeBody broadcast_calls = def_body(ECode::Function_Body);
for (StringCached field : attribute_fields)
for (GAS_AttributeEntry field : attribute_fields)
{
broadcast_calls.append( code_fmt( "field", (StrC)field,
broadcast_calls.append( code_fmt( "field", (StrC)field.Name,
stringize( Event_On<field>Changed.Broadcast( GasaAttribs->Get<field>() ); )
));
}
@ -185,9 +186,9 @@ void gen_UHostWidgetController()
CodeBody bindings = def_body(ECode::Function_Body);
bindings.append(fmt_newline);
bindings.append(fmt_newline);
for (StringCached field : attribute_fields)
for (GAS_AttributeEntry field : attribute_fields)
{
bindings.append( code_fmt( "field", (StrC)field,
bindings.append( code_fmt( "field", (StrC)field.Name,
stringize(
FOnGameplayAttributeValueChange& <field>AttributeChangedDelegate = AbilitySystem->GetGameplayAttributeValueChangeDelegate(GasaAttribs->Get<field>Attribute());
<field>AttributeChangedDelegate.AddUObject(this, &ThisClass::<field>Changed);
@ -219,7 +220,7 @@ void gen_UHostWidgetController()
for ( s32 id = 0; id < attribute_fields.num(); )
{
StringCached attribute_field = attribute_fields[id];
StringCached attribute_field = attribute_fields[id].Name;
attribute_callbacks.append( parse_function( token_fmt(
"field", (StrC) attribute_field,

View File

@ -7,25 +7,44 @@
#include "GasaGenCommon.cpp"
#endif
void def_attribute_properties ( CodeBody body, Array<StringCached> properties );
void def_attribute_field_on_reps ( CodeBody body, Array<StringCached> properties );
void def_attribute_field_property_getters ( CodeBody body, StrC class_name, Array<StringCached> properties );
void def_attribute_field_value_getters ( CodeBody body, Array<StringCached> properties );
void def_attribute_field_value_setters ( CodeBody body, Array<StringCached> properties );
void def_attribute_field_property_setter_inlines( CodeBody body, StrC class_name, Array<StringCached> properties );
void def_attribute_field_initers ( CodeBody body, Array<StringCached> properties );
void impl_attribute_fields ( CodeBody body, StrC class_name, Array<StringCached> properties );
struct GAS_AttributeEntry
{
StringCached Name;
StringCached MinName;
StringCached MaxName;
float Min;
float Max;
};
Array<StringCached> get_gasa_attribute_fields()
void def_attribute_properties ( CodeBody body, Array<GAS_AttributeEntry> properties );
void def_attribute_field_on_reps ( CodeBody body, Array<GAS_AttributeEntry> properties );
void def_attribute_field_property_getters ( CodeBody body, StrC class_name, Array<GAS_AttributeEntry> properties );
void def_attribute_field_value_getters ( CodeBody body, Array<GAS_AttributeEntry> properties );
void def_attribute_field_value_setters ( CodeBody body, Array<GAS_AttributeEntry> properties );
void def_attribute_field_property_setter_inlines( CodeBody body, StrC class_name, Array<GAS_AttributeEntry> properties );
void def_attribute_field_initers ( CodeBody body, Array<GAS_AttributeEntry> properties );
void impl_attribute_fields ( CodeBody body, StrC class_name, Array<GAS_AttributeEntry> properties );
Array<GAS_AttributeEntry> get_gasa_attribute_fields()
{
local_persist
Array<StringCached> attribute_fields = Array<StringCached>::init_reserve(GlobalAllocator, 64);
Array<GAS_AttributeEntry> attribute_fields = Array<GAS_AttributeEntry>::init_reserve(GlobalAllocator, 64);
for (local_persist s32 do_once = 0; do_once == 0; ++ do_once) {
attribute_fields.append( get_cached_string(txt("Health")));
attribute_fields.append( get_cached_string(txt("MaxHealth")));
attribute_fields.append( get_cached_string(txt("Mana")));
attribute_fields.append( get_cached_string(txt("MaxMana")));
StringCached str_Health = get_cached_string(txt("Health"));
StringCached str_MaxHealth = get_cached_string(txt("MaxHealth"));
StringCached str_Mana = get_cached_string(txt("Mana"));
StringCached str_MaxMana = get_cached_string(txt("MaxMana"));
GAS_AttributeEntry Health = { str_Health, {nullptr}, str_MaxHealth, 0, 100.f };
GAS_AttributeEntry MaxHealth = { str_MaxHealth, {nullptr}, {nullptr}, 0, 99999.f };
GAS_AttributeEntry Mana = { str_Mana, {nullptr}, str_MaxMana, 0, 50.f };
GAS_AttributeEntry MaxMana = { str_MaxMana, {nullptr}, {nullptr}, 0, 99999.f };
attribute_fields.append(Health);
attribute_fields.append(MaxHealth);
attribute_fields.append(Mana);
attribute_fields.append(MaxMana);
}
return attribute_fields;
}
@ -35,7 +54,7 @@ void gen_UGasaAttributeSet()
CodeType type_UAttributeSet = def_type( txt("UAttributeSet") );
CodeComment generation_notice = def_comment(txt("Generated by GasaGen/GasaGen_UGasaAttributeSet.cpp"));
Array<StringCached> attribute_fields = get_gasa_attribute_fields();
Array<GAS_AttributeEntry> attribute_fields = get_gasa_attribute_fields();
StrC class_name = txt("UGasaAttributeSet");
@ -57,30 +76,37 @@ void gen_UGasaAttributeSet()
body.append( UHT_GENERATED_BODY);
body.append( access_public );
def_attribute_properties( body, attribute_fields);
body.append(fmt_newline);
body.append( def_constructor() );
body.append(fmt_newline);
def_attribute_properties( body, attribute_fields);
body.append(fmt_newline);
def_attribute_field_on_reps( body, attribute_fields);
body.append(fmt_newline);
body.append( fmt_newline );
body.append( def_pragma(code( region Getters )));
body.append( def_pragma(txt( "region Getters" )));
def_attribute_field_property_getters( body, class_name, attribute_fields );
body.append( fmt_newline );
def_attribute_field_value_getters( body, attribute_fields );
body.append( def_pragma(code( endregion Getters )));
body.append( def_pragma(txt( "endregion Getters" )));
body.append( fmt_newline );
body.append( def_pragma(code( region Setters )));
body.append( def_pragma(txt( "region Setters" )));
def_attribute_field_value_setters( body, attribute_fields );
body.append( fmt_newline );
body.append( fmt_newline );
def_attribute_field_initers( body, attribute_fields );
body.append( def_pragma(code( endregion Setters )));
body.append( def_pragma(txt( "endregion Setters" )));
body.append( fmt_newline );
body.append( def_pragma( txt("region AttributeSet")));
body.append( code_str(
void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
// void PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue) override;
));
body.append( def_pragma( txt("endregion AttributeSet")));
body.append(fmt_newline);
body.append( def_pragma( txt("region UObject")));
@ -165,14 +191,54 @@ void gen_UGasaAttributeSet()
impl_attribute_fields( body, class_name, attribute_fields);
CodeFn PreAttributeChange;
{
CodeBody attribute_clamps = def_body( CodeT::Function_Body );
attribute_clamps.append(fmt_newline);
attribute_clamps.append(fmt_newline);
for (GAS_AttributeEntry field : attribute_fields)
{
String clamp_min;
if (field.MinName.Data)
clamp_min = get_cached_string(token_fmt( "MinName", (StrC)field.MinName, "Get<MinName>()"));
else
clamp_min = String::fmt_buf(GlobalAllocator, "%f", field.Min);
String clamp_max;
if (field.MaxName.Data)
clamp_max = get_cached_string(token_fmt( "MaxName", (StrC)field.MaxName, "Get<MaxName>()"));
else
clamp_max = String::fmt_buf(GlobalAllocator, "%f", field.Max);
attribute_clamps.append( code_fmt(
"field", (StrC)field.Name,
"clamp_min", (StrC)clamp_min,
"clamp_max", (StrC)clamp_max,
stringize(
if (Attribute == Get<field>Attribute())
{
NewValue = FMath::Clamp(NewValue, <clamp_min>, <clamp_max>);
}
)));
}
PreAttributeChange = parse_function( token_fmt( "attribute_clamps", (StrC)attribute_clamps.to_string(), stringize(
void UGasaAttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{
Super::PreAttributeChange(Attribute, NewValue);
<attribute_clamps>
}
)));
}
body.append(PreAttributeChange);
CodeFn GetLifetimeOfReplicatedProps;
{
CodeBody field_lifetimes = def_body( CodeT::Function_Body);
field_lifetimes.append(fmt_newline);
field_lifetimes.append(fmt_newline);
for (StringCached field : attribute_fields)
for (GAS_AttributeEntry field : attribute_fields)
{
field_lifetimes.append( code_fmt( "field", (StrC)field, stringize(
field_lifetimes.append( code_fmt( "field", (StrC)field.Name, stringize(
DOREPLIFETIME_DEFAULT_GAS(UGasaAttributeSet, <field>);
)));
}
@ -194,44 +260,39 @@ void gen_UGasaAttributeSet()
}
}
void def_attribute_properties( CodeBody body, Array<StringCached> properties )
void def_attribute_properties( CodeBody body, Array<GAS_AttributeEntry> properties )
{
for ( StringCached property : properties )
for ( GAS_AttributeEntry property : properties )
{
Code field_uproperty = code_fmt( "property", (StrC)property, stringize(
Code field_uproperty = code_fmt( "property", (StrC)property.Name, stringize(
UPROPERTY(ReplicatedUsing=Client_OnRep_<property>, EditAnywhere, BlueprintReadWrite, Category="Attributes")
FGameplayAttributeData <property>;
));
CodeType type_FGameplayAttributeData = def_type( txt("FGameplayAttributeData"));
body.append(fmt_newline);
body.append(field_uproperty);
body.append(fmt_newline);
body.append( def_variable( type_FGameplayAttributeData, StrC(property)) );
}
}
void def_attribute_field_on_reps( CodeBody body, Array<StringCached> properties )
void def_attribute_field_on_reps( CodeBody body, Array<GAS_AttributeEntry> properties )
{
for ( StringCached property : properties )
for ( GAS_AttributeEntry property : properties )
{
Code umeta_UFUNCTION = code_str( UFUNCTION() );
body.append(fmt_newline);
body.append( umeta_UFUNCTION );
body.append(fmt_newline);
body.append( code_fmt( "property", (StrC)property, stringize(
body.append( code_fmt( "property", (StrC)property.Name, stringize(
void Client_OnRep_<property>(FGameplayAttributeData& Prev<property>);
)));
}
}
void def_attribute_field_property_getters( CodeBody body, StrC class_name, Array<StringCached> properties )
void def_attribute_field_property_getters( CodeBody body, StrC class_name, Array<GAS_AttributeEntry> properties )
{
for ( String property : properties )
for ( GAS_AttributeEntry property : properties )
{
CodeFn generated_get_attribute = parse_function(
token_fmt( "class_name", class_name, "property", (StrC)property,
token_fmt( "class_name", class_name, "property", (StrC)property.Name,
stringize(
static FGameplayAttribute Get<property>Attribute()
{
@ -245,11 +306,11 @@ void def_attribute_field_property_getters( CodeBody body, StrC class_name, Array
#pragma push_macro("FORCEINLINE")
#undef FORCEINLINE
void def_attribute_field_value_getters( CodeBody body, Array<StringCached> properties )
void def_attribute_field_value_getters( CodeBody body, Array<GAS_AttributeEntry> properties )
{
for ( String property : properties )
for ( GAS_AttributeEntry property : properties )
{
body.append( code_fmt( "property", (StrC)property,
body.append( code_fmt( "property", (StrC)property.Name,
stringize(
FORCEINLINE float Get<property>() const
{
@ -259,24 +320,24 @@ void def_attribute_field_value_getters( CodeBody body, Array<StringCached> prope
}
}
void def_attribute_field_value_setters( CodeBody body, Array<StringCached> properties )
void def_attribute_field_value_setters( CodeBody body, Array<GAS_AttributeEntry> properties )
{
for ( String property : properties )
for ( GAS_AttributeEntry property : properties )
{
body.append( code_fmt( "property", (StrC)property,
body.append( code_fmt( "property", (StrC)property.Name,
stringize(
FORCEINLINE void Set<property>(float NewVal);
)));
}
}
void def_attribute_field_property_setter_inlines( CodeBody body, StrC class_name, Array<StringCached> properties )
void def_attribute_field_property_setter_inlines( CodeBody body, StrC class_name, Array<GAS_AttributeEntry> properties )
{
body.append(def_pragma( txt("region Attribute Setters")));
for ( String property : properties )
for ( GAS_AttributeEntry property : properties )
{
CodeFn generated_get_attribute = parse_function(
token_fmt( "class_name", class_name, "property", (StrC)property,
token_fmt( "class_name", class_name, "property", (StrC)property.Name,
stringize(
FORCEINLINE void <class_name>::Set<property>(float NewVal)
{
@ -292,11 +353,11 @@ void def_attribute_field_property_setter_inlines( CodeBody body, StrC class_name
body.append(def_pragma( txt("endregion Attribute Setters")));
}
void def_attribute_field_initers ( CodeBody body, Array<StringCached> properties )
void def_attribute_field_initers ( CodeBody body, Array<GAS_AttributeEntry> properties )
{
for ( String property : properties )
for ( GAS_AttributeEntry property : properties )
{
body.append( code_fmt( "property", (StrC)property,
body.append( code_fmt( "property", (StrC)property.Name,
stringize(
FORCEINLINE void Init<property>(float NewVal)
{
@ -307,14 +368,14 @@ void def_attribute_field_initers ( CodeBody body, Array<StringCached> properties
}
}
void impl_attribute_fields( CodeBody body, StrC class_name, Array<StringCached> properties )
void impl_attribute_fields( CodeBody body, StrC class_name, Array<GAS_AttributeEntry> properties )
{
body.append(fmt_newline);
body.append(def_pragma( txt("region Rep Notifies")));
for ( String property : properties )
for ( GAS_AttributeEntry property : properties )
{
CodeFn field_impl = parse_function( token_fmt(
"class_name", class_name, "property", (StrC)property, "from_notice", txt("\n// From GAMEPLAYATTRIBUTE_REPNOTIFY\n"),
"class_name", class_name, "property", (StrC)property.Name, "from_notice", txt("\n// From GAMEPLAYATTRIBUTE_REPNOTIFY\n"),
stringize(
void <class_name>::Client_OnRep_<property>(FGameplayAttributeData& Prev<property>)
{

View File

@ -55,6 +55,21 @@
</Expand>
</Type>
<Type Name="gen::StringCached">
<DisplayString Condition="Data == nullptr">null</DisplayString>
<DisplayString>{Data,na}</DisplayString>
<Expand>
<Synthetic Name="Header">
<DisplayString>{(Header*)((char*)Data - sizeof(Header))}</DisplayString>
<Expand>
<Item Name="Allocator">((Header*)((char*)Data - sizeof(Header)))->Allocator</Item>
<Item Name="Capacity">((Header*)((char*)Data - sizeof(Header)))->Capacity</Item>
<Item Name="Length">((Header*)((char*)Data - sizeof(Header)))->Length</Item>
</Expand>
</Synthetic>
</Expand>
</Type>
<Type Name="gen::String::Header">
<DisplayString>Length: {Length}, Capacity: {Capacity}</DisplayString>
<Expand>