34. Listening for Attribute Changes
This commit is contained in:
		| @@ -17,6 +17,197 @@ using namespace gen; | ||||
| #include "GasaGen_UGasaAttributeSet.cpp" | ||||
| #include "GasaGen_ChangeBPActionMenu.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() | ||||
| { | ||||
| @@ -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_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)); | ||||
| @@ -77,6 +269,7 @@ int gen_main() | ||||
|  | ||||
| 	gen_UGasaAttributeSet(); | ||||
| 	gen_FGasaDevOptionsCache(); | ||||
| 	gen_UHostWidgetController(); | ||||
|  | ||||
| 	// One offs | ||||
| 	if (0) | ||||
|   | ||||
| @@ -13,11 +13,13 @@ using namespace gen; | ||||
| #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_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("); | ||||
|   | ||||
| @@ -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 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() | ||||
| { | ||||
| 	CodeType   type_UAttributeSet = def_type( txt("UAttributeSet") ); | ||||
| 	CodeComment generation_notice = def_comment(txt("Generated by GasaGen/GasaGen_UGasaAttributeSet.cpp")); | ||||
|  | ||||
| 	Array<StringCached> attribute_fields = Array<StringCached>::init( GlobalAllocator); | ||||
| 	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"))); | ||||
| 	Array<StringCached> attribute_fields = get_gasa_attribute_fields(); | ||||
|  | ||||
| 	StrC class_name = txt("UGasaAttributeSet"); | ||||
|  | ||||
|   | ||||
| @@ -1950,6 +1950,7 @@ void CodeFn::to_string_def( String& result ) | ||||
| 	if ( ast->Attributes ) | ||||
| 		result.append_fmt( " %S ", ast->Attributes.to_string() ); | ||||
|  | ||||
| 	b32 prefix_specs = false; | ||||
| 	if ( 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 ); | ||||
| 				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" ); | ||||
|  | ||||
| 	if ( ast->ReturnType ) | ||||
| @@ -2000,19 +2003,22 @@ void CodeFn::to_string_fwd( String& result ) | ||||
| 	if ( ast->Attributes ) | ||||
| 		result.append_fmt( "%S ", ast->Attributes.to_string() ); | ||||
|  | ||||
| 	bool prefix_specs = false; | ||||
| 	if ( 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 ); | ||||
| 				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" ); | ||||
| 	} | ||||
| @@ -2894,17 +2900,17 @@ internal void define_constants() | ||||
|  | ||||
| 	access_private       = make_code(); | ||||
| 	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_protected       = make_code(); | ||||
| 	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_public       = make_code(); | ||||
| 	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(); | ||||
|  | ||||
| 	attrib_api_export = def_attributes( code( GEN_API_Export_Code ) ); | ||||
|   | ||||
| @@ -5146,6 +5146,9 @@ Code CodeParam::duplicate() | ||||
|  | ||||
| bool CodeParam::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr && other.ast == nullptr) | ||||
| 		return true; | ||||
|  | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user