A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
VaRest_BreakJson.cpp
Go to the documentation of this file.
1// Copyright 2014-2019 Vladimir Alyamkin. All Rights Reserved.
2// Original code by https://github.com/unktomi
3
4#include "VaRest_BreakJson.h"
5
6#include "BlueprintActionDatabaseRegistrar.h"
7#include "BlueprintNodeSpawner.h"
8#include "EdGraph/EdGraph.h"
9#include "EdGraph/EdGraphNodeUtils.h" // for FNodeTextCache
10#include "EdGraphSchema_K2.h"
11#include "EdGraphUtilities.h"
12#include "EditorCategoryUtils.h"
13#include "KismetCompiler.h"
14#include "Runtime/Launch/Resources/Version.h"
15
16#define LOCTEXT_NAMESPACE "VaRest_BreakJson"
17
19{
20
21public:
22 FKCHandler_BreakJson(FKismetCompilerContext& InCompilerContext)
23 : FNodeHandlingFunctor(InCompilerContext)
24 {
25 }
26
27 virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override
28 {
29 UEdGraphPin* InputPin = nullptr;
30
31 for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex)
32 {
33 UEdGraphPin* Pin = Node->Pins[PinIndex];
34 if (Pin && (EGPD_Input == Pin->Direction))
35 {
36 InputPin = Pin;
37 break;
38 }
39 }
40
41 UEdGraphPin* InNet = FEdGraphUtilities::GetNetFromPin(InputPin);
42 UClass* Class = Cast<UClass>(StaticLoadObject(UClass::StaticClass(), nullptr, TEXT("class'VaRest.VaRestJsonObject'")));
43
44 FBPTerminal** SourceTerm = Context.NetMap.Find(InNet);
45 if (SourceTerm == nullptr)
46 {
47 return;
48 }
49
50 for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex)
51 {
52 UEdGraphPin* Pin = Node->Pins[PinIndex];
53 if (Pin && (EGPD_Output == Pin->Direction))
54 {
55 if (Pin->LinkedTo.Num() < 1)
56 {
57 continue;
58 }
59
60 FBPTerminal** Target = Context.NetMap.Find(Pin);
61
62 const FName& FieldName = Pin->PinName;
63 const FName& FieldType = Pin->PinType.PinCategory;
64
65 FBPTerminal* FieldNameTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
66 FieldNameTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_String;
67 FieldNameTerm->SourcePin = Pin;
68
69 FieldNameTerm->Name = FieldName.ToString();
70 FieldNameTerm->TextLiteral = FText::FromName(FieldName);
71
72 FBlueprintCompiledStatement& Statement = Context.AppendStatementForNode(Node);
73 FName FunctionName;
74
75 const bool bIsArray = Pin->PinType.ContainerType == EPinContainerType::Array;
76 if (FieldType == CompilerContext.GetSchema()->PC_Boolean)
77 {
78 FunctionName = bIsArray ? TEXT("GetBoolArrayField") : TEXT("GetBoolField");
79 }
80 else if (FieldType == CompilerContext.GetSchema()->PC_Float)
81 {
82 FunctionName = bIsArray ? TEXT("GetNumberArrayField") : TEXT("GetNumberField");
83 }
84 else if (FieldType == CompilerContext.GetSchema()->PC_String)
85 {
86 FunctionName = bIsArray ? TEXT("GetStringArrayField") : TEXT("GetStringField");
87 }
88 else if (FieldType == CompilerContext.GetSchema()->PC_Object)
89 {
90 FunctionName = bIsArray ? TEXT("GetObjectArrayField") : TEXT("GetObjectField");
91 }
92 else
93 {
94 continue;
95 }
96
97 UFunction* FunctionPtr = Class->FindFunctionByName(FunctionName);
98 Statement.Type = KCST_CallFunction;
99 Statement.FunctionToCall = FunctionPtr;
100 Statement.FunctionContext = *SourceTerm;
101 Statement.bIsParentContext = false;
102 Statement.LHS = *Target;
103 Statement.RHS.Add(FieldNameTerm);
104 }
105 }
106 }
107
108 FBPTerminal* RegisterInputTerm(FKismetFunctionContext& Context, UVaRest_BreakJson* Node)
109 {
110 // Find input pin
111 UEdGraphPin* InputPin = nullptr;
112 for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex)
113 {
114 UEdGraphPin* Pin = Node->Pins[PinIndex];
115 if (Pin && (EGPD_Input == Pin->Direction))
116 {
117 InputPin = Pin;
118 break;
119 }
120 }
121 check(NULL != InputPin);
122
123 // Find structure source net
124 UEdGraphPin* Net = FEdGraphUtilities::GetNetFromPin(InputPin);
125 FBPTerminal** TermPtr = Context.NetMap.Find(Net);
126
127 if (!TermPtr)
128 {
129 FBPTerminal* Term = Context.CreateLocalTerminalFromPinAutoChooseScope(Net, Context.NetNameMap->MakeValidName(Net));
130
131 Context.NetMap.Add(Net, Term);
132
133 return Term;
134 }
135
136 return *TermPtr;
137 }
138
139 void RegisterOutputTerm(FKismetFunctionContext& Context, UEdGraphPin* OutputPin, FBPTerminal* ContextTerm)
140 {
141 FBPTerminal* Term = Context.CreateLocalTerminalFromPinAutoChooseScope(OutputPin, Context.NetNameMap->MakeValidName(OutputPin));
142 Context.NetMap.Add(OutputPin, Term);
143 }
144
145 virtual void RegisterNets(FKismetFunctionContext& Context, UEdGraphNode* InNode) override
146 {
147 UVaRest_BreakJson* Node = Cast<UVaRest_BreakJson>(InNode);
148 FNodeHandlingFunctor::RegisterNets(Context, Node);
149
150 check(NULL != Node);
151
152 if (FBPTerminal* StructContextTerm = RegisterInputTerm(Context, Node))
153 {
154 for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex)
155 {
156 UEdGraphPin* Pin = Node->Pins[PinIndex];
157 if (nullptr != Pin && EGPD_Output == Pin->Direction)
158 {
159 RegisterOutputTerm(Context, Pin, StructContextTerm);
160 }
161 }
162 }
163 }
164};
165
169UVaRest_BreakJson::UVaRest_BreakJson(const FObjectInitializer& ObjectInitializer)
170 : Super(ObjectInitializer)
171{
172}
173
174FNodeHandlingFunctor* UVaRest_BreakJson::CreateNodeHandler(class FKismetCompilerContext& CompilerContext) const
175{
176 return new FKCHandler_BreakJson(CompilerContext);
177}
178
180{
181 const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
182
183 UClass* Class = Cast<UClass>(StaticLoadObject(UClass::StaticClass(), nullptr, TEXT("class'VaRest.VaRestJsonObject'")));
184 UEdGraphPin* Pin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), Class, TEXT("Target"));
185
186 K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin);
187
189}
190
192{
193 return FLinearColor(255.0f, 255.0f, 0.0f);
194}
195
196void UVaRest_BreakJson::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
197{
198 const FName PropertyName = (PropertyChangedEvent.Property != nullptr) ? PropertyChangedEvent.Property->GetFName() : NAME_None;
199 if (PropertyName == GET_MEMBER_NAME_STRING_CHECKED(UVaRest_BreakJson, Outputs) ||
200 PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FVaRest_NamedType, Name) ||
201 PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FVaRest_NamedType, Type) ||
202 PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FVaRest_NamedType, bIsArray))
203 {
204 ReconstructNode();
205 GetGraph()->NotifyGraphChanged();
206 }
207
208 Super::PostEditChangeProperty(PropertyChangedEvent);
209}
210
211void UVaRest_BreakJson::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
212{
213 // actions get registered under specific object-keys; the idea is that
214 // actions might have to be updated (or deleted) if their object-key is
215 // mutated (or removed)... here we use the node's class (so if the node
216 // type disappears, then the action should go with it)
217 UClass* ActionKey = GetClass();
218
219 // to keep from needlessly instantiating a UBlueprintNodeSpawner, first
220 // check to make sure that the registrar is looking for actions of this type
221 // (could be regenerating actions for a specific asset, and therefore the
222 // registrar would only accept actions corresponding to that asset)
223 if (ActionRegistrar.IsOpenForRegistration(ActionKey))
224 {
225 UBlueprintNodeSpawner* NodeSpawner = UBlueprintNodeSpawner::Create(GetClass());
226 check(NodeSpawner != nullptr);
227
228 ActionRegistrar.AddBlueprintAction(ActionKey, NodeSpawner);
229 }
230}
231
233{
234 static FNodeTextCache CachedCategory;
235
236 if (CachedCategory.IsOutOfDate(this))
237 {
238 // FText::Format() is slow, so we cache this to save on performance
239 CachedCategory.SetCachedText(FEditorCategoryUtils::BuildCategoryString(FCommonEditorCategory::Utilities, LOCTEXT("ActionMenuCategory", "VaRest")), this);
240 }
241 return CachedCategory;
242}
243
245{
246 const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
247 UClass* Class = Cast<UClass>(StaticLoadObject(UClass::StaticClass(), nullptr, TEXT("class'VaRest.VaRestJsonObject'")));
248
249 for (TArray<FVaRest_NamedType>::TIterator it(Outputs); it; ++it)
250 {
251 FName Type;
252
253 UObject* Subtype = nullptr;
254
255 switch ((*it).Type)
256 {
258 Type = K2Schema->PC_Boolean;
259 break;
260
262 Type = K2Schema->PC_Float;
263 break;
264
266 Type = K2Schema->PC_String;
267 break;
268
270 Type = K2Schema->PC_Object;
271 Subtype = Class;
272 break;
273 }
274
275 UEdGraphNode::FCreatePinParams OutputPinParams;
276 OutputPinParams.ContainerType = (*it).bIsArray ? EPinContainerType::Array : EPinContainerType::None;
277 UEdGraphPin* OutputPin = CreatePin(EGPD_Output, Type, TEXT(""), Subtype, (*it).Name, OutputPinParams);
278 }
279}
280
281FText UVaRest_BreakJson::GetNodeTitle(ENodeTitleType::Type TitleType) const
282{
283 return LOCTEXT("VaRest_Break_Json.NodeTitle", "Break Json");
284}
285
287{
288
289public:
290 FKCHandler_MakeJson(FKismetCompilerContext& InCompilerContext)
291 : FNodeHandlingFunctor(InCompilerContext)
292 {
293 }
294
295 virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override
296 {
297 UEdGraphPin* OutputPin = nullptr;
298
299 for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex)
300 {
301 UEdGraphPin* Pin = Node->Pins[PinIndex];
302 if (Pin && (EGPD_Output == Pin->Direction))
303 {
304 OutputPin = Pin;
305 break;
306 }
307 }
308
309 UClass* Class = Cast<UClass>(StaticLoadObject(UClass::StaticClass(), nullptr, TEXT("class'VaRest.VaRestJsonObject'")));
310
311 FBPTerminal** TargetTerm = Context.NetMap.Find(OutputPin);
312 if (TargetTerm == nullptr)
313 {
314 return;
315 }
316
317 {
318 UClass* SubsystemClass = Cast<UClass>(StaticLoadObject(UClass::StaticClass(), nullptr, TEXT("class'VaRest.VaRestSubsystem'")));
319
320 const FName FunctionName = TEXT("StaticConstructVaRestJsonObject");
321 UFunction* FunctionPtr = SubsystemClass->FindFunctionByName(FunctionName);
322 FBlueprintCompiledStatement& Statement = Context.AppendStatementForNode(Node);
323 Statement.Type = KCST_CallFunction;
324 Statement.FunctionToCall = FunctionPtr;
325 Statement.FunctionContext = nullptr;
326 Statement.bIsParentContext = false;
327 Statement.LHS = *TargetTerm;
328 FBPTerminal* NullTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
329 NullTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_Object;
330 NullTerm->ObjectLiteral = nullptr;
331 NullTerm->SourcePin = OutputPin;
332 Statement.RHS.Add(NullTerm);
333 }
334
335 for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex)
336 {
337 UEdGraphPin* Pin = Node->Pins[PinIndex];
338 if (Pin && (EGPD_Input == Pin->Direction))
339 {
340 FBPTerminal** Source = Context.NetMap.Find(FEdGraphUtilities::GetNetFromPin(Pin));
341
342 const FName& FieldName = Pin->PinName;
343 const FName& FieldType = Pin->PinType.PinCategory;
344
345 FBPTerminal* FieldNameTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
346 FieldNameTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_String;
347 FieldNameTerm->SourcePin = Pin;
348
349 FieldNameTerm->Name = FieldName.ToString();
350 FieldNameTerm->TextLiteral = FText::FromName(FieldName);
351
352 FBlueprintCompiledStatement& Statement = Context.AppendStatementForNode(Node);
353 FName FunctionName;
354
355 const bool bIsArray = Pin->PinType.ContainerType == EPinContainerType::Array;
356 if (FieldType == CompilerContext.GetSchema()->PC_Boolean)
357 {
358 FunctionName = bIsArray ? TEXT("SetBoolArrayField") : TEXT("SetBoolField");
359 }
360 else if (FieldType == CompilerContext.GetSchema()->PC_Float)
361 {
362 FunctionName = bIsArray ? TEXT("SetNumberArrayField") : TEXT("SetNumberField");
363 }
364 else if (FieldType == CompilerContext.GetSchema()->PC_String)
365 {
366 FunctionName = bIsArray ? TEXT("SetStringArrayField") : TEXT("SetStringField");
367 }
368 else if (FieldType == CompilerContext.GetSchema()->PC_Object)
369 {
370 FunctionName = bIsArray ? TEXT("SetObjectArrayField") : TEXT("SetObjectField");
371 }
372 else
373 {
374 continue;
375 }
376
377 UFunction* FunctionPtr = Class->FindFunctionByName(FunctionName);
378 Statement.Type = KCST_CallFunction;
379 Statement.FunctionToCall = FunctionPtr;
380 Statement.FunctionContext = *TargetTerm;
381 Statement.bIsParentContext = false;
382 Statement.LHS = nullptr;
383 Statement.RHS.Add(FieldNameTerm);
384 Statement.RHS.Add(*Source);
385 }
386 }
387 }
388
389 FBPTerminal* RegisterInputTerm(FKismetFunctionContext& Context, UEdGraphPin* InputPin)
390 {
391 // Find structure source net
392 UEdGraphPin* Net = FEdGraphUtilities::GetNetFromPin(InputPin);
393 FBPTerminal** TermPtr = Context.NetMap.Find(Net);
394
395 if (!TermPtr)
396 {
397 FBPTerminal* Term = Context.CreateLocalTerminalFromPinAutoChooseScope(Net, Context.NetNameMap->MakeValidName(Net));
398
399 Context.NetMap.Add(Net, Term);
400
401 return Term;
402 }
403
404 return *TermPtr;
405 }
406
407 void RegisterOutputTerm(FKismetFunctionContext& Context, UEdGraphPin* OutputPin)
408 {
409 FBPTerminal* Term = Context.CreateLocalTerminalFromPinAutoChooseScope(OutputPin, Context.NetNameMap->MakeValidName(OutputPin));
410 Context.NetMap.Add(OutputPin, Term);
411 }
412
413 virtual void RegisterNets(FKismetFunctionContext& Context, UEdGraphNode* InNode) override
414 {
415 UVaRest_MakeJson* Node = Cast<UVaRest_MakeJson>(InNode);
416 FNodeHandlingFunctor::RegisterNets(Context, Node);
417
418 check(NULL != Node);
419 {
420 for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex)
421 {
422 UEdGraphPin* Pin = Node->Pins[PinIndex];
423 if (EGPD_Output == Pin->Direction)
424 {
425 RegisterOutputTerm(Context, Pin);
426 }
427 else
428 {
429 RegisterInputTerm(Context, Pin);
430 }
431 }
432 }
433 }
434};
435
439UVaRest_MakeJson::UVaRest_MakeJson(const FObjectInitializer& ObjectInitializer)
440 : Super(ObjectInitializer)
441{
442}
443
444FNodeHandlingFunctor* UVaRest_MakeJson::CreateNodeHandler(class FKismetCompilerContext& CompilerContext) const
445{
446 return new FKCHandler_MakeJson(CompilerContext);
447}
448
450{
451 const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
452
453 UClass* Class = Cast<UClass>(StaticLoadObject(UClass::StaticClass(), nullptr, TEXT("class'VaRest.VaRestJsonObject'")));
454 UEdGraphPin* Pin = CreatePin(EGPD_Output, K2Schema->PC_Object, TEXT(""), Class, TEXT("Target"));
455
456 K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin);
457
459}
460
462{
463 return FLinearColor(255.0f, 255.0f, 0.0f);
464}
465
466void UVaRest_MakeJson::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
467{
468 const FName PropertyName = (PropertyChangedEvent.Property != nullptr) ? PropertyChangedEvent.Property->GetFName() : NAME_None;
469 if (PropertyName == GET_MEMBER_NAME_STRING_CHECKED(UVaRest_MakeJson, Inputs) ||
470 PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FVaRest_NamedType, Name) ||
471 PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FVaRest_NamedType, Type) ||
472 PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FVaRest_NamedType, bIsArray))
473 {
474 ReconstructNode();
475 GetGraph()->NotifyGraphChanged();
476 }
477
478 Super::PostEditChangeProperty(PropertyChangedEvent);
479}
480
481void UVaRest_MakeJson::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
482{
483 // actions get registered under specific object-keys; the idea is that
484 // actions might have to be updated (or deleted) if their object-key is
485 // mutated (or removed)... here we use the node's class (so if the node
486 // type disappears, then the action should go with it)
487 UClass* ActionKey = GetClass();
488
489 // to keep from needlessly instantiating a UBlueprintNodeSpawner, first
490 // check to make sure that the registrar is looking for actions of this type
491 // (could be regenerating actions for a specific asset, and therefore the
492 // registrar would only accept actions corresponding to that asset)
493 if (ActionRegistrar.IsOpenForRegistration(ActionKey))
494 {
495 UBlueprintNodeSpawner* NodeSpawner = UBlueprintNodeSpawner::Create(GetClass());
496 check(NodeSpawner != nullptr);
497
498 ActionRegistrar.AddBlueprintAction(ActionKey, NodeSpawner);
499 }
500}
501
503{
504 static FNodeTextCache CachedCategory;
505
506 if (CachedCategory.IsOutOfDate(this))
507 {
508 // FText::Format() is slow, so we cache this to save on performance
509 CachedCategory.SetCachedText(FEditorCategoryUtils::BuildCategoryString(FCommonEditorCategory::Utilities, LOCTEXT("ActionMenuCategory", "VaRest")), this);
510 }
511 return CachedCategory;
512}
513
515{
516 const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
517 UClass* Class = Cast<UClass>(StaticLoadObject(UClass::StaticClass(), nullptr, TEXT("class'VaRest.VaRestJsonObject'")));
518
519 for (TArray<FVaRest_NamedType>::TIterator it(Inputs); it; ++it)
520 {
521 FName Type;
522 UObject* Subtype = nullptr;
523
524 switch ((*it).Type)
525 {
527 Type = K2Schema->PC_Boolean;
528 break;
529
531 Type = K2Schema->PC_Float;
532 break;
533
535 Type = K2Schema->PC_String;
536 break;
537
539 Type = K2Schema->PC_Object;
540 Subtype = Class;
541 break;
542 }
543
544 UEdGraphNode::FCreatePinParams InputPinParams;
545 InputPinParams.ContainerType = (*it).bIsArray ? EPinContainerType::Array : EPinContainerType::None;
546 UEdGraphPin* InputPin = CreatePin(EGPD_Input, Type, TEXT(""), Subtype, (*it).Name, InputPinParams);
547
548 InputPin->SetSavePinIfOrphaned(false);
549 }
550}
551
552FText UVaRest_MakeJson::GetNodeTitle(ENodeTitleType::Type TitleType) const
553{
554 return LOCTEXT("VaRest_Make_Json.NodeTitle", "Make Json");
555}
556
557#undef LOCTEXT_NAMESPACE
void RegisterOutputTerm(FKismetFunctionContext &Context, UEdGraphPin *OutputPin, FBPTerminal *ContextTerm)
virtual void RegisterNets(FKismetFunctionContext &Context, UEdGraphNode *InNode) override
virtual void Compile(FKismetFunctionContext &Context, UEdGraphNode *Node) override
FBPTerminal * RegisterInputTerm(FKismetFunctionContext &Context, UVaRest_BreakJson *Node)
FKCHandler_BreakJson(FKismetCompilerContext &InCompilerContext)
FKCHandler_MakeJson(FKismetCompilerContext &InCompilerContext)
void RegisterOutputTerm(FKismetFunctionContext &Context, UEdGraphPin *OutputPin)
virtual void Compile(FKismetFunctionContext &Context, UEdGraphNode *Node) override
FBPTerminal * RegisterInputTerm(FKismetFunctionContext &Context, UEdGraphPin *InputPin)
virtual void RegisterNets(FKismetFunctionContext &Context, UEdGraphNode *InNode) override
UCLASS(BlueprintType, Blueprintable)
virtual FLinearColor GetNodeTitleColor() const override
virtual class FNodeHandlingFunctor * CreateNodeHandler(class FKismetCompilerContext &CompilerContext) const override
void GetMenuActions(FBlueprintActionDatabaseRegistrar &ActionRegistrar) const override
virtual void AllocateDefaultPins() override
virtual FText GetMenuCategory() const override
virtual void PostEditChangeProperty(struct FPropertyChangedEvent &PropertyChangedEvent) override
virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override
TArray< FVaRest_NamedType > Outputs
UPROPERTY(EditAnywhere, Category = PinOptions)
virtual void CreateProjectionPins(UEdGraphPin *Source)
UCLASS(BlueprintType, Blueprintable)
virtual void AllocateDefaultPins() override
virtual FLinearColor GetNodeTitleColor() const override
void GetMenuActions(FBlueprintActionDatabaseRegistrar &ActionRegistrar) const override
TArray< FVaRest_NamedType > Inputs
UPROPERTY(EditAnywhere, Category = PinOptions)
virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override
virtual void CreateProjectionPins(UEdGraphPin *Source)
virtual FText GetMenuCategory() const override
virtual void PostEditChangeProperty(struct FPropertyChangedEvent &PropertyChangedEvent) override
virtual class FNodeHandlingFunctor * CreateNodeHandler(class FKismetCompilerContext &CompilerContext) const override
USTRUCT(BlueprintType)