// Used in the GasaGen.cpp translation unit #if GASA_INTELLISENSE_DIRECTIVES #pragma once #define GEN_EXPOSE_BACKEND #include "gen.hpp" #include "gen.builder.hpp" #include "GasaGenCommon.cpp" #endif struct GAS_AttributeEntry { StringCached Name; // StringCached Description; // StringCached Category; StringCached MinName; StringCached MaxName; float Min; float Max; }; void def_attribute_properties ( CodeBody body, Array properties ); void def_attribute_field_on_reps ( CodeBody body, Array properties ); void def_attribute_field_property_getters ( CodeBody body, StrC class_name, Array properties ); void def_attribute_field_value_getters ( CodeBody body, Array properties ); void def_attribute_field_value_setters ( CodeBody body, Array properties ); void def_attribute_field_property_setter_inlines( CodeBody body, StrC class_name, Array properties ); void def_attribute_field_initers ( CodeBody body, Array properties ); void impl_attribute_fields ( CodeBody body, StrC class_name, Array properties ); Array get_gasa_primary_attribute_fields() { local_persist Array attribute_fields = Array::init_reserve(GlobalAllocator, 64); for (local_persist s32 do_once = 0; do_once == 0; ++ do_once) { StringCached str_Strength = get_cached_string(txt("Strength")); StringCached str_Intelligence = get_cached_string(txt("Intelligence")); StringCached str_Resilience = get_cached_string(txt("Resilience")); StringCached str_Vigor = get_cached_string(txt("Vigor")); GAS_AttributeEntry Strength = { str_Strength, {nullptr}, {nullptr}, 0, 999.f }; GAS_AttributeEntry Intelligence = { str_Intelligence, {nullptr}, {nullptr}, 0, 999.f }; GAS_AttributeEntry Resilience = { str_Resilience, {nullptr}, {nullptr}, 0, 999.f }; GAS_AttributeEntry Vigor = { str_Vigor, {nullptr}, {nullptr}, 0, 999.f }; attribute_fields.append(Strength); attribute_fields.append(Intelligence); attribute_fields.append(Resilience); attribute_fields.append(Vigor); } return attribute_fields; } Array get_gasa_secondary_attribute_fields() { local_persist Array attribute_fields = Array::init_reserve(GlobalAllocator, 64); for (local_persist s32 do_once = 0; do_once == 0; ++ do_once) { // StringCached str_Strength = get_cached_string(txt("Strength")); // StringCached str_Intelligence = get_cached_string(txt("Intelligence")); // StringCached str_Resilience = get_cached_string(txt("Resilience")); // StringCached str_Vigor = get_cached_string(txt("Vigor")); // // 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 }; } return attribute_fields; } Array get_gasa_vital_attribute_fields() { local_persist Array attribute_fields = Array::init_reserve(GlobalAllocator, 64); for (local_persist s32 do_once = 0; do_once == 0; ++ do_once) { 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; } void gen_UGasaAttributeSet() { CodeType type_UAttributeSet = def_type( txt("UAttributeSet") ); CodeComment generation_notice = def_comment(txt("Generated by GasaGen/GasaGen_UGasaAttributeSet.cpp")); Array primary_attribute_fields = get_gasa_primary_attribute_fields(); Array secondary_attribute_fields = get_gasa_secondary_attribute_fields(); Array vital_attribute_fields = get_gasa_vital_attribute_fields(); s32 all_attrib_count = primary_attribute_fields.num() + secondary_attribute_fields.num() + vital_attribute_fields.num(); Array< GAS_AttributeEntry> all_attribute_fields = Array::init_reserve(GlobalAllocator, all_attrib_count); all_attribute_fields.append( primary_attribute_fields); all_attribute_fields.append( secondary_attribute_fields); all_attribute_fields.append( vital_attribute_fields); StrC class_name = txt("UGasaAttributeSet"); Builder header = Builder::open( path_gasa_ability_system "GasaAttributeSet.h"); { header.print(generation_notice); header.print(pragma_once); header.print(fmt_newline); { CodeInclude Include_AttributeSet = def_include(txt("AttributeSet.h")); CodeInclude Include_GasaAttributeSet_Generated = def_include(txt("GasaAttributeSet.generated.h")); CodeAttributes api_attribute = def_attributes( UModule_GASA_API->Name); CodeClass GasaAttributeSet = {}; { CodeBody body = def_body( CodeT::Class_Body ); { body.append( UHT_GENERATED_BODY); body.append( access_public ); body.append( def_constructor() ); body.append(fmt_newline); body.append( def_comment(txt("Primary Attribute Fields"))); body.append(fmt_newline); def_attribute_properties( body, primary_attribute_fields); body.append(fmt_newline); body.append(fmt_newline); // body.append( def_comment(txt("Secondary Attribute Fields"))); // body.append(fmt_newline); // def_attribute_properties( body, secondary_attribute_fields); // body.append(fmt_newline); // body.append(fmt_newline); body.append( def_comment(txt("Vital Attribute Fields"))); body.append(fmt_newline); def_attribute_properties( body, vital_attribute_fields); body.append(fmt_newline); def_attribute_field_on_reps( body, primary_attribute_fields); def_attribute_field_on_reps( body, secondary_attribute_fields); def_attribute_field_on_reps( body, vital_attribute_fields); body.append(fmt_newline); body.append( fmt_newline ); body.append( def_pragma(txt( "region Getters" ))); def_attribute_field_property_getters( body, class_name, primary_attribute_fields ); def_attribute_field_property_getters( body, class_name, secondary_attribute_fields ); def_attribute_field_property_getters( body, class_name, vital_attribute_fields ); body.append( fmt_newline ); def_attribute_field_value_getters( body, primary_attribute_fields ); def_attribute_field_value_getters( body, secondary_attribute_fields ); def_attribute_field_value_getters( body, vital_attribute_fields ); body.append( def_pragma(txt( "endregion Getters" ))); body.append( fmt_newline ); body.append( def_pragma(txt( "region Setters" ))); def_attribute_field_value_setters( body, primary_attribute_fields ); def_attribute_field_value_setters( body, secondary_attribute_fields ); def_attribute_field_value_setters( body, vital_attribute_fields ); body.append( fmt_newline ); body.append( fmt_newline ); def_attribute_field_initers( body, primary_attribute_fields ); def_attribute_field_initers( body, secondary_attribute_fields ); def_attribute_field_initers( body, vital_attribute_fields ); 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 PostGameplayEffectExecute(FGameplayEffectModCallbackData const& Data) override; )); body.append( def_pragma( txt("endregion AttributeSet"))); body.append(fmt_newline); body.append( def_pragma( txt("region UObject"))); CodeFn GetLifetimeOfReplicatedProps = parse_function( code( void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; )); body.append( GetLifetimeOfReplicatedProps ); body.append( def_pragma( txt("endregion UObject"))); } GasaAttributeSet = def_class( class_name, body , type_UAttributeSet, AccessSpec::Public , api_attribute ); } header.print( Include_AttributeSet); header.print( Include_GasaAttributeSet_Generated); header.print( fmt_newline); header.print( UHT_UCLASS ); header.print(GasaAttributeSet); } header.write(); format_file(path_gasa_ability_system "GasaAttributeSet.h"); } Builder inlines = Builder::open( path_gasa_ability_system "GasaAttributeSet_Inlines.h"); { inlines.print(generation_notice); inlines.print(pragma_once); inlines.print(fmt_newline); inlines.print( def_include( txt("GasaAttributeSet.h"))); inlines.print( def_include(txt("AbilitySystemComponent.h"))); inlines.print(fmt_newline); CodeBody body = def_body(CodeT::Global_Body); { def_attribute_field_property_setter_inlines( body, class_name, all_attribute_fields ); } inlines.print(body); inlines.print(fmt_newline); CodeNS ns_gasa = parse_namespace( code( namespace Gasa { inline UGasaAttributeSet const* GetAttributeSet( UAbilitySystemComponent* ASC ) { return Cast(ASC->GetAttributeSet( UGasaAttributeSet::StaticClass() )); } } )); inlines.print(ns_gasa); inlines.write(); format_file(path_gasa_ability_system "GasaAttributeSet_Inlines.h"); } Builder source = Builder::open( path_gasa_ability_system "GasaAttributeSet.cpp" ); { source.print(generation_notice); header.print(fmt_newline); source.print( def_include( txt("GasaAttributeSet.h"))); source.print( def_include( txt("GasaAttributeSet_Inlines.h"))); source.print( def_include( txt("EffectProperties.h"))); source.print(fmt_newline); source.print( def_include( txt("AbilitySystemComponent.h"))); source.print( def_include( txt("Net/UnrealNetwork.h"))); source.print( def_include( txt("Networking/GasaNetLibrary.h"))); source.print( def_include( txt("GameplayEffectExtension.h"))); { CodeBody body = def_body( CodeT::Global_Body ); body.append(fmt_newline); CodeConstructor constructor_for_UGasaAttributeSet = parse_constructor( code( UGasaAttributeSet::UGasaAttributeSet() { InitHealth( 100.f ); InitMaxHealth( 100.f ); InitMana( 50.f ); InitMaxMana( 50.f ); } )); body.append(constructor_for_UGasaAttributeSet ); impl_attribute_fields( body, class_name, all_attribute_fields); CodeFn PostGameplayEffectExecute; CodeFn PreAttributeChange; { CodeBody pre_attribute_clamps = def_body( CodeT::Function_Body ); pre_attribute_clamps.append(fmt_newline); pre_attribute_clamps.append(fmt_newline); CodeBody post_attribute_clamps = def_body( CodeT::Function_Body ); post_attribute_clamps.append(fmt_newline); post_attribute_clamps.append(fmt_newline); for (GAS_AttributeEntry field : all_attribute_fields) { String clamp_min; if (field.MinName.Data) clamp_min = get_cached_string(token_fmt( "MinName", (StrC)field.MinName, "Get()")); 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()")); else clamp_max = String::fmt_buf(GlobalAllocator, "%f", field.Max); pre_attribute_clamps.append( code_fmt( "field", (StrC)field.Name, "clamp_min", (StrC)clamp_min, "clamp_max", (StrC)clamp_max, stringize( if (Attribute == GetAttribute()) { NewValue = FMath::Clamp(NewValue, , ); } ))); post_attribute_clamps.append( code_fmt( "field", (StrC)field.Name, "clamp_min", (StrC)clamp_min, "clamp_max", (StrC)clamp_max, stringize( if ( Data.EvaluatedData.Attribute == GetAttribute() ) { Set(FMath::Clamp(Get(), , )); } ))); } pre_attribute_clamps.append(fmt_newline); pre_attribute_clamps.append(fmt_newline); post_attribute_clamps.append(fmt_newline); post_attribute_clamps.append(fmt_newline); PreAttributeChange = parse_function( token_fmt( "attribute_clamps", (StrC)pre_attribute_clamps.to_string(), stringize( void UGasaAttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) { Super::PreAttributeChange(Attribute, NewValue); PreAttributeChange_Custom(); } ))); PostGameplayEffectExecute = parse_function( token_fmt( "attribute_clamps", (StrC)post_attribute_clamps.to_string(), stringize( void UGasaAttributeSet::PostGameplayEffectExecute(FGameplayEffectModCallbackData const& Data) { Super::PostGameplayEffectExecute(Data); FEffectProperties Props; Props.Populate(Data); PostAttributeChange_Custom(); } ))); } body.append(PostGameplayEffectExecute); body.append(fmt_newline); body.append(PreAttributeChange); body.append(fmt_newline); CodeFn GetLifetimeOfReplicatedProps; { CodeBody field_lifetimes = def_body( CodeT::Function_Body); field_lifetimes.append(fmt_newline); field_lifetimes.append(fmt_newline); for (GAS_AttributeEntry field : all_attribute_fields) { field_lifetimes.append( code_fmt( "field", (StrC)field.Name, stringize( DOREPLIFETIME_DEFAULT_GAS(UGasaAttributeSet, ); ))); } GetLifetimeOfReplicatedProps = parse_function( token_fmt( "field_lifetimes", (StrC)(field_lifetimes.to_string()), stringize( void UGasaAttributeSet::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); } ))); } body.append(GetLifetimeOfReplicatedProps); source.print(body); } source.write(); format_file(path_gasa_ability_system "GasaAttributeSet.cpp"); } } void def_attribute_properties( CodeBody body, Array properties ) { for ( GAS_AttributeEntry property : properties ) { Code field_uproperty = code_fmt( "property", (StrC)property.Name, stringize( UPROPERTY(ReplicatedUsing=Client_OnRep_, EditAnywhere, BlueprintReadWrite, Category="Attributes") FGameplayAttributeData ; )); body.append(field_uproperty); } } void def_attribute_field_on_reps( CodeBody body, Array 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.Name, stringize( void Client_OnRep_(FGameplayAttributeData& Prev); ))); } } void def_attribute_field_property_getters( CodeBody body, StrC class_name, Array properties ) { for ( GAS_AttributeEntry property : properties ) { CodeFn generated_get_attribute = parse_function( token_fmt( "class_name", class_name, "property", (StrC)property.Name, stringize( static FGameplayAttribute GetAttribute() { static FProperty* Prop = FindFieldChecked(::StaticClass(), GET_MEMBER_NAME_CHECKED(, )); return Prop; } ))); body.append( generated_get_attribute ); } } #pragma push_macro("FORCEINLINE") #undef FORCEINLINE void def_attribute_field_value_getters( CodeBody body, Array properties ) { for ( GAS_AttributeEntry property : properties ) { body.append( code_fmt( "property", (StrC)property.Name, stringize( FORCEINLINE float Get() const { return .GetCurrentValue(); } ))); } } void def_attribute_field_value_setters( CodeBody body, Array properties ) { for ( GAS_AttributeEntry property : properties ) { body.append( code_fmt( "property", (StrC)property.Name, stringize( FORCEINLINE void Set(float NewVal); ))); } } void def_attribute_field_property_setter_inlines( CodeBody body, StrC class_name, Array properties ) { body.append(def_pragma( txt("region Attribute Setters"))); for ( GAS_AttributeEntry property : properties ) { CodeFn generated_get_attribute = parse_function( token_fmt( "class_name", class_name, "property", (StrC)property.Name, stringize( FORCEINLINE void ::Set(float NewVal) { UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent(); if (ensure(AbilityComp)) { AbilityComp->SetNumericAttributeBase(GetAttribute(), NewVal); }; } ))); body.append( generated_get_attribute ); } body.append(def_pragma( txt("endregion Attribute Setters"))); } void def_attribute_field_initers ( CodeBody body, Array properties ) { for ( GAS_AttributeEntry property : properties ) { body.append( code_fmt( "property", (StrC)property.Name, stringize( FORCEINLINE void Init(float NewVal) { .SetBaseValue(NewVal); .SetCurrentValue(NewVal); } ))); } } void impl_attribute_fields( CodeBody body, StrC class_name, Array properties ) { body.append(fmt_newline); body.append(def_pragma( txt("region Rep Notifies"))); for ( GAS_AttributeEntry property : properties ) { CodeFn field_impl = parse_function( token_fmt( "class_name", class_name, "property", (StrC)property.Name, "from_notice", txt("\n// From GAMEPLAYATTRIBUTE_REPNOTIFY\n"), stringize( void ::Client_OnRep_(FGameplayAttributeData& Prev) { static FProperty* Property = FindFieldChecked( StaticClass(), GET_MEMBER_NAME_CHECKED(, )); GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication(FGameplayAttribute(Property), , Prev); } ))); body.append( field_impl ); } body.append( def_pragma( txt("endregion Rep Notifies"))); body.append(fmt_newline); } inline Code gen_GAMEPLAYATTRIBUTE_REPNOTIFY(StrC class_name, StrC property_name, StrC old_value) { Code rep_notify = code_fmt( "class_name", class_name , "property_name", property_name , "old_value", old_value, stringize( static FProperty* Property = FindFieldChecked(::StaticClass(), GET_MEMBER_NAME_CHECKED(, )); GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication(FGameplayAttribute(Property), , ); )); } #pragma pop_macro("FORCEINLINE")