34. Listening for Attribute Changes

This commit is contained in:
2024-04-22 00:30:29 -04:00
parent 811dc33f4a
commit 2c11939244
34 changed files with 324 additions and 60 deletions

View File

@@ -9,7 +9,7 @@ Tag_PPV=Global_PPV
Tag_GlobalPPV=Global_PPV Tag_GlobalPPV=Global_PPV
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
Template_HostWidgetController=/Game/Core/BP_HostWidgetController.BP_HostWidgetController_C Template_HostWidgetController=/Game/UI/BP_HostWidgetController.BP_HostWidgetController_C
[/Script/GameplayAbilities.AbilitySystemGlobals] [/Script/GameplayAbilities.AbilitySystemGlobals]
bUseDebugTargetFromHud=true bUseDebugTargetFromHud=true

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -8,9 +8,9 @@
UGasaAttributeSet::UGasaAttributeSet() UGasaAttributeSet::UGasaAttributeSet()
{ {
InitHealth( 100.f ); InitHealth( 80.f );
InitMaxHealth( 100.f ); InitMaxHealth( 100.f );
InitMana( 50.f ); InitMana( 20.f );
InitMaxMana( 50.f ); InitMaxMana( 50.f );
} }
@@ -33,7 +33,6 @@ void UGasaAttributeSet::Client_OnRep_MaxMana( FGameplayAttributeData& PrevMaxMan
{ {
GAMEPLAYATTRIBUTE_REPNOTIFY( UGasaAttributeSet, MaxMana, PrevMaxMana ) GAMEPLAYATTRIBUTE_REPNOTIFY( UGasaAttributeSet, MaxMana, PrevMaxMana )
} }
void UGasaAttributeSet::GetLifetimeReplicatedProps( TArray<FLifetimeProperty>& OutLifetimeProps ) const void UGasaAttributeSet::GetLifetimeReplicatedProps( TArray<FLifetimeProperty>& OutLifetimeProps ) const
{ {
Super::GetLifetimeReplicatedProps( OutLifetimeProps ); Super::GetLifetimeReplicatedProps( OutLifetimeProps );

View File

@@ -90,7 +90,6 @@ public:
#pragma endregion Setters #pragma endregion Setters
#pragma region UObject #pragma region UObject
void void
GetLifetimeReplicatedProps( TArray<FLifetimeProperty>& OutLifetimeProps ) const override; GetLifetimeReplicatedProps( TArray<FLifetimeProperty>& OutLifetimeProps ) const override;
#pragma endregion UObject #pragma endregion UObject

View File

@@ -28,7 +28,7 @@ void APlayerCharacter::PossessedBy(AController* NewController)
AGasaPlayerController* PC = GetController<AGasaPlayerController>(); AGasaPlayerController* PC = GetController<AGasaPlayerController>();
AGasaHUD* HUD = PC->GetHUD<AGasaHUD>(); AGasaHUD* HUD = PC->GetHUD<AGasaHUD>();
FWidgetControllerData Data = { PC, PS, AbilitySystem, Attributes }; FWidgetControllerData Data = { PC, PS, AbilitySystem, Attributes };
HUD->InitOverlay(& Data); HUD->InitHostWidget(& Data);
} }
// TODO(Ed): We need to setup Net Slime... // TODO(Ed): We need to setup Net Slime...
@@ -49,6 +49,6 @@ void APlayerCharacter::OnRep_PlayerState()
AGasaPlayerController* PC = GetController<AGasaPlayerController>(); AGasaPlayerController* PC = GetController<AGasaPlayerController>();
AGasaHUD* HUD = PC->GetHUD<AGasaHUD>(); AGasaHUD* HUD = PC->GetHUD<AGasaHUD>();
FWidgetControllerData Data = { PC, PS, AbilitySystem, Attributes }; FWidgetControllerData Data = { PC, PS, AbilitySystem, Attributes };
HUD->InitOverlay(& Data); HUD->InitHostWidget(& Data);
} }
} }

View File

@@ -6,14 +6,16 @@
#include "Blueprint/UserWidget.h" #include "Blueprint/UserWidget.h"
using namespace Gasa; using namespace Gasa;
void AGasaHUD::InitOverlay(FWidgetControllerData const* WidgetControllerData) void AGasaHUD::InitHostWidget(FWidgetControllerData const* WidgetControllerData)
{ {
HostWidget = CreateWidget<UHUDHostWidget>( GetWorld() HostWidget = CreateWidget<UHUDHostWidget>( GetWorld()
, GetDevOptions()->Template_HUD_HostUI.LoadSynchronous() ); , GetDevOptions()->Template_HUD_HostUI.LoadSynchronous() );
HostWidgetController = NewObject<UHostWidgetController>(this, GetDevOptions()->Template_HostWidgetController.Get()); HostWidgetController = NewObject<UHostWidgetController>(this, GetDevOptions()->Template_HostWidgetController.Get());
HostWidgetController->Data = (* WidgetControllerData);
HostWidget->SetWidgetController(HostWidgetController); HostWidget->SetWidgetController(HostWidgetController);
HostWidgetController->BroadcastInitialValues();
HostWidget->AddToViewport(); HostWidget->AddToViewport();
} }

View File

@@ -19,7 +19,7 @@ public:
UPROPERTY(VisibleAnywhere, BlueprintReadWrite) UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
TObjectPtr<UHostWidgetController> HostWidgetController; TObjectPtr<UHostWidgetController> HostWidgetController;
void InitOverlay(FWidgetControllerData const* WidgetControllerData); void InitHostWidget(FWidgetControllerData const* WidgetControllerData);
#pragma region HUD #pragma region HUD
void ShowHUD() override; void ShowHUD() override;

View File

@@ -89,6 +89,11 @@ void UGlobeProgressBar::SetGlassStyle(FSlateBrush brush)
Glass->SetBrush(brush); Glass->SetBrush(brush);
} }
void UGlobeProgressBar::SetPercentage(float CurrentValue, float MaxValue)
{
Bar->SetPercent( MaxValue > 0.f ? CurrentValue / MaxValue : 0.f );
}
void UGlobeProgressBar::SetSize(float width, float height) void UGlobeProgressBar::SetSize(float width, float height)
{ {
Root_SB->SetWidthOverride( width ); Root_SB->SetWidthOverride( width );

View File

@@ -47,6 +47,9 @@ public:
UFUNCTION(BlueprintCallable, Category="Globe") UFUNCTION(BlueprintCallable, Category="Globe")
void SetGlassStyle(FSlateBrush brush); void SetGlassStyle(FSlateBrush brush);
UFUNCTION(BlueprintCallable, Category="Globe")
void SetPercentage(float CurrentValue, float MaxValue);
UFUNCTION(BlueprintCallable, Category="Globe") UFUNCTION(BlueprintCallable, Category="Globe")
void SetSize(float width, float height); void SetSize(float width, float height);
#pragma endregion Bindings #pragma endregion Bindings

View File

@@ -1 +1,14 @@
#include "HostWidgetController.h" #include "HostWidgetController.h"
#include "AbilitySystem/GasaAttributeSet.h"
void UHostWidgetController::BroadcastInitialValues()
{
Super::BroadcastInitialValues();
UGasaAttributeSet* GasaAttribs = Cast<UGasaAttributeSet>( Data.Attributes );
if ( GasaAttribs )
{
Event_OnHealthChanged.Broadcast( GasaAttribs->GetHealth() );
Event_OnMaxHealthChanged.Broadcast( GasaAttribs->GetMaxHealth() );
Event_OnManaChanged.Broadcast( GasaAttribs->GetMana() );
Event_OnMaxManaChanged.Broadcast( GasaAttribs->GetMaxMana() );
}
}

View File

@@ -1,12 +1,31 @@
#pragma once #pragma once
#include "WidgetController.h" #include "WidgetController.h"
#include "HostWidgetController.generated.h" #include "HostWidgetController.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam( FAttributeFloatChangedSig, float, NewValue );
UCLASS() UCLASS( Blueprintable, BlueprintType )
class GASA_API UHostWidgetController : public UWidgetController class GASA_API UHostWidgetController : public UWidgetController
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
#pragma region Attribute Events
// Attribute Events are generated by GasaGen/GasaGen_HostWidgetController.cpp
UPROPERTY( BlueprintAssignable, Category = "Attributes" )
FAttributeFloatChangedSig Event_OnHealthChanged;
UPROPERTY( BlueprintAssignable, Category = "Attributes" )
FAttributeFloatChangedSig Event_OnMaxHealthChanged;
UPROPERTY( BlueprintAssignable, Category = "Attributes" )
FAttributeFloatChangedSig Event_OnManaChanged;
UPROPERTY( BlueprintAssignable, Category = "Attributes" )
FAttributeFloatChangedSig Event_OnMaxManaChanged;
#pragma endregion Attribute Events
#pragma region WidgetController
void BroadcastInitialValues() override;
#pragma endregion WidgetController
}; };

View File

@@ -7,27 +7,19 @@ USTRUCT(BlueprintType)
struct GASA_API FWidgetControllerData struct GASA_API FWidgetControllerData
{ {
GENERATED_BODY() GENERATED_BODY()
public:
FWidgetControllerData() = default; FWidgetControllerData() = default;
FWidgetControllerData(AGasaPlayerController* Controller FWidgetControllerData
, AGasaPlayerState* PlayerState ( AGasaPlayerController* Controller
, UAbilitySystemComponent* AbilitySystem , AGasaPlayerState* PlayerState
, UAttributeSet* Attributes ) , UAbilitySystemComponent* AbilitySystem
#if 1 , UAttributeSet* Attributes )
: Controller(Controller) : Controller(Controller)
, PlayerState(PlayerState) , PlayerState(PlayerState)
, AbilitySystem(AbilitySystem) , AbilitySystem(AbilitySystem)
, Attributes(Attributes) , Attributes(Attributes)
#endif {}
{
#if 0
this->Controller = Controller;
this->PlayerState = PlayerState;
this->AbilitySystem = AbilitySystem;
this->Attributes = Attributes;
#endif
}
UPROPERTY(BlueprintReadOnly, Category="Player") UPROPERTY(BlueprintReadOnly, Category="Player")
TObjectPtr<AGasaPlayerController> Controller; TObjectPtr<AGasaPlayerController> Controller;
@@ -50,4 +42,7 @@ public:
UPROPERTY(BlueprintReadOnly, Category="Player") UPROPERTY(BlueprintReadOnly, Category="Player")
FWidgetControllerData Data; FWidgetControllerData Data;
UFUNCTION()
virtual void BroadcastInitialValues() {};
}; };

View File

@@ -17,6 +17,197 @@ using namespace gen;
#include "GasaGen_UGasaAttributeSet.cpp" #include "GasaGen_UGasaAttributeSet.cpp"
#include "GasaGen_ChangeBPActionMenu.cpp" #include "GasaGen_ChangeBPActionMenu.cpp"
#include "GasaGen_DevOptionsCache.cpp" #include "GasaGen_DevOptionsCache.cpp"
#include "GasaGen_HostWidgetController.cpp"
void gen_UHostWidgetController()
{
Array<StringCached> attribute_fields = get_gasa_attribute_fields();
CodeBody ori_HostWidgetController_header = parse_file(path_gasa_ui "HostWidgetController.h");
{
CodeBody header_body = def_body(ECode::Global_Body);
StrC str_UHostWidgetController = txt("UHostWidgetController");
CodeClass ori_UHostWidgetController = NoCode;
Code file_code = ori_HostWidgetController_header.begin();
for ( ; file_code != ori_HostWidgetController_header.end(); ++ file_code )
{
if (s32 never_enter = 0; never_enter)
found: break;
switch (file_code->Type)
{
default:
header_body.append(file_code);
continue;
case ECode::Class:
if ( ! file_code->Name.starts_with(str_UHostWidgetController))
continue;
ori_UHostWidgetController = file_code.cast<CodeClass>();
++ file_code;
goto found;
case ECode::Preprocess_Include:
header_body.append(file_code);
if ( file_code->Content.starts_with(txt("HostWidgetController.generated.h")))
{
header_body.append(fmt_newline);
header_body.append(fmt_newline);
}
continue;
case ECode::Untyped:
header_body.append(file_code);
if (file_code->Content.starts_with( txt("DECLARE_"))
|| file_code->Content.starts_with( txt("UCLASS"))
)
header_body.append(fmt_newline);
continue;
}
}
CodeBody attribute_events = def_body(ECode::Class_Body);
{
attribute_events.append( def_comment( txt("Attribute Events are generated by GasaGen/GasaGen_HostWidgetController.cpp")));
attribute_events.append(fmt_newline);
for ( s32 id = 0; id < attribute_fields.num(); )
{
StringCached 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; ))
));
++ id;
if ( id < attribute_fields.num() )
{
attribute_events.append(fmt_newline);
}
}
}
CodeClass new_UHostWidgetController = ori_UHostWidgetController.duplicate().cast<CodeClass>();
CodeBody new_body = def_body(ECode::Class_Body);
for (Code code = ori_UHostWidgetController->Body.begin();
code != ori_UHostWidgetController->Body.end();
++ code )
{
switch (code->Type)
{
default:
new_body.append(code);
continue;
case ECode::Preprocess_Pragma:
{
local_persist bool found = false;
if (found)
{
new_body.append(code);
continue;
}
CodePragma pragma = code.cast<CodePragma>();
if ( pragma->Content.starts_with(txt("region Attribute Events")) )
{
new_body.append(pragma);
++ code;
new_body.append(attribute_events);
while (code->Type != ECode::Preprocess_Pragma
|| ! code->Content.starts_with(txt("endregion Attribute Events")))
++ code;
new_body.append( code );
found = true;
}
}
break;
case ECode::Untyped:
new_body.append(code);
if (code->Content.starts_with( txt("GENERATED_BODY")))
new_body.append(fmt_newline);
}
}
new_body.append(fmt_newline);
new_UHostWidgetController->Body = new_body;
header_body.append(new_UHostWidgetController);
for (; file_code != ori_HostWidgetController_header.end(); ++ file_code)
{
header_body.append(file_code);
}
Builder header = Builder::open(path_gasa_ui "HostWidgetController.h");
header.print(header_body);
header.write();
format_file(path_gasa_ui "HostWidgetController.h");
}
CodeBody ori_HostWidgetController_source = parse_file(path_gasa_ui "HostWidgetController.cpp");
{
CodeBody source_body = def_body(ECode::Global_Body);
CodeBody broadcast_calls = def_body(ECode::Function_Body);
for (StringCached field : attribute_fields)
{
broadcast_calls.append( code_fmt( "field", (StrC)field,
stringize( Event_On<field>Changed.Broadcast( GasaAttribs->Get<field>() ); )
));
}
CodeFn BroadcastInitialValues = parse_function( token_fmt( "broadcast_calls", (StrC)broadcast_calls.to_string(),
stringize(
void UHostWidgetController::BroadcastInitialValues()
{
Super::BroadcastInitialValues();
// Thiis function is managed by: GasaGen/GasaGen_HostWidgetController.cpp
UGasaAttributeSet* GasaAttribs = Cast<UGasaAttributeSet>(Data.Attributes);
if (GasaAttribs)
{
<broadcast_calls>
}
})
));
for ( Code code : ori_HostWidgetController_source)
{
switch (code->Type)
{
case ECode::Function:
CodeFn function_def = code.cast<CodeFn>();
if ( String::are_equal(function_def->Name, BroadcastInitialValues->Name)
&& function_def->Params.is_equal(BroadcastInitialValues->Params))
{
code = BroadcastInitialValues;
log_fmt("Swapped: %S", BroadcastInitialValues->Name);
}
break;
}
source_body.append(code);
}
Builder source = Builder::open(path_gasa_ui "HostWidgetController.cpp");
source.print(source_body);
source.write();
format_file(path_gasa_ui "HostWidgetController.cpp");
}
}
int gen_main() int gen_main()
{ {
@@ -38,6 +229,7 @@ int gen_main()
PreprocessorDefines.append( get_cached_string(str_DECLARE_DELEGATE_RetVal_OneParam)); PreprocessorDefines.append( get_cached_string(str_DECLARE_DELEGATE_RetVal_OneParam));
PreprocessorDefines.append( get_cached_string(str_DECLARE_DELEGATE_RetVal_ThreeParams)); PreprocessorDefines.append( get_cached_string(str_DECLARE_DELEGATE_RetVal_ThreeParams));
PreprocessorDefines.append( get_cached_string(str_DECLARE_DELEGATE_SixParams)); PreprocessorDefines.append( get_cached_string(str_DECLARE_DELEGATE_SixParams));
PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam));
PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams)); PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams));
PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams)); PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams));
PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams)); PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams));
@@ -77,6 +269,7 @@ int gen_main()
gen_UGasaAttributeSet(); gen_UGasaAttributeSet();
gen_FGasaDevOptionsCache(); gen_FGasaDevOptionsCache();
gen_UHostWidgetController();
// One offs // One offs
if (0) if (0)

View File

@@ -13,11 +13,13 @@ using namespace gen;
#define path_config path_source "Config/" #define path_config path_source "Config/"
#define path_module_gasa path_source "Gasa/" #define path_module_gasa path_source "Gasa/"
#define path_gasa_ability_system path_module_gasa "AbilitySystem/" #define path_gasa_ability_system path_module_gasa "AbilitySystem/"
#define path_gasa_ui path_module_gasa "UI/"
constexpr StrC str_DECLARE_CLASS = txt("DECLARE_CLASS("); constexpr StrC str_DECLARE_CLASS = txt("DECLARE_CLASS(");
constexpr StrC str_DECLARE_DELEGATE_RetVal_OneParam = txt("DECLARE_DELEGATE_RetVal_OneParam("); constexpr StrC str_DECLARE_DELEGATE_RetVal_OneParam = txt("DECLARE_DELEGATE_RetVal_OneParam(");
constexpr StrC str_DECLARE_DELEGATE_RetVal_ThreeParams = txt("DECLARE_DELEGATE_RetVal_ThreeParams("); constexpr StrC str_DECLARE_DELEGATE_RetVal_ThreeParams = txt("DECLARE_DELEGATE_RetVal_ThreeParams(");
constexpr StrC str_DECLARE_DELEGATE_SixParams = txt("DECLARE_DELEGATE_SixParams("); constexpr StrC str_DECLARE_DELEGATE_SixParams = txt("DECLARE_DELEGATE_SixParams(");
constexpr StrC str_DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam = txt("DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(");
constexpr StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams("); constexpr StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams(");
constexpr StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams("); constexpr StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams(");
constexpr StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams("); constexpr StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams(");

View File

@@ -16,16 +16,26 @@ void def_attribute_field_property_setter_inlines( CodeBody body, StrC class_name
void def_attribute_field_initers ( CodeBody body, 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 ); void impl_attribute_fields ( CodeBody body, StrC class_name, Array<StringCached> properties );
Array<StringCached> get_gasa_attribute_fields()
{
local_persist
Array<StringCached> attribute_fields = Array<StringCached>::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")));
}
return attribute_fields;
}
void gen_UGasaAttributeSet() void gen_UGasaAttributeSet()
{ {
CodeType type_UAttributeSet = def_type( txt("UAttributeSet") ); CodeType type_UAttributeSet = def_type( txt("UAttributeSet") );
CodeComment generation_notice = def_comment(txt("Generated by GasaGen/GasaGen_UGasaAttributeSet.cpp")); CodeComment generation_notice = def_comment(txt("Generated by GasaGen/GasaGen_UGasaAttributeSet.cpp"));
Array<StringCached> attribute_fields = Array<StringCached>::init( GlobalAllocator); Array<StringCached> attribute_fields = get_gasa_attribute_fields();
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")));
StrC class_name = txt("UGasaAttributeSet"); StrC class_name = txt("UGasaAttributeSet");

View File

@@ -1950,6 +1950,7 @@ void CodeFn::to_string_def( String& result )
if ( ast->Attributes ) if ( ast->Attributes )
result.append_fmt( " %S ", ast->Attributes.to_string() ); result.append_fmt( " %S ", ast->Attributes.to_string() );
b32 prefix_specs = false;
if ( ast->Specs ) if ( ast->Specs )
{ {
for ( SpecifierT spec : ast->Specs ) for ( SpecifierT spec : ast->Specs )
@@ -1958,11 +1959,13 @@ void CodeFn::to_string_def( String& result )
{ {
StrC spec_str = ESpecifier::to_str( spec ); StrC spec_str = ESpecifier::to_str( spec );
result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr ); result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr );
prefix_specs = true;
} }
} }
} }
if ( ast->Attributes || ast->Specs ) if ( ast->Attributes || prefix_specs )
result.append( "\n" ); result.append( "\n" );
if ( ast->ReturnType ) if ( ast->ReturnType )
@@ -2000,19 +2003,22 @@ void CodeFn::to_string_fwd( String& result )
if ( ast->Attributes ) if ( ast->Attributes )
result.append_fmt( "%S ", ast->Attributes.to_string() ); result.append_fmt( "%S ", ast->Attributes.to_string() );
bool prefix_specs = false;
if ( ast->Specs ) if ( ast->Specs )
{ {
for ( SpecifierT spec : ast->Specs ) for ( SpecifierT spec : ast->Specs )
{ {
if ( ESpecifier::is_trailing( spec ) && ! ( spec != ESpecifier::Pure ) ) if ( ! ESpecifier::is_trailing( spec ) || ! ( spec != ESpecifier::Pure ) )
{ {
StrC spec_str = ESpecifier::to_str( spec ); StrC spec_str = ESpecifier::to_str( spec );
result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr ); result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr );
prefix_specs = true;
} }
} }
} }
if ( ast->Attributes || ast->Specs ) if ( ast->Attributes || prefix_specs )
{ {
result.append( "\n" ); result.append( "\n" );
} }
@@ -2894,17 +2900,17 @@ internal void define_constants()
access_private = make_code(); access_private = make_code();
access_private->Type = ECode::Access_Private; access_private->Type = ECode::Access_Private;
access_private->Name = get_cached_string( txt( "private:" ) ); access_private->Name = get_cached_string( txt( "private:\n" ) );
access_private.set_global(); access_private.set_global();
access_protected = make_code(); access_protected = make_code();
access_protected->Type = ECode::Access_Protected; access_protected->Type = ECode::Access_Protected;
access_protected->Name = get_cached_string( txt( "protected:" ) ); access_protected->Name = get_cached_string( txt( "protected:\n" ) );
access_protected.set_global(); access_protected.set_global();
access_public = make_code(); access_public = make_code();
access_public->Type = ECode::Access_Public; access_public->Type = ECode::Access_Public;
access_public->Name = get_cached_string( txt( "public:" ) ); access_public->Name = get_cached_string( txt( "public:\n" ) );
access_public.set_global(); access_public.set_global();
attrib_api_export = def_attributes( code( GEN_API_Export_Code ) ); attrib_api_export = def_attributes( code( GEN_API_Export_Code ) );

View File

@@ -5146,6 +5146,9 @@ Code CodeParam::duplicate()
bool CodeParam::is_equal( Code other ) bool CodeParam::is_equal( Code other )
{ {
if ( ast == nullptr && other.ast == nullptr)
return true;
if ( ast == nullptr || other.ast == nullptr ) if ( ast == nullptr || other.ast == nullptr )
{ {
log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); log_failure( "Code::is_equal: Cannot compare code, AST is null!" );

View File

@@ -166,7 +166,16 @@ SpacesInSquareBrackets: false
Standard: c++20 Standard: c++20
StatementMacros: ['UPROPERTY', 'UFUNCTION', 'UCLASS', 'USTRUCT', 'UENUM', 'UINTERFACE', 'GENERATED_BODY'] StatementMacros: [
'UPROPERTY',
'UFUNCTION',
'UCLASS',
'USTRUCT',
'UENUM',
'UINTERFACE',
'GENERATED_BODY',
'DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam'
]
TabWidth: 4 TabWidth: 4

View File

@@ -79,6 +79,7 @@ function build-gengasa
$compiler_args = @() $compiler_args = @()
$compiler_args += ($flag_define + 'GEN_TIME') $compiler_args += ($flag_define + 'GEN_TIME')
$compiler_args += ($flag_cpp_version + 'c++17')
$linker_args = @() $linker_args = @()
$linker_args += $flag_link_win_subsystem_console $linker_args += $flag_link_win_subsystem_console

View File

@@ -94,6 +94,7 @@ if ( $vendor -match "clang" )
# https://clang.llvm.org/docs/ClangCommandLineReference.html # https://clang.llvm.org/docs/ClangCommandLineReference.html
$flag_all_c = '-x c' $flag_all_c = '-x c'
$flag_all_cpp = '-x c++' $flag_all_cpp = '-x c++'
$flag_cpp_version = '-std='
$flag_compile = '-c' $flag_compile = '-c'
$flag_color_diagnostics = '-fcolor-diagnostics' $flag_color_diagnostics = '-fcolor-diagnostics'
$flag_no_color_diagnostics = '-fno-color-diagnostics' $flag_no_color_diagnostics = '-fno-color-diagnostics'
@@ -318,6 +319,7 @@ if ( $vendor -match "msvc" )
# https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170 # https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170
$flag_all_c = '/TC' $flag_all_c = '/TC'
$flag_all_cpp = '/TP' $flag_all_cpp = '/TP'
$flag_cpp_version = '/std:'
$flag_compile = '/c' $flag_compile = '/c'
$flag_debug = '/Zi' $flag_debug = '/Zi'
$flag_define = '/D' $flag_define = '/D'