Setting up GasaGen in the editor module

issues with clang format...
This commit is contained in:
Edward R. Gonzalez 2024-10-21 22:39:40 -04:00
parent 2522f4df6c
commit c492613179
23 changed files with 27581 additions and 14 deletions

View File

@ -8,10 +8,12 @@
#define internal static #define internal static
#define local_persist static #define local_persist static
#ifndef ccast
#define ccast( Type, Value ) ( *const_cast<(Type)*>( &( Value ) ) ) #define ccast( Type, Value ) ( *const_cast<(Type)*>( &( Value ) ) )
#define pcast( Type, Value ) ( *reinterpret_cast<(Type)*>( &( Value ) ) ) #define pcast( Type, Value ) ( *reinterpret_cast<(Type)*>( &( Value ) ) )
#define rcast( Type, Value ) reinterpret_cast<Type>( Value ) #define rcast( Type, Value ) reinterpret_cast<Type>( Value )
#define scast( Type, Value ) static_cast<Type>( Value ) #define scast( Type, Value ) static_cast<Type>( Value )
#endif
#define bit(position) (1 << position) #define bit(position) (1 << position)

View File

@ -1,4 +1,4 @@
using ModuleRules = UnrealBuildTool.ModuleRules; using ModuleRules = UnrealBuildTool.ModuleRules;
using ReadOnlyTargetRules = UnrealBuildTool.ReadOnlyTargetRules; using ReadOnlyTargetRules = UnrealBuildTool.ReadOnlyTargetRules;
public class GasaEditor : ModuleRules public class GasaEditor : ModuleRules
@ -15,6 +15,7 @@ public class GasaEditor : ModuleRules
"Core", "Core",
"Engine", "Engine",
"CoreUObject", "CoreUObject",
"EditorStyle",
"PropertyEditor", "PropertyEditor",
"SlateCore", "SlateCore",
"Slate", "Slate",
@ -25,5 +26,17 @@ public class GasaEditor : ModuleRules
PublicIncludePaths.Add("GasaEditor"); PublicIncludePaths.Add("GasaEditor");
PrivateDependencyModuleNames.Add("Gasa"); PrivateDependencyModuleNames.Add("Gasa");
}
bWarningsAsErrors = false;
ShadowVariableWarningLevel = UnrealBuildTool.WarningLevel.Warning;
UndefinedIdentifierWarningLevel = UnrealBuildTool.WarningLevel.Warning;
// gencpp related defines
PublicDefinitions.Add("Build_Debug=1");
PublicDefinitions.Add("GEN_TIME=1");
PublicDefinitions.Add("GEN_EXECUTION_EXPRESSION_SUPPORT=0");
PublicDefinitions.Add("GEN_EXPOSE_BACKEND=1");
PublicDefinitions.Add("GEN_PARSER_DISABLE_MACRO_TYPEDEF=0");
}
} }

View File

@ -1,12 +1,66 @@
#include "GasaEditorModule.h" #include "GasaEditorModule.h"
#include "Framework/Commands/Commands.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "Framework/Commands/UICommandList.h"
#include "EditorStyleSet.h"
#include "LevelEditor.h"
#include "EditorDetails/GlobeProgressBarDetails.h" #include "EditorDetails/GlobeProgressBarDetails.h"
#include "GasaGen/GasaGen.h"
#include "UI/GlobeProgressBar.h" #include "UI/GlobeProgressBar.h"
IMPLEMENT_PRIMARY_GAME_MODULE(FGasaEditorModule, GasaEditor, GasaEditor); IMPLEMENT_PRIMARY_GAME_MODULE(FGasaEditorModule, GasaEditor, GasaEditor);
#define LOCTEXT_NAMESPACE "GasaEditor"
class FGasaEditorCommands : public TCommands<FGasaEditorCommands>
{
public:
FGasaEditorCommands()
: TCommands<FGasaEditorCommands>(
TEXT("GasaEditorCommands"),
NSLOCTEXT("Contexts", "GasaEditorCommands", "GASATHON Editor Commands"),
NAME_None,
FAppStyle::GetAppStyleSetName())
{}
virtual void RegisterCommands() override
{
UI_COMMAND(GasaModule_Codegen_Command, "Run GasaGen Codegen", "Execute gasa codegen pass", EUserInterfaceActionType::Button, FInputChord());
}
TSharedPtr<FUICommandInfo> GasaModule_Codegen_Command;
};
void FGasaEditorModule::StartupModule() void FGasaEditorModule::StartupModule()
{ {
// Codegen commands
{
FGasaEditorCommands::Register();
TSharedPtr<FUICommandList> PluginCommands = MakeShareable(new FUICommandList);
PluginCommands->MapAction( FGasaEditorCommands::Get().GasaModule_Codegen_Command,
FExecuteAction::CreateStatic(& Execute_GasaModule_Codegen),
FCanExecuteAction()
);
FLevelEditorModule& LEM = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender);
MenuExtender->AddMenuExtension(
"Tools",
EExtensionHook::First,
PluginCommands,
FMenuExtensionDelegate::CreateLambda([](FMenuBuilder& Builder) {
Builder.AddMenuEntry(FGasaEditorCommands::Get().GasaModule_Codegen_Command);
Builder.AddSeparator(); // Add a separator after your command
})
);
LEM.GetMenuExtensibilityManager()->AddExtender(MenuExtender);
}
FPropertyEditorModule& PropertyEditor = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor"); FPropertyEditorModule& PropertyEditor = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
PropertyEditor.RegisterCustomClassLayout( UGlobeProgressBar::StaticClass()->GetFName() PropertyEditor.RegisterCustomClassLayout( UGlobeProgressBar::StaticClass()->GetFName()
@ -22,4 +76,6 @@ void FGasaEditorModule::ShutdownModule()
PropertyEditor.UnregisterCustomClassLayout(UGlobeProgressBar::StaticClass()->GetFName()); PropertyEditor.UnregisterCustomClassLayout(UGlobeProgressBar::StaticClass()->GetFName());
} }
} }
#undef LOCTEXT_NAMESPACE

View File

@ -12,7 +12,7 @@ public:
static FGasaEditorModule& Get() { static FGasaEditorModule& Get() {
return FModuleManager::LoadModuleChecked<FGasaEditorModule>("GasaEditor"); return FModuleManager::LoadModuleChecked<FGasaEditorModule>("GasaEditor");
} }
protected: protected:
void StartupModule() override; void StartupModule() override;
void ShutdownModule() override; void ShutdownModule() override;

View File

@ -0,0 +1,114 @@
#include "GasaGen.h"
#include "GasaGen_Common.h"
#include "GasaGen_DevOptionsCache.h"
// Editor Module
#include "GasaEditorCommon.h"
global String Project_Path;
global String Root_Path;
global Code UHT_GENERATED_BODY;
global Code UHT_UCLASS;
global Code UHT_UPROPERTY;
global Code UHT_USTRUCT;
global Code UModule_GASA_API;
void Execute_GasaModule_Codegen()
{
Gasa::LogEditor("Executing: Gasa Module code generation.");
gen::init();
FString ue_project_path = FPaths::ConvertRelativePathToFull( FPaths::ProjectDir() );
FPaths::NormalizeDirectoryName(ue_project_path);
char const* ue_ansi_project_path = TCHAR_TO_ANSI( * ue_project_path);
FString ue_root_path = FPaths::GetPath( ue_project_path );
FPaths::NormalizeDirectoryName(ue_root_path);
char const* ue_ansi_rooot_path = TCHAR_TO_ANSI( * ue_project_path);
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() );
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
{
#pragma push_macro("UCLASS")
#pragma push_macro("UPROPERTY")
#pragma push_macro("USTRUCT")
#pragma push_macro("GENERATED_BODY")
#pragma push_macro("GASA_API")
#undef UCLASS
#undef UPROPERTY
#undef USTRUCT
#undef GENERATED_BODY
#undef GASA_API
UHT_UCLASS = code_str( UCLASS() );
UHT_UPROPERTY = code_str( UPROPERTY() );
UHT_USTRUCT = code_str( USTRUCT() );
UHT_GENERATED_BODY = code_str( GENERATED_BODY()\n );
UModule_GASA_API = code_str( GASA_API );
#pragma pop_macro("UCLASS")
#pragma pop_macro("UPROPERTY")
#pragma pop_macro("USTRUCT")
#pragma pop_macro("GENERATED_BODY")
#pragma pop_macro("GASA_API")
}
// Populate Defines
{
PreprocessorDefines.append( get_cached_string(str_DECLARE_CLASS));
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_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_FourParams));
PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams));
PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam));
PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SevenParams));
PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams));
PreprocessorDefines.append( get_cached_string(str_DECLARE_EVENT_ThreeParams));
PreprocessorDefines.append( get_cached_string(str_DECLARE_EVENT_TwoParams));
PreprocessorDefines.append( get_cached_string(str_DECLARE_FUNCTION));
PreprocessorDefines.append( get_cached_string(str_DECLARE_LOG_CATEGORY_EXTERN));
PreprocessorDefines.append( get_cached_string(str_DECLARE_MULTICAST_DELEGATE_OneParam));
PreprocessorDefines.append( get_cached_string(str_DECLARE_MULTICAST_DELEGATE_ThreeParams));
PreprocessorDefines.append( get_cached_string(str_DECLARE_MULTICAST_DELEGATE_TwoParams));
PreprocessorDefines.append( get_cached_string(str_DECLARE_TS_MULTICAST_DELEGATE_OneParam));
PreprocessorDefines.append( get_cached_string(str_DECLARE_TS_MULTICAST_DELEGATE_TwoParams));
PreprocessorDefines.append( get_cached_string(str_DECLARE_TS_MULTICAST_DELEGATE_ThreeParams));
PreprocessorDefines.append( get_cached_string(str_DEFINE_ACTORDESC_TYPE));
PreprocessorDefines.append( get_cached_string(str_DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL));
PreprocessorDefines.append( get_cached_string(str_ENUM_CLASS_FLAGS));
PreprocessorDefines.append( get_cached_string(str_FORCEINLINE_DEBUGGABLE));
// PreprocessorDefines.append( get_cached_string(str_FORCEINLINE));
PreprocessorDefines.append( get_cached_string(str_GENERATED_BODY));
PreprocessorDefines.append( get_cached_string(str_GENERATED_UCLASS_BODY));
PreprocessorDefines.append( get_cached_string(str_GENERATED_USTRUCT_BODY));
PreprocessorDefines.append( get_cached_string(str_PRAGMA_DISABLE_DEPRECATION_WARNINGS));
PreprocessorDefines.append( get_cached_string(str_PRAGMA_ENABLE_DEPRECATION_WARNINGS));
PreprocessorDefines.append( get_cached_string(str_PROPERTY_BINDING_IMPLEMENTATION));
PreprocessorDefines.append( get_cached_string(str_RESULT_DECL));
PreprocessorDefines.append( get_cached_string(str_SLATE_BEGIN_ARGS));
PreprocessorDefines.append( get_cached_string(str_SLATE_END_ARGS));
PreprocessorDefines.append( get_cached_string(str_TEXT));
PreprocessorDefines.append( get_cached_string(str_UCLASS));
PreprocessorDefines.append( get_cached_string(str_UENUM));
PreprocessorDefines.append( get_cached_string(str_UFUNCTION));
PreprocessorDefines.append( get_cached_string(str_UMETA));
PreprocessorDefines.append( get_cached_string(str_UPARAM));
PreprocessorDefines.append( get_cached_string(str_UPROPERTY));
PreprocessorDefines.append( get_cached_string(str_USTRUCT));
PreprocessorDefines.append( get_cached_string(str_UE_REQUIRES));
}
//generate_AttributeSets();
generate_DevOptionsCache();
//generate_HostWidgetController();
gen::deinit();
}

View File

@ -0,0 +1,3 @@
#pragma once
void Execute_GasaModule_Codegen();

View File

@ -0,0 +1,8 @@
#include "GasaGen_AttributeSets.h"
#include "GasaGen_Common.h"
void generate_AttributeSets()
{
}

View File

@ -0,0 +1,3 @@
#pragma once
void generate_attribute_sets();

View File

@ -0,0 +1,131 @@
#pragma once
#include "gencpp/gen.hpp"
#include "gencpp/gen.builder.hpp"
using namespace gen;
#undef check
// Codegen assumes its working directory is the project
#define path_scripts "/scripts/"
#define path_project "/Project/"
#define path_source "/Source/"
#define path_config path_source "Config/"
#define path_module_gasa path_source "Gasa/"
#define path_gasa_ability_system path_module_gasa "AbilitySystem/"
#define path_gasa_actors path_module_gasa "Actors/"
#define path_gasa_characters path_module_gasa "Characters/"
#define path_gasa_game path_module_gasa "Game/"
#define path_gasa_ui path_module_gasa "UI/"
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_ThreeParams = txt("DECLARE_DELEGATE_RetVal_ThreeParams(");
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_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_OneParam = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam(");
constexpr StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SevenParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SevenParams(");
constexpr StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams(");
constexpr StrC str_DECLARE_EVENT_ThreeParams = txt("DECLARE_EVENT_ThreeParams(");
constexpr StrC str_DECLARE_EVENT_TwoParams = txt("DECLARE_EVENT_TwoParams(");
constexpr StrC str_DECLARE_FUNCTION = txt("DECLARE_FUNCTION(");
constexpr StrC str_DECLARE_LOG_CATEGORY_EXTERN = txt("DECLARE_LOG_CATEGORY_EXTERN(");
constexpr StrC str_DECLARE_MULTICAST_DELEGATE_OneParam = txt("DECLARE_MULTICAST_DELEGATE_OneParam(");
constexpr StrC str_DECLARE_MULTICAST_DELEGATE_ThreeParams = txt("DECLARE_MULTICAST_DELEGATE_ThreeParams(");
constexpr StrC str_DECLARE_MULTICAST_DELEGATE_TwoParams = txt("DECLARE_MULTICAST_DELEGATE_TwoParams(");
constexpr StrC str_DECLARE_TS_MULTICAST_DELEGATE_OneParam = txt("DECLARE_TS_MULTICAST_DELEGATE_OneParam(");
constexpr StrC str_DECLARE_TS_MULTICAST_DELEGATE_TwoParams = txt("DECLARE_TS_MULTICAST_DELEGATE_TwoParams(");
constexpr StrC str_DECLARE_TS_MULTICAST_DELEGATE_ThreeParams = txt("DECLARE_TS_MULTICAST_DELEGATE_ThreeParams(");
constexpr StrC str_DEFINE_ACTORDESC_TYPE = txt("DEFINE_ACTORDESC_TYPE(");
constexpr StrC str_DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL = txt("DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(");
constexpr StrC str_ENUM_CLASS_FLAGS = txt("ENUM_CLASS_FLAGS(");
// constexpr StrC str_FORCEINLINE = txt("FORCEINLINE");
constexpr StrC str_FORCEINLINE_DEBUGGABLE = txt("FORCEINLINE_DEBUGGABLE");
constexpr StrC str_GENERATED_BODY = txt("GENERATED_BODY(");
constexpr StrC str_GENERATED_UCLASS_BODY = txt("GENERATED_UCLASS_BODY(");
constexpr StrC str_GENERATED_USTRUCT_BODY = txt("GENERATED_USTRUCT_BODY(");
constexpr StrC str_PRAGMA_DISABLE_DEPRECATION_WARNINGS = txt("PRAGMA_DISABLE_DEPRECATION_WARNINGS");
constexpr StrC str_PRAGMA_ENABLE_DEPRECATION_WARNINGS = txt("PRAGMA_ENABLE_DEPRECATION_WARNINGS");
constexpr StrC str_PROPERTY_BINDING_IMPLEMENTATION = txt("PROPERTY_BINDING_IMPLEMENTATION(");
constexpr StrC str_RESULT_DECL = txt("RESULT_DECL");
constexpr StrC str_SLATE_BEGIN_ARGS = txt("SLATE_BEGIN_ARGS(");
constexpr StrC str_SLATE_END_ARGS = txt("SLATE_END_ARGS(");
constexpr StrC str_TEXT = txt("TEXT(");
constexpr StrC str_UCLASS = txt("UCLASS(");
constexpr StrC str_UENUM = txt("UENUM(");
constexpr StrC str_UFUNCTION = txt("UFUNCTION(");
constexpr StrC str_UMETA = txt("UMETA(");
constexpr StrC str_UPARAM = txt("UPARAM(");
constexpr StrC str_UPROPERTY = txt("UPROPERTY(");
constexpr StrC str_USTRUCT = txt("USTRUCT(");
constexpr StrC str_UE_REQUIRES = txt("UE_REQUIRES(");
#pragma region Globals
extern String Project_Path;
extern String Root_Path;
// These Code objects are created before anything else after gencpp does its initializatioon
extern Code UHT_GENERATED_BODY;
extern Code UHT_UCLASS;
extern Code UHT_UPROPERTY;
extern Code UHT_USTRUCT;
extern Code UModule_GASA_API;
#pragma endregion Globals
inline
CodeBody parse_file( char const* path ) {
String
resolved_path = String::make(GlobalAllocator, StrC(Project_Path));
resolved_path.append(path);
FileContents content = file_read_contents( GlobalAllocator, true, resolved_path );
CodeBody code = parse_global_body( StrC { content.size, (char const*)content.data });
return code;
}
// Automatically handles resolving project path
inline
Builder builder_open(char const* path) {
String
resolved_path = String::make(GlobalAllocator, StrC(Project_Path));
resolved_path.append(path);
return Builder::open( resolved_path );
}
// inline
// CodeConstructor find_constructor( StrC parent_name, )
inline
void format_file( char const* path )
{
String
resolved_path = String::make(GlobalAllocator, StrC(Project_Path));
resolved_path.append(path);
String clang_format_path = String::make(GlobalAllocator, StrC(Root_Path));
clang_format_path.append("/scripts/.clang-format");
// Need to execute clang format on the generated file to get it to match the original.
#define clang_format "clang-format "
#define cf_format_inplace "-i "
#define cf_verbose "-verbose "
String command = String::make( GlobalAllocator, clang_format );
command.append( cf_format_inplace );
command.append_fmt("-style=file:%S ", *StrC(clang_format_path));
command.append( cf_verbose );
command.append( resolved_path );
log_fmt("\tRunning clang-format on file:\n");
system( command );
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_format_inplace
#undef cf_style
#undef cf_verbse
}

View File

@ -0,0 +1,169 @@
#include "GasaGen_DevOptionsCache.h"
#include "GasaGen_Common.h"
#pragma push_macro("GASA_API")
#pragma push_macro("ensureMsgf")
#undef GASA_API
#undef ensureMsgf
PRAGMA_DISABLE_OPTIMIZATION
void generate_DevOptionsCache()
{
Array<CodeVar> GasaDevOptions_UPROPERTIES = Array<CodeVar>::init(GlobalAllocator);
{
CodeBody header_GasaDevOptions = parse_file( path_module_gasa "GasaDevOptions.h" );
CodeClass UGasaDevOptions = NoCode;
for (Code entry : header_GasaDevOptions)
{
if ( entry->Type == ECode::Class && entry->Name.starts_with( txt("UGasaDevOptions")) )
{
UGasaDevOptions = entry.cast<CodeClass>();
break;
}
}
for (Code member = UGasaDevOptions->Body.begin(); member != UGasaDevOptions->Body.end(); ++ member)
{
if ( member->Type == ECode::Untyped && member->Name.starts_with(str_UPROPERTY) )
++ member;
if ( member->Type == ECode::Variable
&& ( member->ValueType->Name.starts_with( txt("TArray< TSoftObjectPtr"))
|| member->ValueType->Name.starts_with( txt("TSoftClassPtr"))
|| member->ValueType->Name.starts_with( txt("TSoftObjectPtr")) )
)
GasaDevOptions_UPROPERTIES.append(member.cast<CodeVar>());
}
}
CodeComment generation_notice = def_comment(txt("Generated by GasaGen/GasaGen_DevOptionsCache.cpp"));
CodeType t_UClassPtr = parse_type(code(UClass*));
CodeType t_UObjectPtr = parse_type(code(UObject*));
CodeType t_Array_UObjectPtr = parse_type(code(TArray< UObject* >));
Builder header = builder_open( path_module_gasa "GasaDevOptionsCache.h" );
{
header.print( generation_notice );
header.print( pragma_once );
header.print( fmt_newline );
header.print( def_include(txt("GasaDevOptionsCache.generated.h")));
header.print( fmt_newline );
header.print( UHT_USTRUCT );
CodeStruct FGasaDevOptionsCache;
{
CodeBody body = def_body(ECode::Struct_Body);
{
body.append(UHT_GENERATED_BODY);
body.append(fmt_newline);
for (CodeVar var : GasaDevOptions_UPROPERTIES)
{
if ( var->ValueType->Name.starts_with( txt("TSoftClassPtr") )) {
body.append(UHT_UPROPERTY);
body.append( def_variable(t_UClassPtr, var->Name));
}
if ( var->ValueType->Name.starts_with( txt("TSoftObjectPtr") )) {
body.append(UHT_UPROPERTY);
body.append( def_variable(t_UObjectPtr, var->Name));
}
if ( var->ValueType->Name.starts_with( txt("TArray< TSoftObjectPtr") )) {
body.append(UHT_UPROPERTY);
body.append( def_variable(t_Array_UObjectPtr, var->Name));
}
}
body.append(fmt_newline);
body.append( parse_function(code( void CachedDevOptions(); )));
}
FGasaDevOptionsCache = parse_struct( token_fmt( "body", (StrC)body.to_string(), stringize(
struct GASA_API FGasaDevOptionsCache {
<body>
};
)));
}
header.print(FGasaDevOptionsCache);
header.print( fmt_newline );
header.write();
format_file( path_module_gasa "GasaDevOptionsCache.h" );
}
Builder source = builder_open( path_module_gasa "GasaDevOptionsCache.cpp" );
{
Array<CodeInclude> GasaDevOptions_Includes = Array<CodeInclude>::init(GlobalAllocator);
{
CodeBody source_GasaDevOptions = parse_file( path_module_gasa "GasaDevOptions.cpp");
for ( Code entry : source_GasaDevOptions )
{
if ( entry->Type == ECode::Preprocess_Include )
GasaDevOptions_Includes.append( entry.cast<CodeInclude>() );
}
}
source.print( generation_notice );
source.print( def_include(txt("GasaDevOptionsCache.h")));
source.print(fmt_newline);
for ( CodeInclude include : GasaDevOptions_Includes ) {
source.print( include );
}
source.print( parse_using(code( using namespace Gasa; )));
source.print(fmt_newline);
CodeBody cached_property_assignments = def_body(ECode::Function_Body);
{
cached_property_assignments.append(fmt_newline);
cached_property_assignments.append(fmt_newline);
for (CodeVar var : GasaDevOptions_UPROPERTIES)
{
if ( var->ValueType.to_string().starts_with(txt("TArray")) )
{
#pragma push_macro("TEXT")
#undef TEXT
Code assignment = code_fmt( "property_array", (StrC)var->Name, stringize(
for ( auto& entry : DevOpts-> <property_array> )
{
<property_array>.Push( entry.LoadSynchronous() );
ensureMsgf(entry != nullptr, TEXT("An <property_array> entry is null, DO NOT RUN PIE or else you may get a crash if not handled in BP or C++"));
}
));
#pragma pop_macro("TEXT")
cached_property_assignments.append(assignment);
cached_property_assignments.append(fmt_newline);
cached_property_assignments.append(fmt_newline);
continue;
}
#pragma push_macro("TEXT")
#undef TEXT
Code assignment = code_fmt( "property", (StrC)var->Name, stringize(
<property> = DevOpts-> <property>.LoadSynchronous();
ensureMsgf(<property> != nullptr, TEXT("<property> is null, DO NOT RUN PIE or else you may get a crash if not handled in BP or C++"));
));
#pragma pop_macro("TEXT")
cached_property_assignments.append(assignment);
cached_property_assignments.append(fmt_newline);
cached_property_assignments.append(fmt_newline);
}
}
CodeFn CachedDevOptions = parse_function( token_fmt(
"cached_property_assignments", (StrC)cached_property_assignments.to_string(),
stringize(
void FGasaDevOptionsCache::CachedDevOptions()
{
UGasaDevOptions* DevOpts = GetMutDevOptions();
<cached_property_assignments>
Tag_GlobalPPV = DevOpts->Tag_GlobalPPV;
})
));
source.print(CachedDevOptions);
source.write();
format_file( path_module_gasa "GasaDevOptionsCache.cpp" );
}
}
PRAGMA_ENABLE_OPTIMIZATION
#pragma pop_macro("ensureMsgf")
#pragma pop_macro("GASA_API")

View File

@ -0,0 +1,3 @@
#pragma once
void generate_DevOptionsCache();

View File

@ -0,0 +1,88 @@
// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)
#include "gen.builder.hpp"
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-const-variable"
#pragma clang diagnostic ignored "-Wswitch"
#pragma clang diagnostic ignored "-Wunused-variable"
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wvarargs"
#pragma clang diagnostic ignored "-Wunused-function"
#endif
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wcomment"
#pragma GCC diagnostic ignored "-Wswitch"
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif
GEN_NS_BEGIN
Builder Builder::open( char const* path )
{
Builder result;
FileError error = file_open_mode( &result.File, EFileMode_WRITE, path );
if ( error != EFileError_NONE )
{
log_failure( "gen::File::open - Could not open file: %s", path );
return result;
}
result.Buffer = String::make_reserve( GlobalAllocator, Builder_StrBufferReserve );
// log_fmt("$Builder - Opened file: %s\n", result.File.filename );
return result;
}
void Builder::pad_lines( s32 num )
{
Buffer.append( "\n" );
}
void Builder::print( Code code )
{
String str = code->to_string();
// const sw len = str.length();
// log_fmt( "%s - print: %.*s\n", File.filename, len > 80 ? 80 : len, str.Data );
Buffer.append( str );
}
void Builder::print_fmt( char const* fmt, ... )
{
sw res;
char buf[GEN_PRINTF_MAXLEN] = { 0 };
va_list va;
va_start( va, fmt );
res = str_fmt_va( buf, count_of( buf ) - 1, fmt, va ) - 1;
va_end( va );
// log_fmt( "$%s - print_fmt: %.*s\n", File.filename, res > 80 ? 80 : res, buf );
Buffer.append( buf, res );
}
void Builder::write()
{
b32 result = file_write( &File, Buffer, Buffer.length() );
if ( result == false )
log_failure( "gen::File::write - Failed to write to file: %s\n", file_name( &File ) );
log_fmt( "Generated: %s\n", File.filename );
file_close( &File );
Buffer.free();
}
GEN_NS_END
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

View File

@ -0,0 +1,50 @@
// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)
#pragma once
#include "gen.hpp"
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-const-variable"
#pragma clang diagnostic ignored "-Wswitch"
#pragma clang diagnostic ignored "-Wunused-variable"
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wvarargs"
#pragma clang diagnostic ignored "-Wunused-function"
#endif
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wcomment"
#pragma GCC diagnostic ignored "-Wswitch"
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif
GEN_NS_BEGIN
struct Builder
{
FileInfo File;
String Buffer;
static Builder open( char const* path );
void pad_lines( s32 num );
void print( Code );
void print_fmt( char const* fmt, ... );
void write();
};
GEN_NS_END
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,619 @@
// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)
#pragma once
#include "gen.hpp"
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-const-variable"
#pragma clang diagnostic ignored "-Wswitch"
#pragma clang diagnostic ignored "-Wunused-variable"
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wvarargs"
#pragma clang diagnostic ignored "-Wunused-function"
#endif
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wcomment"
#pragma GCC diagnostic ignored "-Wswitch"
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif
GEN_NS_BEGIN
#pragma region ADT
enum ADT_Type : u32
{
EADT_TYPE_UNINITIALISED, /* node was not initialised, this is a programming error! */
EADT_TYPE_ARRAY,
EADT_TYPE_OBJECT,
EADT_TYPE_STRING,
EADT_TYPE_MULTISTRING,
EADT_TYPE_INTEGER,
EADT_TYPE_REAL,
};
enum ADT_Props : u32
{
EADT_PROPS_NONE,
EADT_PROPS_NAN,
EADT_PROPS_NAN_NEG,
EADT_PROPS_INFINITY,
EADT_PROPS_INFINITY_NEG,
EADT_PROPS_FALSE,
EADT_PROPS_TRUE,
EADT_PROPS_NULL,
EADT_PROPS_IS_EXP,
EADT_PROPS_IS_HEX,
// Used internally so that people can fill in real numbers they plan to write.
EADT_PROPS_IS_PARSED_REAL,
};
enum ADT_NamingStyle : u32
{
EADT_NAME_STYLE_DOUBLE_QUOTE,
EADT_NAME_STYLE_SINGLE_QUOTE,
EADT_NAME_STYLE_NO_QUOTES,
};
enum ADT_AssignStyle : u32
{
EADT_ASSIGN_STYLE_COLON,
EADT_ASSIGN_STYLE_EQUALS,
EADT_ASSIGN_STYLE_LINE,
};
enum ADT_DelimStyle : u32
{
EADT_DELIM_STYLE_COMMA,
EADT_DELIM_STYLE_LINE,
EADT_DELIM_STYLE_NEWLINE,
};
enum ADT_Error : u32
{
EADT_ERROR_NONE,
EADT_ERROR_INTERNAL,
EADT_ERROR_ALREADY_CONVERTED,
EADT_ERROR_INVALID_TYPE,
EADT_ERROR_OUT_OF_MEMORY,
};
struct ADT_Node
{
char const* name;
struct ADT_Node* parent;
/* properties */
ADT_Type type : 4;
u8 props : 4;
#ifndef GEN_PARSER_DISABLE_ANALYSIS
u8 cfg_mode : 1;
u8 name_style : 2;
u8 assign_style : 2;
u8 delim_style : 2;
u8 delim_line_width : 4;
u8 assign_line_width : 4;
#endif
/* adt data */
union
{
char const* string;
Array<ADT_Node> nodes; ///< zpl_array
struct
{
union
{
f64 real;
s64 integer;
};
#ifndef GEN_PARSER_DISABLE_ANALYSIS
/* number analysis */
s32 base;
s32 base2;
u8 base2_offset : 4;
s8 exp : 4;
u8 neg_zero : 1;
u8 lead_digit : 1;
#endif
};
};
};
/* ADT NODE LIMITS
* delimiter and assignment segment width is limited to 128 whitespace symbols each.
* real number limits decimal position to 128 places.
* real number exponent is limited to 64 digits.
*/
/**
* @brief Initialise an ADT object or array
*
* @param node
* @param backing Memory allocator used for descendants
* @param name Node's name
* @param is_array
* @return error code
*/
u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32 is_array );
/**
* @brief Destroy an ADT branch and its descendants
*
* @param node
* @return error code
*/
u8 adt_destroy_branch( ADT_Node* node );
/**
* @brief Initialise an ADT leaf
*
* @param node
* @param name Node's name
* @param type Node's type (use zpl_adt_make_branch for container nodes)
* @return error code
*/
u8 adt_make_leaf( ADT_Node* node, char const* name, ADT_Type type );
/**
* @brief Fetch a node using provided URI string.
*
* This method uses a basic syntax to fetch a node from the ADT. The following features are available
* to retrieve the data:
*
* - "a/b/c" navigates through objects "a" and "b" to get to "c"
* - "arr/[foo=123]/bar" iterates over "arr" to find any object with param "foo" that matches the value "123", then gets its field called "bar"
* - "arr/3" retrieves the 4th element in "arr"
* - "arr/[apple]" retrieves the first element of value "apple" in "arr"
*
* @param node ADT node
* @param uri Locator string as described above
* @return zpl_adt_node*
*
* @see code/apps/examples/json_get.c
*/
ADT_Node* adt_query( ADT_Node* node, char const* uri );
/**
* @brief Find a field node within an object by the given name.
*
* @param node
* @param name
* @param deep_search Perform search recursively
* @return zpl_adt_node * node
*/
ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search );
/**
* @brief Allocate an unitialised node within a container at a specified index.
*
* @param parent
* @param index
* @return zpl_adt_node * node
*/
ADT_Node* adt_alloc_at( ADT_Node* parent, sw index );
/**
* @brief Allocate an unitialised node within a container.
*
* @param parent
* @return zpl_adt_node * node
*/
ADT_Node* adt_alloc( ADT_Node* parent );
/**
* @brief Move an existing node to a new container at a specified index.
*
* @param node
* @param new_parent
* @param index
* @return zpl_adt_node * node
*/
ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, sw index );
/**
* @brief Move an existing node to a new container.
*
* @param node
* @param new_parent
* @return zpl_adt_node * node
*/
ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent );
/**
* @brief Swap two nodes.
*
* @param node
* @param other_node
* @return
*/
void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node );
/**
* @brief Remove node from container.
*
* @param node
* @return
*/
void adt_remove_node( ADT_Node* node );
/**
* @brief Initialise a node as an object
*
* @param obj
* @param name
* @param backing
* @return
*/
b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing );
/**
* @brief Initialise a node as an array
*
* @param obj
* @param name
* @param backing
* @return
*/
b8 adt_set_arr( ADT_Node* obj, char const* name, AllocatorInfo backing );
/**
* @brief Initialise a node as a string
*
* @param obj
* @param name
* @param value
* @return
*/
b8 adt_set_str( ADT_Node* obj, char const* name, char const* value );
/**
* @brief Initialise a node as a float
*
* @param obj
* @param name
* @param value
* @return
*/
b8 adt_set_flt( ADT_Node* obj, char const* name, f64 value );
/**
* @brief Initialise a node as a signed integer
*
* @param obj
* @param name
* @param value
* @return
*/
b8 adt_set_int( ADT_Node* obj, char const* name, s64 value );
/**
* @brief Append a new node to a container as an object
*
* @param parent
* @param name
* @return*
*/
ADT_Node* adt_append_obj( ADT_Node* parent, char const* name );
/**
* @brief Append a new node to a container as an array
*
* @param parent
* @param name
* @return*
*/
ADT_Node* adt_append_arr( ADT_Node* parent, char const* name );
/**
* @brief Append a new node to a container as a string
*
* @param parent
* @param name
* @param value
* @return*
*/
ADT_Node* adt_append_str( ADT_Node* parent, char const* name, char const* value );
/**
* @brief Append a new node to a container as a float
*
* @param parent
* @param name
* @param value
* @return*
*/
ADT_Node* adt_append_flt( ADT_Node* parent, char const* name, f64 value );
/**
* @brief Append a new node to a container as a signed integer
*
* @param parent
* @param name
* @param value
* @return*
*/
ADT_Node* adt_append_int( ADT_Node* parent, char const* name, s64 value );
/* parser helpers */
/**
* @brief Parses a text and stores the result into an unitialised node.
*
* @param node
* @param base
* @return*
*/
char* adt_parse_number( ADT_Node* node, char* base );
/**
* @brief Parses a text and stores the result into an unitialised node.
* This function expects the entire input to be a number.
*
* @param node
* @param base
* @return*
*/
char* adt_parse_number_strict( ADT_Node* node, char* base_str );
/**
* @brief Parses and converts an existing string node into a number.
*
* @param node
* @return
*/
ADT_Error adt_str_to_number( ADT_Node* node );
/**
* @brief Parses and converts an existing string node into a number.
* This function expects the entire input to be a number.
*
* @param node
* @return
*/
ADT_Error adt_str_to_number_strict( ADT_Node* node );
/**
* @brief Prints a number into a file stream.
*
* The provided file handle can also be a memory mapped stream.
*
* @see zpl_file_stream_new
* @param file
* @param node
* @return
*/
ADT_Error adt_print_number( FileInfo* file, ADT_Node* node );
/**
* @brief Prints a string into a file stream.
*
* The provided file handle can also be a memory mapped stream.
*
* @see zpl_file_stream_new
* @param file
* @param node
* @param escaped_chars
* @param escape_symbol
* @return
*/
ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_chars, char const* escape_symbol );
#pragma endregion ADT
#pragma region CSV
enum CSV_Error : u32
{
ECSV_Error__NONE,
ECSV_Error__INTERNAL,
ECSV_Error__UNEXPECTED_END_OF_INPUT,
ECSV_Error__MISMATCHED_ROWS,
};
typedef ADT_Node CSV_Object;
GEN_DEF_INLINE u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header );
u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header, char delim );
void csv_free( CSV_Object* obj );
GEN_DEF_INLINE void csv_write( FileInfo* file, CSV_Object* obj );
GEN_DEF_INLINE String csv_write_string( AllocatorInfo a, CSV_Object* obj );
void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delim );
String csv_write_string_delimiter( AllocatorInfo a, CSV_Object* obj, char delim );
/* inline */
GEN_IMPL_INLINE u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header )
{
return csv_parse_delimiter( root, text, allocator, has_header, ',' );
}
GEN_IMPL_INLINE void csv_write( FileInfo* file, CSV_Object* obj )
{
csv_write_delimiter( file, obj, ',' );
}
GEN_IMPL_INLINE String csv_write_string( AllocatorInfo a, CSV_Object* obj )
{
return csv_write_string_delimiter( a, obj, ',' );
}
#pragma endregion CSV
// This is a simple file reader that reads the entire file into memory.
// It has an extra option to skip the first few lines for undesired includes.
// This is done so that includes can be kept in dependency and component files so that intellisense works.
Code scan_file( char const* path )
{
FileInfo file;
FileError error = file_open_mode( &file, EFileMode_READ, path );
if ( error != EFileError_NONE )
{
GEN_FATAL( "scan_file: Could not open: %s", path );
}
sw fsize = file_size( &file );
if ( fsize <= 0 )
{
GEN_FATAL( "scan_file: %s is empty", path );
}
String str = String::make_reserve( GlobalAllocator, fsize );
file_read( &file, str, fsize );
str.get_header().Length = fsize;
// Skip GEN_INTELLISENSE_DIRECTIVES preprocessor blocks
// Its designed so that the directive should be the first thing in the file.
// Anything that comes before it will also be omitted.
{
#define current ( *scanner )
#define matched 0
#define move_fwd() \
do \
{ \
++scanner; \
--left; \
} while ( 0 )
const StrC directive_start = txt( "ifdef" );
const StrC directive_end = txt( "endif" );
const StrC def_intellisense = txt( "GEN_INTELLISENSE_DIRECTIVES" );
bool found_directive = false;
char const* scanner = str.Data;
s32 left = fsize;
while ( left )
{
// Processing directive.
if ( current == '#' )
{
move_fwd();
while ( left && char_is_space( current ) )
move_fwd();
if ( ! found_directive )
{
if ( left && str_compare( scanner, directive_start.Ptr, directive_start.Len ) == matched )
{
scanner += directive_start.Len;
left -= directive_start.Len;
while ( left && char_is_space( current ) )
move_fwd();
if ( left && str_compare( scanner, def_intellisense.Ptr, def_intellisense.Len ) == matched )
{
scanner += def_intellisense.Len;
left -= def_intellisense.Len;
found_directive = true;
}
}
// Skip to end of line
while ( left && current != '\r' && current != '\n' )
move_fwd();
move_fwd();
if ( left && current == '\n' )
move_fwd();
continue;
}
if ( left && str_compare( scanner, directive_end.Ptr, directive_end.Len ) == matched )
{
scanner += directive_end.Len;
left -= directive_end.Len;
// Skip to end of line
while ( left && current != '\r' && current != '\n' )
move_fwd();
move_fwd();
if ( left && current == '\n' )
move_fwd();
// sptr skip_size = fsize - left;
if ( ( scanner + 2 ) >= ( str.Data + fsize ) )
{
mem_move( str, scanner, left );
str.get_header().Length = left;
break;
}
mem_move( str, scanner, left );
str.get_header().Length = left;
break;
}
}
move_fwd();
}
#undef move_fwd
#undef matched
#undef current
}
file_close( &file );
return untyped_str( str );
}
#if 0
struct CodeFile
{
using namespace Parser;
String FilePath;
TokArray Tokens;
Array<ParseFailure> ParseFailures;
Code CodeRoot;
};
namespace Parser
{
struct ParseFailure
{
String Reason;
Code Node;
};
}
CodeFile scan_file( char const* path )
{
using namespace Parser;
CodeFile
result = {};
result.FilePath = String::make( GlobalAllocator, path );
Code code = scan_file( path );
result.CodeRoot = code;
ParseContext context = parser_get_last_context();
result.Tokens = context.Tokens;
result.ParseFailures = context.Failures;
return result;
}
#endif
GEN_NS_END
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

View File

@ -2,7 +2,7 @@
#if GASA_INTELLISENSE_DIRECTIVES #if GASA_INTELLISENSE_DIRECTIVES
#pragma once #pragma once
#include "gen.hpp" #include "gen.hpp"
#include "GasaGenCommon.cpp" // #include "GasaGenCommon.cpp"
using namespace gen; using namespace gen;
#endif #endif

View File

@ -27,7 +27,8 @@ void gen_FGasaDevOptionsCache()
if ( member->Type == ECode::Untyped && member->Name.starts_with(str_UPROPERTY) ) if ( member->Type == ECode::Untyped && member->Name.starts_with(str_UPROPERTY) )
++ member; ++ member;
if ( member->Type == ECode::Variable if ( member->Type == ECode::Variable
&& ( member->ValueType->Name.starts_with( txt("TSoftClassPtr")) && ( member->ValueType->Name.starts_with( txt("TArray< TSoftObjectPtr"))
|| member->ValueType->Name.starts_with( txt("TSoftClassPtr"))
|| member->ValueType->Name.starts_with( txt("TSoftObjectPtr")) ) || member->ValueType->Name.starts_with( txt("TSoftObjectPtr")) )
) )
GasaDevOptions_UPROPERTIES.append(member.cast<CodeVar>()); GasaDevOptions_UPROPERTIES.append(member.cast<CodeVar>());
@ -36,6 +37,10 @@ void gen_FGasaDevOptionsCache()
CodeComment generation_notice = def_comment(txt("Generated by GasaGen/GasaGen_DevOptionsCache.cpp")); CodeComment generation_notice = def_comment(txt("Generated by GasaGen/GasaGen_DevOptionsCache.cpp"));
CodeType t_UClassPtr = parse_type(code(UClass*));
CodeType t_UObjectPtr = parse_type(code(UObject*));
CodeType t_Array_UObjectPtr = parse_type(code(TArray< UObject* >));
Builder header = Builder::open( path_module_gasa "GasaDevOptionsCache.h" ); Builder header = Builder::open( path_module_gasa "GasaDevOptionsCache.h" );
{ {
header.print( generation_notice ); header.print( generation_notice );
@ -49,9 +54,6 @@ void gen_FGasaDevOptionsCache()
{ {
CodeBody body = def_body(ECode::Struct_Body); CodeBody body = def_body(ECode::Struct_Body);
{ {
CodeType t_UClassPtr = parse_type(code(UClass*));
CodeType t_UObjectPtr = parse_type(code(UObject*));
body.append(UHT_GENERATED_BODY); body.append(UHT_GENERATED_BODY);
body.append(fmt_newline); body.append(fmt_newline);
for (CodeVar var : GasaDevOptions_UPROPERTIES) for (CodeVar var : GasaDevOptions_UPROPERTIES)
@ -64,6 +66,10 @@ void gen_FGasaDevOptionsCache()
body.append(UHT_UPROPERTY); body.append(UHT_UPROPERTY);
body.append( def_variable(t_UObjectPtr, var->Name)); body.append( def_variable(t_UObjectPtr, var->Name));
} }
if ( var->ValueType->Name.starts_with( txt("TArray< TSoftObjectPtr") )) {
body.append(UHT_UPROPERTY);
body.append( def_variable(t_Array_UObjectPtr, var->Name));
}
} }
body.append(fmt_newline); body.append(fmt_newline);
body.append( parse_function(code( void CachedDevOptions(); ))); body.append( parse_function(code( void CachedDevOptions(); )));
@ -107,6 +113,25 @@ void gen_FGasaDevOptionsCache()
cached_property_assignments.append(fmt_newline); cached_property_assignments.append(fmt_newline);
for (CodeVar var : GasaDevOptions_UPROPERTIES) for (CodeVar var : GasaDevOptions_UPROPERTIES)
{ {
if ( var->ValueType.to_string().starts_with(txt("TArray")) )
{
#pragma push_macro("TEXT")
#undef TEXT
Code assignment = code_fmt( "property_array", (StrC)var->Name, stringize(
for ( auto& entry : DevOpts-> <property_array> )
{
<property_array>.Push( entry.LoadSynchronous() );
ensureMsgf(entry != nullptr, TEXT("An <property_array> entry is null, DO NOT RUN PIE or else you may get a crash if not handled in BP or C++"));
}
));
#pragma pop_macro("TEXT")
cached_property_assignments.append(assignment);
cached_property_assignments.append(fmt_newline);
cached_property_assignments.append(fmt_newline);
continue;
}
#pragma push_macro("TEXT") #pragma push_macro("TEXT")
#undef TEXT #undef TEXT
Code assignment = code_fmt( "property", (StrC)var->Name, stringize( Code assignment = code_fmt( "property", (StrC)var->Name, stringize(

View File

@ -335,8 +335,6 @@ void gen_UGasaAttributeSet()
Super::PreAttributeChange(Attribute, NewValue); Super::PreAttributeChange(Attribute, NewValue);
<attribute_clamps> <attribute_clamps>
PreAttributeChange_Custom();
} }
))); )));
@ -348,8 +346,6 @@ void gen_UGasaAttributeSet()
Props.Populate(Data); Props.Populate(Data);
<attribute_clamps> <attribute_clamps>
PostAttributeChange_Custom();
} }
))); )));
} }

View File

@ -1106,5 +1106,4 @@ String csv_write_string_delimiter( AllocatorInfo a, CSV_Object* obj, char delimi
#pragma endregion CSV #pragma endregion CSV
#include "scanner.hpp"
GEN_NS_END GEN_NS_END