New generic attribute set codegen from table implemented
This commit is contained in:
parent
d4bf7cfaec
commit
8ba9170794
@ -5,7 +5,7 @@ ProjectName=GASATHON
|
|||||||
CopyrightNotice=
|
CopyrightNotice=
|
||||||
|
|
||||||
[/Script/Gasa.GasaDevOptions]
|
[/Script/Gasa.GasaDevOptions]
|
||||||
+AttributeSets=/Game/Core/Tables/DT_AttributeSet.DT_AttributeSet
|
+AttributeSets=/Game/Core/Tables/DT_GasaAttributeSet.DT_GasaAttributeSet
|
||||||
TaggedMessageTable=/Game/Core/Tables/DT_TaggedMessages.DT_TaggedMessages
|
TaggedMessageTable=/Game/Core/Tables/DT_TaggedMessages.DT_TaggedMessages
|
||||||
Template_PlayerCamera=/Game/Actors/BP_CameraMount.BP_CameraMount_C
|
Template_PlayerCamera=/Game/Actors/BP_CameraMount.BP_CameraMount_C
|
||||||
Template_HUD_HostUI=/Game/UI/UI_Host.UI_Host_C
|
Template_HUD_HostUI=/Game/UI/UI_Host.UI_Host_C
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"ColumnWidths":
|
||||||
|
{
|
||||||
|
"MaxValue": 165,
|
||||||
|
"Description": 135,
|
||||||
|
"Category": 96,
|
||||||
|
"BaseValue": 106,
|
||||||
|
"Name": 82
|
||||||
|
}
|
||||||
|
}
|
@ -13,8 +13,8 @@ struct GASA_API FAttributeSetField : public FTableRowBase
|
|||||||
|
|
||||||
FAttributeSetField()
|
FAttributeSetField()
|
||||||
: Name("Provide_Name")
|
: Name("Provide_Name")
|
||||||
, Description("Provide Description")
|
|
||||||
, Category("Optional Category")
|
, Category("Optional Category")
|
||||||
|
, Description("Provide Description")
|
||||||
, BaseValue(0)
|
, BaseValue(0)
|
||||||
, bUseMinAttribute(false)
|
, bUseMinAttribute(false)
|
||||||
, bUseMaxAttribute(false)
|
, bUseMaxAttribute(false)
|
||||||
@ -27,14 +27,14 @@ struct GASA_API FAttributeSetField : public FTableRowBase
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gameplay Attribute")
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gameplay Attribute")
|
||||||
FString Name;
|
FName Name;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gameplay Attribute")
|
||||||
|
FName Category;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gameplay Attribute")
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gameplay Attribute")
|
||||||
FString Description;
|
FString Description;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gameplay Attribute")
|
|
||||||
FString Category;
|
|
||||||
|
|
||||||
// UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gameplay Attribute")
|
// UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gameplay Attribute")
|
||||||
// FGameplayTag Tag;
|
// FGameplayTag Tag;
|
||||||
|
|
||||||
@ -59,4 +59,3 @@ struct GASA_API FAttributeSetField : public FTableRowBase
|
|||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gameplay Attribute", meta =( EditCondition="bUseMaxAttribute==false", EditConditionHides))
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gameplay Attribute", meta =( EditCondition="bUseMaxAttribute==false", EditConditionHides))
|
||||||
float MaxValue;
|
float MaxValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -16,9 +16,6 @@ public:
|
|||||||
// NOTE(Ed): Any Soft-References must have their includes defined in GasaDevOptions.cpp
|
// NOTE(Ed): Any Soft-References must have their includes defined in GasaDevOptions.cpp
|
||||||
// They are used by GasaGen for the GasaDevOptionsCache
|
// They are used by GasaGen for the GasaDevOptionsCache
|
||||||
|
|
||||||
UPROPERTY(Config)
|
|
||||||
TSoftObjectPtr<UDataTable> RandomBullshit;
|
|
||||||
|
|
||||||
UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category="GAS")
|
UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category="GAS")
|
||||||
TArray< TSoftObjectPtr<UDataTable>> AttributeSets;
|
TArray< TSoftObjectPtr<UDataTable>> AttributeSets;
|
||||||
|
|
||||||
|
@ -11,9 +11,6 @@ void FGasaDevOptionsCache::CachedDevOptions()
|
|||||||
{
|
{
|
||||||
UGasaDevOptions* DevOpts = GetMutDevOptions();
|
UGasaDevOptions* DevOpts = GetMutDevOptions();
|
||||||
|
|
||||||
RandomBullshit = DevOpts->RandomBullshit.LoadSynchronous();
|
|
||||||
ensureMsgf( RandomBullshit != nullptr, TEXT( "RandomBullshit is null, DO NOT RUN PIE or else you may get a crash if not handled in BP or C++" ) );
|
|
||||||
|
|
||||||
for ( auto& entry : DevOpts->AttributeSets )
|
for ( auto& entry : DevOpts->AttributeSets )
|
||||||
{
|
{
|
||||||
AttributeSets.Push( entry.LoadSynchronous() );
|
AttributeSets.Push( entry.LoadSynchronous() );
|
||||||
|
@ -8,8 +8,6 @@ struct GASA_API FGasaDevOptionsCache
|
|||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
UPROPERTY()
|
|
||||||
UObject* RandomBullshit;
|
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
TArray<UObject*> AttributeSets;
|
TArray<UObject*> AttributeSets;
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "GasaGen.h"
|
#include "GasaGen.h"
|
||||||
#include "GasaGen_Common.h"
|
#include "GasaGen_Common.h"
|
||||||
|
#include "GasaGen_AttributeSets.h"
|
||||||
#include "GasaGen_DevOptionsCache.h"
|
#include "GasaGen_DevOptionsCache.h"
|
||||||
|
|
||||||
// Editor Module
|
// Editor Module
|
||||||
@ -19,9 +20,9 @@ global Code UModule_GASA_API;
|
|||||||
void Execute_GasaModule_Codegen()
|
void Execute_GasaModule_Codegen()
|
||||||
{
|
{
|
||||||
FScopedSlowTask SlowTask(100.0f, LOCTEXT("RunningGasaGen", "Running GasaGen..."));
|
FScopedSlowTask SlowTask(100.0f, LOCTEXT("RunningGasaGen", "Running GasaGen..."));
|
||||||
SlowTask.MakeDialog(); // Shows a progress dialog
|
SlowTask.MakeDialog(false, true); // Shows a progress dialog
|
||||||
|
|
||||||
AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [&SlowTask]()
|
AsyncTask(ENamedThreads::AnyBackgroundHiPriTask, [&SlowTask]()
|
||||||
{
|
{
|
||||||
Gasa::LogEditor("Executing: Gasa Module code generation.");
|
Gasa::LogEditor("Executing: Gasa Module code generation.");
|
||||||
|
|
||||||
@ -37,8 +38,6 @@ void Execute_GasaModule_Codegen()
|
|||||||
|
|
||||||
Project_Path = String::make_length(GlobalAllocator, ue_ansi_project_path, ue_project_path.Len());
|
Project_Path = String::make_length(GlobalAllocator, ue_ansi_project_path, ue_project_path.Len());
|
||||||
Root_Path = String::make_length(GlobalAllocator, ue_ansi_rooot_path, ue_root_path.Len());
|
Root_Path = String::make_length(GlobalAllocator, ue_ansi_rooot_path, ue_root_path.Len());
|
||||||
UE_LOG(LogTemp, Log, TEXT("Current ROOT Directory: %s"), *ue_project_path);
|
|
||||||
UE_LOG(LogTemp, Log, TEXT("Current Project Directory: %s"), *ue_root_path);
|
|
||||||
|
|
||||||
// Initialize Globals
|
// Initialize Globals
|
||||||
{
|
{
|
||||||
@ -112,16 +111,11 @@ void Execute_GasaModule_Codegen()
|
|||||||
PreprocessorDefines.append(get_cached_string(str_UE_REQUIRES));
|
PreprocessorDefines.append(get_cached_string(str_UE_REQUIRES));
|
||||||
}
|
}
|
||||||
|
|
||||||
//generate_AttributeSets();
|
generate_AttributeSets();
|
||||||
generate_DevOptionsCache();
|
//generate_DevOptionsCache();
|
||||||
//generate_HostWidgetController();
|
//generate_HostWidgetController();
|
||||||
|
|
||||||
gen::deinit();
|
gen::deinit();
|
||||||
|
|
||||||
AsyncTask(ENamedThreads::GameThread, []()
|
|
||||||
{
|
|
||||||
// UI updates if needed
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,463 @@
|
|||||||
#include "GasaGen_AttributeSets.h"
|
#include "GasaGen_AttributeSets.h"
|
||||||
#include "GasaGen_Common.h"
|
#include "GasaGen_Common.h"
|
||||||
|
|
||||||
|
#include "Gasa/AbilitySystem/GasaAbilitySystem.h"
|
||||||
|
#include "Gasa/GasaDevOptions.h"
|
||||||
|
|
||||||
|
using namespace gen;
|
||||||
|
|
||||||
|
#pragma push_macro("UPROPERTY")
|
||||||
|
#pragma push_macro("UFUNCTION")
|
||||||
|
#pragma push_macro("FORCEINLINE")
|
||||||
|
#pragma push_macro("ensure")
|
||||||
|
#undef UPROPERTY
|
||||||
|
#undef UFUNCTION
|
||||||
|
#undef FORCEINLINE
|
||||||
|
#undef ensure
|
||||||
|
|
||||||
|
PRAGMA_DISABLE_OPTIMIZATION
|
||||||
void generate_AttributeSets()
|
void generate_AttributeSets()
|
||||||
{
|
{
|
||||||
|
// All attribute sets are tracked in Gasa's dev options for this project.
|
||||||
|
TArray< TSoftObjectPtr<UDataTable>> AttributeSetTables = Gasa::GetDevOptions()->AttributeSets;
|
||||||
|
check( AttributeSetTables.Num() > 0 );
|
||||||
|
|
||||||
|
// TODO(Ed): Doing one for now
|
||||||
|
FGraphEventRef LoadTableTask;
|
||||||
|
UDataTable* AttributeSetTable = nullptr;
|
||||||
|
FGraphEventArray Prerequisites;
|
||||||
|
LoadTableTask = FFunctionGraphTask::CreateAndDispatchWhenReady(
|
||||||
|
[ & AttributeSetTable, & AttributeSetTables ]()
|
||||||
|
{
|
||||||
|
AttributeSetTable = AttributeSetTables[0].LoadSynchronous();
|
||||||
|
},
|
||||||
|
TStatId(), &Prerequisites, ENamedThreads::GameThread
|
||||||
|
);
|
||||||
|
FTaskGraphInterface::Get().WaitUntilTaskCompletes(LoadTableTask);
|
||||||
|
|
||||||
|
TMap<FName, TArray<FAttributeSetField>> AttributesByCategory;
|
||||||
|
{
|
||||||
|
TMap< FName, uint8* > const& RowMap = AttributeSetTable->GetRowMap();
|
||||||
|
for (const TPair<FName, uint8*>& Row : RowMap)
|
||||||
|
{
|
||||||
|
FAttributeSetField const* RowData = rcast( FAttributeSetField const* , Row.Value);
|
||||||
|
|
||||||
|
// If category is empty, use a default category name
|
||||||
|
FName CategoryName = RowData->Category.IsNone() ? FName(TEXT("Default")) : RowData->Category;
|
||||||
|
|
||||||
|
TArray<FAttributeSetField>& CategoryAttributes = AttributesByCategory.FindOrAdd(CategoryName);
|
||||||
|
CategoryAttributes.Add( * RowData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FString AssetName = AttributeSetTables[0].GetAssetName();
|
||||||
|
check( AssetName.StartsWith(TEXT("DT_") ))
|
||||||
|
AssetName = AssetName.RightChop(3);
|
||||||
|
|
||||||
|
String str_AssetName = to_string(AssetName);
|
||||||
|
|
||||||
|
String class_name = String::fmt_buf(GlobalAllocator, "U%S", str_AssetName);
|
||||||
|
String header_file_name = String::fmt_buf(GlobalAllocator, "%S.h", str_AssetName);
|
||||||
|
String inlines_file_name = String::fmt_buf(GlobalAllocator, "%S_Inlines.h", str_AssetName);
|
||||||
|
String path_header_file = String::fmt_buf(GlobalAllocator, path_gasa_ability_system "%S.h", str_AssetName);
|
||||||
|
String path_inlines_file = String::fmt_buf(GlobalAllocator, path_gasa_ability_system "%S_Inlines.h", str_AssetName);
|
||||||
|
String path_source_file = String::fmt_buf(GlobalAllocator, path_gasa_ability_system "%S.cpp", str_AssetName);
|
||||||
|
String uht_include_file = String::fmt_buf(GlobalAllocator, "%S.generated.h", str_AssetName);
|
||||||
|
|
||||||
|
CodeType type_UAttributeSet = def_type( txt("UAttributeSet") );
|
||||||
|
CodeComment generation_notice = def_comment(txt("Generated by GasaEditor/GasaGen/GasaGen_AttributeSets.cpp"));
|
||||||
|
|
||||||
|
CodeAttributes api_attribute = def_attributes( UModule_GASA_API->Name);
|
||||||
|
|
||||||
|
Builder header = builder_open( path_header_file );
|
||||||
|
{
|
||||||
|
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(uht_include_file);
|
||||||
|
header.print( Include_AttributeSet);
|
||||||
|
header.print( Include_GasaAttributeSet_Generated);
|
||||||
|
header.print( fmt_newline);
|
||||||
|
|
||||||
|
gen::CodeClass attribute_set_class = {};
|
||||||
|
{
|
||||||
|
CodeBody body = def_body( CodeT::Class_Body );
|
||||||
|
{
|
||||||
|
body.append( UHT_GENERATED_BODY);
|
||||||
|
body.append( access_public );
|
||||||
|
|
||||||
|
body.append( def_constructor() );
|
||||||
|
body.append(fmt_newline);
|
||||||
|
|
||||||
|
// Generate UPROPERTIES for each attribute field, organized by category
|
||||||
|
for ( TPair< FName, TArray<FAttributeSetField>>& attributes : AttributesByCategory )
|
||||||
|
{
|
||||||
|
String category_name = to_string(attributes.Key);
|
||||||
|
CodeComment category_cmt = def_comment(token_fmt("category_name", (StrC)category_name, "<category_name> Attributes"));
|
||||||
|
body.append(category_cmt);
|
||||||
|
body.append(fmt_newline);
|
||||||
|
for (FAttributeSetField attribute : attributes.Value)
|
||||||
|
{
|
||||||
|
Code field_uproperty = code_fmt(
|
||||||
|
"category", (StrC)to_string(attribute.Category),
|
||||||
|
"property", (StrC)to_string(attribute.Name),
|
||||||
|
stringize(
|
||||||
|
UPROPERTY(ReplicatedUsing = Client_OnRep_<property>, EditAnywhere, BlueprintReadWrite, Category = "Attributes|<category>")
|
||||||
|
FGameplayAttributeData <property>;
|
||||||
|
));
|
||||||
|
body.append(field_uproperty);
|
||||||
|
}
|
||||||
|
body.append(fmt_newline);
|
||||||
|
body.append(fmt_newline);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate OnReps for each attribute field
|
||||||
|
for ( TPair< FName, TArray<FAttributeSetField>>& attributes : AttributesByCategory )
|
||||||
|
for ( FAttributeSetField attribute : attributes.Value )
|
||||||
|
{
|
||||||
|
Code umeta_UFUNCTION = code_str(UFUNCTION());
|
||||||
|
|
||||||
|
body.append(fmt_newline);
|
||||||
|
body.append(umeta_UFUNCTION);
|
||||||
|
body.append(fmt_newline);
|
||||||
|
body.append(code_fmt("property", (StrC)to_string(attribute.Name), stringize(
|
||||||
|
void Client_OnRep_<property>(FGameplayAttributeData& Prev<property>);
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
body.append(fmt_newline);
|
||||||
|
body.append(fmt_newline);
|
||||||
|
|
||||||
|
body.append(def_pragma(txt("region Getters")));
|
||||||
|
{
|
||||||
|
// Generate property getters
|
||||||
|
for ( TPair< FName, TArray<FAttributeSetField>>& attributes : AttributesByCategory )
|
||||||
|
for (FAttributeSetField attribute : attributes.Value)
|
||||||
|
{
|
||||||
|
CodeFn generated_get_attribute = parse_function(token_fmt(
|
||||||
|
"class_name", (StrC)class_name,
|
||||||
|
"property", (StrC)to_string(attribute.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);
|
||||||
|
}
|
||||||
|
body.append(fmt_newline);
|
||||||
|
|
||||||
|
// Generate value getters
|
||||||
|
for ( TPair< FName, TArray<FAttributeSetField>>& attributes : AttributesByCategory )
|
||||||
|
for (FAttributeSetField attribute : attributes.Value)
|
||||||
|
{
|
||||||
|
body.append(code_fmt("property", (StrC)to_string(attribute.Name),
|
||||||
|
stringize(
|
||||||
|
FORCEINLINE float Get<property>() const
|
||||||
|
{
|
||||||
|
return <property>.GetCurrentValue();
|
||||||
|
}
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
body.append(fmt_newline);
|
||||||
|
}
|
||||||
|
body.append(def_pragma(txt("endregion Getters")));
|
||||||
|
body.append(fmt_newline);
|
||||||
|
|
||||||
|
body.append(def_pragma(txt("region Setters")));
|
||||||
|
{
|
||||||
|
// Generate value setter forwards
|
||||||
|
for ( TPair< FName, TArray<FAttributeSetField>>& attributes : AttributesByCategory )
|
||||||
|
for (FAttributeSetField attribute : attributes.Value)
|
||||||
|
{
|
||||||
|
body.append(code_fmt("property", (StrC)to_string(attribute.Name),
|
||||||
|
stringize(
|
||||||
|
FORCEINLINE void Set<property>(float NewVal);
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
body.append(fmt_newline);
|
||||||
|
body.append(fmt_newline);
|
||||||
|
|
||||||
|
// Generate initers
|
||||||
|
for ( TPair< FName, TArray<FAttributeSetField>>& attributes : AttributesByCategory )
|
||||||
|
for (FAttributeSetField attribute : attributes.Value)
|
||||||
|
{
|
||||||
|
body.append(code_fmt("property", (StrC)to_string(attribute.Name),
|
||||||
|
stringize(
|
||||||
|
FORCEINLINE void Init<property>(float NewVal)
|
||||||
|
{
|
||||||
|
<property>.SetBaseValue(NewVal);
|
||||||
|
<property>.SetCurrentValue(NewVal);
|
||||||
|
}
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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")));
|
||||||
|
body.append(fmt_newline);
|
||||||
|
}
|
||||||
|
|
||||||
|
attribute_set_class = def_class( class_name, body
|
||||||
|
, type_UAttributeSet, AccessSpec::Public
|
||||||
|
, api_attribute
|
||||||
|
);
|
||||||
|
header.print(UHT_UCLASS);
|
||||||
|
header.print(attribute_set_class);
|
||||||
|
}
|
||||||
|
|
||||||
|
header.write();
|
||||||
|
format_file(path_header_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
Builder inlines = builder_open( path_inlines_file );
|
||||||
|
{
|
||||||
|
inlines.print(generation_notice);
|
||||||
|
inlines.print(pragma_once);
|
||||||
|
inlines.print(fmt_newline);
|
||||||
|
inlines.print(def_include(header_file_name));
|
||||||
|
inlines.print(def_include(txt("AbilitySystemComponent.h")));
|
||||||
|
inlines.print(fmt_newline);
|
||||||
|
|
||||||
|
CodeBody body = def_body(ECode::Global_Body);
|
||||||
|
{
|
||||||
|
body.append(def_pragma(txt("region Attribute Setters")));
|
||||||
|
{
|
||||||
|
for (TPair< FName, TArray<FAttributeSetField>>& attributes : AttributesByCategory)
|
||||||
|
for (FAttributeSetField attribute : attributes.Value)
|
||||||
|
{
|
||||||
|
CodeFn generated_get_attribute = parse_function(token_fmt(
|
||||||
|
"class_name", (StrC)class_name,
|
||||||
|
"property", (StrC)to_string(attribute.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")));
|
||||||
|
}
|
||||||
|
inlines.print(body);
|
||||||
|
inlines.print(fmt_newline);
|
||||||
|
|
||||||
|
CodeNS ns_gasa = parse_namespace(token_fmt(
|
||||||
|
"class_name", (StrC)class_name,
|
||||||
|
stringize(
|
||||||
|
namespace Gasa
|
||||||
|
{
|
||||||
|
inline
|
||||||
|
<class_name> const* GetAttributeSet(UAbilitySystemComponent* ASC)
|
||||||
|
{
|
||||||
|
return Cast< <class_name> >(ASC->GetAttributeSet(<class_name>::StaticClass()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)));
|
||||||
|
|
||||||
|
inlines.print(ns_gasa);
|
||||||
|
inlines.write();
|
||||||
|
format_file(path_inlines_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
Builder source = builder_open( path_source_file );
|
||||||
|
{
|
||||||
|
source.print(generation_notice);
|
||||||
|
header.print(fmt_newline);
|
||||||
|
source.print(def_include(header_file_name));
|
||||||
|
source.print(def_include(inlines_file_name));
|
||||||
|
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()
|
||||||
|
{}
|
||||||
|
));
|
||||||
|
body.append(constructor_for_UGasaAttributeSet);
|
||||||
|
|
||||||
|
// Generate Attribute fields implementation
|
||||||
|
{
|
||||||
|
body.append(fmt_newline);
|
||||||
|
body.append(def_pragma(txt("region Rep Notifies")));
|
||||||
|
|
||||||
|
for (TPair< FName, TArray<FAttributeSetField>>& attributes : AttributesByCategory)
|
||||||
|
for (FAttributeSetField attribute : attributes.Value)
|
||||||
|
{
|
||||||
|
CodeFn field_impl = parse_function(token_fmt(
|
||||||
|
"class_name", (StrC)class_name,
|
||||||
|
"property", (StrC)to_string(attribute.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
CodeFn PostGameplayEffectExecute;
|
||||||
|
CodeFn PreAttributeChange;
|
||||||
|
{
|
||||||
|
CodeBody pre_attribute_clamps = def_body(CodeT::Function_Body);
|
||||||
|
CodeBody post_attribute_clamps = def_body(CodeT::Function_Body);
|
||||||
|
|
||||||
|
// Generate field clamping ops for the pre & post functions
|
||||||
|
{
|
||||||
|
pre_attribute_clamps.append(fmt_newline);
|
||||||
|
pre_attribute_clamps.append(fmt_newline);
|
||||||
|
post_attribute_clamps.append(fmt_newline);
|
||||||
|
post_attribute_clamps.append(fmt_newline);
|
||||||
|
|
||||||
|
for (TPair< FName, TArray<FAttributeSetField>>& attributes : AttributesByCategory)
|
||||||
|
for (FAttributeSetField attribute : attributes.Value)
|
||||||
|
{
|
||||||
|
String clamp_min;
|
||||||
|
if (attribute.bUseMinAttribute)
|
||||||
|
clamp_min = get_cached_string(token_fmt("MinName", (StrC)to_string(attribute.MinAttribute), "Get<MinName>()"));
|
||||||
|
else
|
||||||
|
clamp_min = String::fmt_buf(GlobalAllocator, "%f", attribute.MinValue);
|
||||||
|
|
||||||
|
String clamp_max;
|
||||||
|
if (attribute.bUseMaxAttribute)
|
||||||
|
clamp_max = get_cached_string(token_fmt("MaxName", (StrC)to_string(attribute.MaxAttribute), "Get<MaxName>()"));
|
||||||
|
else
|
||||||
|
clamp_max = String::fmt_buf(GlobalAllocator, "%f", attribute.MaxValue);
|
||||||
|
|
||||||
|
pre_attribute_clamps.append(code_fmt(
|
||||||
|
"field", (StrC)to_string(attribute.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>);
|
||||||
|
}
|
||||||
|
)));
|
||||||
|
|
||||||
|
post_attribute_clamps.append(code_fmt(
|
||||||
|
"field", (StrC)to_string(attribute.Name),
|
||||||
|
"clamp_min", (StrC)clamp_min,
|
||||||
|
"clamp_max", (StrC)clamp_max,
|
||||||
|
stringize(
|
||||||
|
if (Data.EvaluatedData.Attribute == Get<field>Attribute())
|
||||||
|
{
|
||||||
|
Set<field>(FMath::Clamp(Get<field>(), <clamp_min>, <clamp_max>));
|
||||||
|
}
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
||||||
|
"class_name", (StrC)class_name,
|
||||||
|
"attribute_clamps", (StrC)pre_attribute_clamps.to_string(),
|
||||||
|
stringize(
|
||||||
|
void <class_name>::PreAttributeChange(FGameplayAttribute const& Attribute, float& NewValue)
|
||||||
|
{
|
||||||
|
Super::PreAttributeChange(Attribute, NewValue);
|
||||||
|
|
||||||
|
<attribute_clamps>
|
||||||
|
}
|
||||||
|
)));
|
||||||
|
|
||||||
|
PostGameplayEffectExecute = parse_function(token_fmt(
|
||||||
|
"class_name", (StrC)class_name,
|
||||||
|
"attribute_clamps", (StrC)post_attribute_clamps.to_string(),
|
||||||
|
stringize(
|
||||||
|
void <class_name>::PostGameplayEffectExecute(FGameplayEffectModCallbackData const& Data)
|
||||||
|
{
|
||||||
|
Super::PostGameplayEffectExecute(Data);
|
||||||
|
FEffectProperties Props;
|
||||||
|
Props.Populate(Data);
|
||||||
|
|
||||||
|
<attribute_clamps>
|
||||||
|
}
|
||||||
|
)));
|
||||||
|
|
||||||
|
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 (TPair< FName, TArray<FAttributeSetField>>& attributes : AttributesByCategory)
|
||||||
|
for (FAttributeSetField attribute : attributes.Value)
|
||||||
|
{
|
||||||
|
field_lifetimes.append(code_fmt(
|
||||||
|
"class_name", (StrC)class_name,
|
||||||
|
"property", (StrC)to_string(attribute.Name),
|
||||||
|
stringize(
|
||||||
|
DOREPLIFETIME_DEFAULT_GAS( <class_name>, <property> );
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
GetLifetimeOfReplicatedProps = parse_function(token_fmt(
|
||||||
|
"class_name", (StrC)class_name,
|
||||||
|
"property_lifetimes", (StrC)(field_lifetimes.to_string()),
|
||||||
|
stringize(
|
||||||
|
void <class_name>::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||||
|
{
|
||||||
|
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||||
|
<property_lifetimes>
|
||||||
|
}
|
||||||
|
)));
|
||||||
|
|
||||||
|
body.append(GetLifetimeOfReplicatedProps);
|
||||||
|
}
|
||||||
|
source.print(body);
|
||||||
|
}
|
||||||
|
source.write();
|
||||||
|
format_file(path_source_file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
PRAGMA_ENABLE_OPTIMIZATION
|
||||||
|
|
||||||
|
#pragma pop_macro("UPROPERTY")
|
||||||
|
#pragma pop_macro("UFUNCTION")
|
||||||
|
#pragma pop_macro("FORCEINLINE")
|
||||||
|
#pragma pop_macro("ensure")
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
void generate_attribute_sets();
|
void generate_AttributeSets();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
#include "gencpp/gen.builder.hpp"
|
#include "gencpp/gen.builder.hpp"
|
||||||
using namespace gen;
|
using namespace gen;
|
||||||
|
|
||||||
#undef check
|
|
||||||
|
|
||||||
// Codegen assumes its working directory is the project
|
// Codegen assumes its working directory is the project
|
||||||
#define path_scripts "/scripts/"
|
#define path_scripts "/scripts/"
|
||||||
#define path_project "/Project/"
|
#define path_project "/Project/"
|
||||||
@ -121,11 +119,20 @@ void format_file( char const* path )
|
|||||||
log_fmt("\tRunning clang-format on file:\n");
|
log_fmt("\tRunning clang-format on file:\n");
|
||||||
system( command );
|
system( command );
|
||||||
log_fmt("\tclang-format finished reformatting.\n");
|
log_fmt("\tclang-format finished reformatting.\n");
|
||||||
|
|
||||||
FString command_fstr = FString( command.Data, command.length());
|
|
||||||
UE_LOG(LogTemp, Log, TEXT("clang format command: %s"), *command_fstr );
|
|
||||||
#undef cf_cmd
|
#undef cf_cmd
|
||||||
#undef cf_format_inplace
|
#undef cf_format_inplace
|
||||||
#undef cf_style
|
#undef cf_style
|
||||||
#undef cf_verbse
|
#undef cf_verbse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FORCEINLINE
|
||||||
|
String to_string( FString ue_string ) {
|
||||||
|
char const* ansi_str = TCHAR_TO_ANSI(*ue_string);
|
||||||
|
return String::make_length(GlobalAllocator, ansi_str, ue_string.Len());
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCEINLINE
|
||||||
|
String to_string( FName ue_fname ) {
|
||||||
|
char const* ansi_str = TCHAR_TO_ANSI(*ue_fname.ToString());
|
||||||
|
return String::make_length(GlobalAllocator, ansi_str, ue_fname.GetStringLength());
|
||||||
|
}
|
||||||
|
@ -124,6 +124,9 @@ void gen_UGasaAttributeSet()
|
|||||||
{
|
{
|
||||||
CodeInclude Include_AttributeSet = def_include(txt("AttributeSet.h"));
|
CodeInclude Include_AttributeSet = def_include(txt("AttributeSet.h"));
|
||||||
CodeInclude Include_GasaAttributeSet_Generated = def_include(txt("GasaAttributeSet.generated.h"));
|
CodeInclude Include_GasaAttributeSet_Generated = def_include(txt("GasaAttributeSet.generated.h"));
|
||||||
|
header.print( Include_AttributeSet);
|
||||||
|
header.print( Include_GasaAttributeSet_Generated);
|
||||||
|
header.print( fmt_newline);
|
||||||
|
|
||||||
CodeAttributes api_attribute = def_attributes( UModule_GASA_API->Name);
|
CodeAttributes api_attribute = def_attributes( UModule_GASA_API->Name);
|
||||||
|
|
||||||
@ -144,8 +147,7 @@ void gen_UGasaAttributeSet()
|
|||||||
body.append(fmt_newline);
|
body.append(fmt_newline);
|
||||||
|
|
||||||
// body.append( def_comment(txt("Secondary Attribute Fields")));
|
// body.append( def_comment(txt("Secondary Attribute Fields")));
|
||||||
// body.append(fmt_newline);
|
// body.append(fmt_newline);sssss// def_attribute_properties( body, secondary_attribute_fields);
|
||||||
// def_attribute_properties( body, secondary_attribute_fields);
|
|
||||||
// body.append(fmt_newline);
|
// body.append(fmt_newline);
|
||||||
// body.append(fmt_newline);
|
// body.append(fmt_newline);
|
||||||
|
|
||||||
@ -205,9 +207,6 @@ void gen_UGasaAttributeSet()
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
header.print( Include_AttributeSet);
|
|
||||||
header.print( Include_GasaAttributeSet_Generated);
|
|
||||||
header.print( fmt_newline);
|
|
||||||
header.print( UHT_UCLASS );
|
header.print( UHT_UCLASS );
|
||||||
header.print(GasaAttributeSet);
|
header.print(GasaAttributeSet);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user