422 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			422 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // 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 MinName;
 | |
| 	StringCached MaxName;
 | |
| 	float Min;
 | |
| 	float Max;
 | |
| };
 | |
| 
 | |
| 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<GAS_AttributeEntry> attribute_fields = Array<GAS_AttributeEntry>::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<GAS_AttributeEntry> attribute_fields = get_gasa_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);
 | |
| 
 | |
| 					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(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(txt( "endregion Getters" )));
 | |
| 					body.append( fmt_newline );
 | |
| 
 | |
| 					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(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<FLifetimeProperty>& 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, 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<UGasaAttributeSet>(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")));
 | |
| 		{
 | |
| 			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, attribute_fields);
 | |
| 
 | |
| 			Code PostGameplayEffectExecute = parse_function( code(
 | |
| 				void UGasaAttributeSet::PostGameplayEffectExecute(FGameplayEffectModCallbackData const& Data)
 | |
| 				{
 | |
| 					Super::PostGameplayEffectExecute(Data);
 | |
| 					FEffectProperties Props;
 | |
| 					Props.Populate(Data);
 | |
| 				}
 | |
| 			));
 | |
| 			body.append(PostGameplayEffectExecute);
 | |
| 			body.append(fmt_newline);
 | |
| 
 | |
| 			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>);
 | |
| 						}
 | |
| 					)));
 | |
| 				}
 | |
| 				attribute_clamps.append(fmt_newline);
 | |
| 				attribute_clamps.append(fmt_newline);
 | |
| 				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);
 | |
| 			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 : attribute_fields)
 | |
| 				{
 | |
| 					field_lifetimes.append( code_fmt( "field", (StrC)field.Name, stringize(
 | |
| 						DOREPLIFETIME_DEFAULT_GAS(UGasaAttributeSet, <field>);
 | |
| 					)));
 | |
| 				}
 | |
| 
 | |
| 				GetLifetimeOfReplicatedProps = parse_function( token_fmt( "field_lifetimes", (StrC)(field_lifetimes.to_string()), stringize(
 | |
| 					void UGasaAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
 | |
| 					{
 | |
| 						Super::GetLifetimeReplicatedProps(OutLifetimeProps);
 | |
| 						<field_lifetimes>
 | |
| 					}
 | |
| 				)));
 | |
| 			}
 | |
| 			body.append(GetLifetimeOfReplicatedProps);
 | |
| 
 | |
| 			source.print(body);
 | |
| 		}
 | |
| 		source.write();
 | |
| 		format_file(path_gasa_ability_system "GasaAttributeSet.cpp");
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void def_attribute_properties( CodeBody body, Array<GAS_AttributeEntry> properties )
 | |
| {
 | |
| 	for ( GAS_AttributeEntry property : properties )
 | |
| 	{
 | |
| 		Code field_uproperty = code_fmt( "property", (StrC)property.Name, stringize(
 | |
| 			UPROPERTY(ReplicatedUsing=Client_OnRep_<property>, EditAnywhere, BlueprintReadWrite, Category="Attributes")
 | |
| 			FGameplayAttributeData <property>;
 | |
| 		));
 | |
| 		body.append(field_uproperty);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void def_attribute_field_on_reps( CodeBody body, Array<GAS_AttributeEntry> 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_<property>(FGameplayAttributeData& Prev<property>);
 | |
| 		)));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void def_attribute_field_property_getters( CodeBody body, StrC class_name, Array<GAS_AttributeEntry> 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 Get<property>Attribute()
 | |
| 				{
 | |
| 					static FProperty* Prop = FindFieldChecked<FProperty>(<class_name>::StaticClass(), GET_MEMBER_NAME_CHECKED(<class_name>, <property>));
 | |
| 					return Prop;
 | |
| 				}
 | |
| 			)));
 | |
| 		body.append( generated_get_attribute );
 | |
| 	}
 | |
| }
 | |
| 
 | |
| #pragma push_macro("FORCEINLINE")
 | |
| #undef FORCEINLINE
 | |
| void def_attribute_field_value_getters( CodeBody body, Array<GAS_AttributeEntry> properties )
 | |
| {
 | |
| 	for ( GAS_AttributeEntry property : properties )
 | |
| 	{
 | |
| 		body.append( code_fmt( "property", (StrC)property.Name,
 | |
| 		stringize(
 | |
| 			FORCEINLINE float Get<property>() const
 | |
| 			{
 | |
| 				return <property>.GetCurrentValue();
 | |
| 			}
 | |
| 		)));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void def_attribute_field_value_setters( CodeBody body, Array<GAS_AttributeEntry> properties )
 | |
| {
 | |
| 	for ( GAS_AttributeEntry property : properties )
 | |
| 	{
 | |
| 		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<GAS_AttributeEntry> 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 <class_name>::Set<property>(float NewVal)
 | |
| 				{
 | |
| 					UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();
 | |
| 					if (ensure(AbilityComp))
 | |
| 					{
 | |
| 						AbilityComp->SetNumericAttributeBase(Get<property>Attribute(), NewVal);
 | |
| 					};
 | |
| 				}
 | |
| 			)));
 | |
| 		body.append( generated_get_attribute );
 | |
| 	}
 | |
| 	body.append(def_pragma( txt("endregion Attribute Setters")));
 | |
| }
 | |
| 
 | |
| void def_attribute_field_initers ( CodeBody body, Array<GAS_AttributeEntry> properties )
 | |
| {
 | |
| 	for ( GAS_AttributeEntry property : properties )
 | |
| 	{
 | |
| 		body.append( code_fmt( "property", (StrC)property.Name,
 | |
| 		stringize(
 | |
| 			FORCEINLINE void Init<property>(float NewVal)
 | |
| 			{
 | |
| 				<property>.SetBaseValue(NewVal);
 | |
| 				<property>.SetCurrentValue(NewVal);
 | |
| 			}
 | |
| 		)));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 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 ( 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 <class_name>::Client_OnRep_<property>(FGameplayAttributeData& Prev<property>)
 | |
| 			{
 | |
| 				<from_notice>
 | |
| 				static FProperty* <class_name>Property = FindFieldChecked<FProperty>( StaticClass(), GET_MEMBER_NAME_CHECKED(<class_name>, <property>));
 | |
| 				GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication(FGameplayAttribute(<class_name>Property), <property>, Prev<property>);
 | |
| 			}
 | |
| 		)));
 | |
| 
 | |
| 		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* <class_name>Property = FindFieldChecked<FProperty>(<class_name>::StaticClass(), GET_MEMBER_NAME_CHECKED(<class_name>, <property_name>));
 | |
| 		GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication(FGameplayAttribute(<class_name>Property), <property_name>, <old_value>);
 | |
| 	));
 | |
| }
 | |
| #pragma pop_macro("FORCEINLINE")
 |