212 lines
7.4 KiB
C++
212 lines
7.4 KiB
C++
|
|
|
|
#include "ReadLuaValues.h"
|
|
|
|
#include "BlueprintActionDatabaseRegistrar.h"
|
|
#include "BlueprintNodeSpawner.h"
|
|
#include "EdGraphSchema_K2.h"
|
|
#include "K2Node_CallFunction.h"
|
|
#include "KismetCompiler.h"
|
|
#include "LuaCall.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "ReadLuaValues"
|
|
|
|
const FName UK2Node_ReadLuaValues::PrototypePinName(TEXT("Prototype"));
|
|
const FName UK2Node_ReadLuaValues::InputValuesPinName(TEXT("Input Values"));
|
|
const FName UK2Node_ReadLuaValues::RemainingPinName(TEXT("Remaining"));
|
|
const FName UK2Node_ReadLuaValues::ErrorPinName(TEXT("Error"));
|
|
|
|
FText UK2Node_ReadLuaValues::GetTooltipText() const
|
|
{
|
|
static FText Tooltip = FText::FromString(FString::Printf(TEXT(
|
|
"Read typed values from a Lua Values array.\n"
|
|
"\n"
|
|
"The value prototype must be a hardwired string listing the\n"
|
|
"types and names of the values to read, for example:\n"
|
|
"\n"
|
|
" string x, float y, int z\n"
|
|
"\n"
|
|
"If you add '...' at the end, any remaining values will\n"
|
|
"be available through the Remaining output pin.\n"
|
|
"\n"
|
|
"Supported types: %s\n"),
|
|
*UlxLuaCallLibrary::AllKnownReturnValueTypes()));
|
|
return Tooltip;
|
|
}
|
|
|
|
void UK2Node_ReadLuaValues::ReconstructNode()
|
|
{
|
|
// Save the value of the Prototype Pin before it gets reconstructed.
|
|
UEdGraphPin* PrototypePin = FindPin(PrototypePinName);
|
|
if (PrototypePin != nullptr)
|
|
{
|
|
ValuePrototype = PrototypePin->DefaultValue;
|
|
}
|
|
|
|
Super::ReconstructNode();
|
|
}
|
|
|
|
void UK2Node_ReadLuaValues::AllocateDefaultPins()
|
|
{
|
|
Pins.Reset();
|
|
Super::AllocateDefaultPins();
|
|
|
|
// Parse the value prototype string.
|
|
FlxParsedProto ParsedProto = FlxParsedProto::ParseReturnValuesOnly(ValuePrototype);
|
|
if (!ParsedProto.ErrorMessage.IsEmpty())
|
|
{
|
|
SetErrorMsg(FString::Printf(TEXT("Syntax error in value prototype: %s"), *ParsedProto.ErrorMessage));
|
|
}
|
|
|
|
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Execute);
|
|
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Then);
|
|
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, ErrorPinName);
|
|
|
|
UEdGraphPin *PrototypePin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_String, PrototypePinName);
|
|
PrototypePin->DefaultValue = ValuePrototype;
|
|
|
|
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Object, UlxLuaValues::StaticClass(), InputValuesPinName);
|
|
|
|
// Create output pins for each value.
|
|
for (const FlxParsedProto::Pin & Pin : ParsedProto.ReturnValues)
|
|
{
|
|
FName PrefixedName = AddPrefix(Pin.Name, 'R');
|
|
UFunction *Accessor = UlxLuaCallLibrary::GetReturnValueUnpacker(Pin.Type);
|
|
if (Accessor == nullptr) {
|
|
SetErrorMsg(FString::Printf(TEXT("Unknown value type: %s"), *Pin.Type));
|
|
continue;
|
|
}
|
|
CreatePin(EGPD_Output, PropertyToPinType(Accessor->FindPropertyByName(TEXT("Result"))), PrefixedName);
|
|
}
|
|
|
|
if (ParsedProto.ExtraReturnValues)
|
|
{
|
|
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Object, UlxLuaValues::StaticClass(), RemainingPinName);
|
|
}
|
|
}
|
|
|
|
|
|
FText UK2Node_ReadLuaValues::GetNodeTitle(ENodeTitleType::Type TitleType) const
|
|
{
|
|
return LOCTEXT("ReadLuaValues_Title", "Read Lua Values");
|
|
}
|
|
|
|
FText UK2Node_ReadLuaValues::GetPinDisplayName(const UEdGraphPin* Pin) const
|
|
{
|
|
// These pins don't need labels.
|
|
if ((Pin->PinName == UEdGraphSchema_K2::PN_Execute) ||
|
|
(Pin->PinName == UEdGraphSchema_K2::PN_Then) ||
|
|
(Pin->PinName == PrototypePinName))
|
|
{
|
|
return FText::GetEmpty();
|
|
}
|
|
|
|
// Return the pin name, removing R: prefix if present.
|
|
return FText::FromName(RemovePrefix(Pin->PinName));
|
|
}
|
|
|
|
void UK2Node_ReadLuaValues::PinDefaultValueChanged(UEdGraphPin* Pin)
|
|
{
|
|
if ((Pin->PinName == PrototypePinName) && (Pin->DefaultValue != ValuePrototype))
|
|
{
|
|
ReconstructNode();
|
|
}
|
|
}
|
|
|
|
|
|
void UK2Node_ReadLuaValues::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
|
|
{
|
|
Super::ExpandNode(CompilerContext, SourceGraph);
|
|
|
|
FlxParsedProto ParsedProto = FlxParsedProto::ParseReturnValuesOnly(ValuePrototype);
|
|
UEdGraphPin *InputInputValuesCopyPin = FindPinChecked(InputValuesPinName);
|
|
|
|
// Save the cursor so we can restore it on error.
|
|
// SaveCursor returns the UlxLuaValues*, which we use as the
|
|
// intermediate pin for all subsequent nodes.
|
|
UFunction *SaveCursorFunc = UlxLuaValues::StaticClass()->FindFunctionByName(TEXT("SaveCursor"));
|
|
UK2Node_CallFunction *SaveCursorNode = MakeCallFunctionNode(CompilerContext, SourceGraph, SaveCursorFunc);
|
|
CompilerContext.MovePinLinksToIntermediate(*InputInputValuesCopyPin, *SaveCursorNode->FindPinChecked(UEdGraphSchema_K2::PN_Self));
|
|
CompilerContext.MovePinLinksToIntermediate(*GetExecPin(), *SaveCursorNode->GetExecPin());
|
|
UEdGraphPin *InputValuesCopyPin = SaveCursorNode->GetReturnValuePin();
|
|
UEdGraphPin *ThenPin = SaveCursorNode->GetThenPin();
|
|
|
|
// The Read functions automatically restore the cursor on failure,
|
|
// so we just need a pin to wire WrongType outputs to.
|
|
UEdGraphPin *ErrorExecPin = FindPinChecked(ErrorPinName);
|
|
|
|
// Add Unpacking operations for all output pins.
|
|
for (const FlxParsedProto::Pin &PinInfo : ParsedProto.ReturnValues)
|
|
{
|
|
UEdGraphPin *Pin = FindPinChecked(AddPrefix(PinInfo.Name, 'R'));
|
|
UFunction *UnpackingFunc = UlxLuaCallLibrary::GetReturnValueUnpacker(PinInfo.Type);
|
|
if (UnpackingFunc == nullptr)
|
|
{
|
|
CompilerContext.MessageLog.Error(TEXT("All value pins must have known types."));
|
|
continue;
|
|
}
|
|
UK2Node_CallFunction *UnpackNode = MakeCallFunctionNode(CompilerContext, SourceGraph, UnpackingFunc);
|
|
InputValuesCopyPin->MakeLinkTo(UnpackNode->FindPinChecked(UEdGraphSchema_K2::PN_Self));
|
|
CompilerContext.CopyPinLinksToIntermediate(*ErrorExecPin, *UnpackNode->FindPinChecked(TEXT("WrongType")));
|
|
CompilerContext.MovePinLinksToIntermediate(*Pin, *UnpackNode->FindPinChecked(TEXT("Result")));
|
|
ThenPin = ChainExecPin(ThenPin, UnpackNode, TEXT("Success"));
|
|
}
|
|
|
|
// If there is a Remaining output pin, pass through the LuaValues object.
|
|
// The cursor is already past the consumed values.
|
|
if (ParsedProto.ExtraReturnValues)
|
|
{
|
|
UEdGraphPin *RemainingPin = FindPinChecked(RemainingPinName);
|
|
CompilerContext.MovePinLinksToIntermediate(*RemainingPin, *InputValuesCopyPin);
|
|
}
|
|
|
|
// Link up the output exec pin.
|
|
CompilerContext.MovePinLinksToIntermediate(*GetThenPin(), *ThenPin);
|
|
|
|
BreakAllNodeLinks();
|
|
}
|
|
|
|
|
|
UK2Node::ERedirectType UK2Node_ReadLuaValues::DoPinsMatchForReconstruction(const UEdGraphPin* NewPin, int32 NewPinIndex, const UEdGraphPin* OldPin, int32 OldPinIndex) const
|
|
{
|
|
if (IsTemplate() || (GetGraph() == nullptr)) return ERedirectType_None;
|
|
if ((NewPin->PinName == OldPin->PinName) &&
|
|
(NewPin->Direction == OldPin->Direction) &&
|
|
(NewPin->PinType == OldPin->PinType))
|
|
{
|
|
return ERedirectType_Name;
|
|
}
|
|
return ERedirectType_None;
|
|
}
|
|
|
|
bool UK2Node_ReadLuaValues::IsConnectionDisallowed(const UEdGraphPin* MyPin, const UEdGraphPin* OtherPin, FString& OutReason) const
|
|
{
|
|
// The prototype pin cannot be connected.
|
|
if (MyPin->PinName == PrototypePinName)
|
|
{
|
|
OutReason = LOCTEXT("Error_PrototypeMustBeHardwired", "Value prototype must be a hardwired constant.").ToString();
|
|
return true;
|
|
}
|
|
|
|
return Super::IsConnectionDisallowed(MyPin, OtherPin, OutReason);
|
|
}
|
|
|
|
void UK2Node_ReadLuaValues::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
|
|
{
|
|
UClass* ActionKey = GetClass();
|
|
if (ActionRegistrar.IsOpenForRegistration(ActionKey))
|
|
{
|
|
UBlueprintNodeSpawner* NodeSpawner = UBlueprintNodeSpawner::Create(GetClass());
|
|
check(NodeSpawner != nullptr);
|
|
ActionRegistrar.AddBlueprintAction(ActionKey, NodeSpawner);
|
|
}
|
|
}
|
|
|
|
FText UK2Node_ReadLuaValues::GetMenuCategory() const
|
|
{
|
|
return FText::FromString(FString(TEXT("Luprex|Lua")));
|
|
}
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|