Lots of work on several unrelated things.

This commit is contained in:
2025-03-28 23:31:44 -04:00
parent 3741470b20
commit b26d56048f
30 changed files with 444 additions and 612 deletions

View File

@@ -2,6 +2,7 @@
#include "LuaCallNode.h"
#include "StringDecoder.h"
#include "BlueprintActionDatabaseRegistrar.h"
#include "BlueprintNodeSpawner.h"
@@ -40,59 +41,41 @@
#define LOCTEXT_NAMESPACE "LuaCall"
#define LuaCallLibraryFunction(name) (UlxLuaCallLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UlxLuaCallLibrary, name)))
// All argument pins will have internal Names that start with "A:"
static bool IsArgumentPin(const UEdGraphPin *Pin) {
const FName UK2Node_LuaCall::FunctionPinName(TEXT("Lua Function Prototype"));
const FName UK2Node_LuaCall::InvokeOrProbePinName(TEXT("Invoke or Probe"));
const FName UK2Node_LuaCall::PlacePinName(TEXT("Place Tangible"));
const FName UK2Node_LuaCall::ExtraResultsPinName(TEXT("Extra Results"));
bool UK2Node_LuaCall::IsPrefix(const UEdGraphPin *Pin, char Prefix)
{
TCHAR pname[FName::StringBufferSize];
Pin->PinName.ToString(pname);
return pname[0] == 'A' && pname[1] == ':';
return pname[0] == Prefix && pname[1] == ':';
}
static FName ArgumentNameAddPrefix(const FString &name) {
FString Prefixed = FString("A:") + name;
FName UK2Node_LuaCall::AddPrefix(const FString &Name, char Prefix)
{
TCHAR PrefixChars[3];
PrefixChars[0] = Prefix;
PrefixChars[1] = ':';
PrefixChars[2] = 0;
FString Prefixed = PrefixChars + Name;
return FName(*Prefixed);
}
static FString ArgumentNameRemovePrefix(const FName &name) {
return name.ToString().Mid(2, FName::StringBufferSize);
}
// All return value pins will have internal Names that start with "R:"
static bool IsReturnValuePin(const UEdGraphPin *Pin) {
FString UK2Node_LuaCall::RemovePrefix(FName Name, char Prefix)
{
TCHAR pname[FName::StringBufferSize];
Pin->PinName.ToString(pname);
return pname[0] == 'R' && pname[1] == ':';
Name.ToString(pname);
check(pname[0] == Prefix);
check(pname[1] == ':');
return FString(pname + 2);
}
static FName ReturnValueNameAddPrefix(const FString &name) {
FString Prefixed = FString("R:") + name;
return FName(*Prefixed);
}
static FString ReturnValueNameRemovePrefix(const FName &name) {
return name.ToString().Mid(2, FName::StringBufferSize);
}
// Builtin pins will have names with no prefixes.
static const FName FunctionPinName(TEXT("Lua Function Prototype"));
static bool IsFunctionPin(const UEdGraphPin *Pin) {
return (Pin->PinName == FunctionPinName);
}
static const FName InvokeOrProbePinName(TEXT("Invoke or Probe"));
static bool IsInvokeOrProbePin(const UEdGraphPin *Pin) {
return (Pin->PinName == InvokeOrProbePinName);
}
static const FName PlacePinName(TEXT("Place Tangible"));
static bool IsPlacePin(const UEdGraphPin *Pin) {
return (Pin->PinName == PlacePinName);
}
#define LuaCallLibraryFunction(name) (UlxLuaCallLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UlxLuaCallLibrary, name)))
static FEdGraphPinType GetPinType(const FProperty *Property)
{
FEdGraphPinType PinType;
@@ -107,7 +90,6 @@ static FEdGraphPinType GetPinType(const FProperty *Property)
}
UK2Node_LuaCall::UK2Node_LuaCall(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
@@ -154,29 +136,6 @@ void UK2Node_LuaCall::CreateCorrectPins()
LuaFunctionPrototype = TEXT("class.func(int arg1, int arg2) : int ret1, int ret2");
}
if (FindPin(UEdGraphSchema_K2::PN_Execute) == nullptr) {
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Execute);
}
if (FindPin(UEdGraphSchema_K2::PN_Then) == nullptr) {
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Then);
}
if (FindPin(FunctionPinName, EGPD_Input) == nullptr) {
UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_String, FunctionPinName);
P->DefaultValue = LuaFunctionPrototype;
}
if (FindPin(InvokeOrProbePinName, EGPD_Input) == nullptr) {
UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Byte, StaticEnum<ElxInvokeOrProbe>(), InvokeOrProbePinName);
P->DefaultValue = TEXT("Probe");
P->AutogeneratedDefaultValue = P->DefaultValue;
}
if (FindPin(PlacePinName, EGPD_Input) == nullptr) {
UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Object, AActor::StaticClass(), PlacePinName);
}
// Parse the lua function prototype.
FlxParsedProto ParsedProto(LuaFunctionPrototype);
if (!ParsedProto.ErrorMessage.IsEmpty())
@@ -186,26 +145,60 @@ void UK2Node_LuaCall::CreateCorrectPins()
ErrorMsg = FString::Printf(TEXT("Syntax error in lua function prototype: %s"), *ParsedProto.ErrorMessage);
}
// Transfer all Existing argument and return value pins to the Old Pins Maps.
TMap<FName, UEdGraphPin *> OldArgumentPins;
TMap<FName, UEdGraphPin *> OldReturnValuePins;
// Transfer all pins to the old pins map and clear the pin list.
TMap<FName, UEdGraphPin *> OldPins;
for (auto It = Pins.CreateIterator(); It; ++It)
{
UEdGraphPin* CheckPin = *It;
if (IsArgumentPin(CheckPin)) {
OldArgumentPins.Add(CheckPin->PinName, CheckPin);
It.RemoveCurrent();
}
if (IsReturnValuePin(CheckPin)) {
OldReturnValuePins.Add(CheckPin->PinName, CheckPin);
It.RemoveCurrent();
OldPins.Add(CheckPin->PinName, CheckPin);
}
Pins.Empty();
// KeepPin is a function that moves a pin from the old pins
// map back onto the pins list.
auto KeepPin = [&](FName Name, FEdGraphPinType Type = FEdGraphPinType()) -> bool
{
UEdGraphPin **OldPin = OldPins.Find(Name);
if ((OldPin != nullptr) && (((*OldPin)->PinType == Type) || (Type.PinCategory == FName())))
{
Pins.Emplace(*OldPin);
OldPins.Remove(Name);
}
return OldPin != nullptr;
};
if (!KeepPin(UEdGraphSchema_K2::PN_Execute))
{
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Execute);
}
if (!KeepPin(UEdGraphSchema_K2::PN_Then))
{
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Then);
}
if (!KeepPin(FunctionPinName))
{
UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_String, FunctionPinName);
P->DefaultValue = LuaFunctionPrototype;
}
if (!KeepPin(InvokeOrProbePinName))
{
UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Byte, StaticEnum<ElxInvokeOrProbe>(), InvokeOrProbePinName);
P->DefaultValue = TEXT("Probe");
P->AutogeneratedDefaultValue = P->DefaultValue;
}
if (!KeepPin(PlacePinName))
{
UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Object, AActor::StaticClass(), PlacePinName);
}
// Create Argument pins in the correct order, reusing old pins where possible.
for (const FlxParsedProto::Pin & Pin : ParsedProto.Arguments)
{
FName PrefixedName = ArgumentNameAddPrefix(Pin.Name);
FName PrefixedName = AddPrefix(Pin.Name, 'A');
UFunction *Accessor = UlxLuaCallLibrary::GetArgumentPacker(Pin.Type);
if (Accessor == nullptr) {
bHasCompilerMessage = true;
@@ -214,11 +207,8 @@ void UK2Node_LuaCall::CreateCorrectPins()
continue;
}
FEdGraphPinType PinType = GetPinType(Accessor->FindPropertyByName(TEXT("Value")));
UEdGraphPin **OldPin = OldArgumentPins.Find(PrefixedName);
if ((OldPin != nullptr) && ((*OldPin)->PinType == PinType)) {
Pins.Emplace(*OldPin);
OldArgumentPins.Remove(PrefixedName);
} else {
if (!KeepPin(PrefixedName, PinType))
{
CreatePin(EGPD_Input, PinType, PrefixedName);
}
}
@@ -226,7 +216,7 @@ void UK2Node_LuaCall::CreateCorrectPins()
// Create ReturnValue pins in the correct order, reusing old pins where possible.
for (const FlxParsedProto::Pin & Pin : ParsedProto.ReturnValues)
{
FName PrefixedName = ReturnValueNameAddPrefix(Pin.Name);
FName PrefixedName = AddPrefix(Pin.Name, 'R');
UFunction *Accessor = UlxLuaCallLibrary::GetReturnValueUnpacker(Pin.Type);
if (Accessor == nullptr) {
bHasCompilerMessage = true;
@@ -235,28 +225,27 @@ void UK2Node_LuaCall::CreateCorrectPins()
continue;
}
FEdGraphPinType PinType = GetPinType(Accessor->GetReturnProperty());
UEdGraphPin **OldPin = OldReturnValuePins.Find(PrefixedName);
if ((OldPin != nullptr) && ((*OldPin)->PinType == PinType)) {
Pins.Emplace(*OldPin);
OldReturnValuePins.Remove(PrefixedName);
} else {
if (!KeepPin(PrefixedName, PinType))
{
CreatePin(EGPD_Output, PinType, PrefixedName);
}
}
if (ParsedProto.ExtraReturnValues)
{
if (!KeepPin(ExtraResultsPinName))
{
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Object, UlxLuaValues::StaticClass(), ExtraResultsPinName);
}
}
// Delete any unused pins.
for (auto &iter : OldArgumentPins)
for (auto &iter : OldPins)
{
iter.Value->Modify();
iter.Value->MarkAsGarbage();
}
for (auto &iter : OldReturnValuePins)
{
iter.Value->Modify();
iter.Value->MarkAsGarbage();
}
OldArgumentPins.Empty();
OldReturnValuePins.Empty();
OldPins.Empty();
}
@@ -274,7 +263,7 @@ FText UK2Node_LuaCall::GetPinDisplayName(const UEdGraphPin* Pin) const
}
// Many pins can go unlabeled if they have default values.
if (IsFunctionPin(Pin) || IsInvokeOrProbePin(Pin))
if ((Pin->PinName == FunctionPinName) || (Pin->PinName == InvokeOrProbePinName))
{
if (Pin->LinkedTo.Num() == 0)
{
@@ -283,13 +272,15 @@ FText UK2Node_LuaCall::GetPinDisplayName(const UEdGraphPin* Pin) const
}
// For argument pins, we must strip off the Argument Pin Prefix.
if (IsArgumentPin(Pin)) {
return FText::FromString(ArgumentNameRemovePrefix(Pin->PinName));
if (IsPrefix(Pin, 'A'))
{
return FText::FromString(RemovePrefix(Pin->PinName, 'A'));
}
// For return value pins, we must strip off the Return Value Pin Prefix.
if (IsReturnValuePin(Pin)) {
return FText::FromString(ReturnValueNameRemovePrefix(Pin->PinName));
if (IsPrefix(Pin, 'R'))
{
return FText::FromString(RemovePrefix(Pin->PinName, 'R'));
}
// Otherwise, just return the Pin Name the normal way.
@@ -309,7 +300,7 @@ void UK2Node_LuaCall::PinConnectionListChanged(UEdGraphPin* Pin)
void UK2Node_LuaCall::PinDefaultValueChanged(UEdGraphPin* Pin)
{
if(IsFunctionPin(Pin))
if(Pin->PinName == FunctionPinName)
{
LuaFunctionPrototype = Pin->DefaultValue;
CreateCorrectPins();
@@ -356,7 +347,7 @@ void UK2Node_LuaCall::ExpandNode(class FKismetCompilerContext& CompilerContext,
// Add Packing operations for all argument pins.
for (const FlxParsedProto::Pin &PinInfo : ParsedProto.Arguments)
{
UEdGraphPin *Pin = FindPinChecked(ArgumentNameAddPrefix(PinInfo.Name));
UEdGraphPin *Pin = FindPinChecked(AddPrefix(PinInfo.Name, 'A'));
UFunction *PackingFunc = UlxLuaCallLibrary::GetArgumentPacker(PinInfo.Type);
if (PackingFunc == nullptr)
{
@@ -378,10 +369,10 @@ void UK2Node_LuaCall::ExpandNode(class FKismetCompilerContext& CompilerContext,
PrevNode->GetThenPin()->MakeLinkTo(ActionNode->GetExecPin());
PrevNode = ActionNode;
// Add Unpacking operations for all argument pins.
// Add Unpacking operations for all return value pins.
for (const FlxParsedProto::Pin &PinInfo : ParsedProto.ReturnValues)
{
UEdGraphPin *Pin = FindPinChecked(ReturnValueNameAddPrefix(PinInfo.Name));
UEdGraphPin *Pin = FindPinChecked(AddPrefix(PinInfo.Name, 'R'));
UFunction *UnpackingFunc = UlxLuaCallLibrary::GetReturnValueUnpacker(PinInfo.Type);
if (UnpackingFunc == nullptr)
{
@@ -395,16 +386,26 @@ void UK2Node_LuaCall::ExpandNode(class FKismetCompilerContext& CompilerContext,
PrevNode = UnpackNode;
}
// Make sure we didn't have return values for an invoke.
if (IsInvoke && (ParsedProto.ReturnValues.Num() > 0))
// If there is an extra results pin, hook it up.
if (ParsedProto.ExtraReturnValues)
{
CompilerContext.MessageLog.Error(TEXT("Lua Call in Invoke mode does not support return values"));
UEdGraphPin *Pin = FindPinChecked(ExtraResultsPinName);
UK2Node_CallFunction *UnpackNode = MakeCallFunctionNode(LuaCallLibraryFunction(LuaCallGetRest));
CompilerContext.MovePinLinksToIntermediate(*Pin, *UnpackNode->FindPinChecked(UEdGraphSchema_K2::PN_ReturnValue));
PrevNode->GetThenPin()->MakeLinkTo(UnpackNode->GetExecPin());
PrevNode = UnpackNode;
}
// Link up the Exec pins.
CompilerContext.MovePinLinksToIntermediate(*GetExecPin(), *BeginNode->GetExecPin());
CompilerContext.MovePinLinksToIntermediate(*GetThenPin(), *PrevNode->GetThenPin());
// Make sure we didn't have return values for an invoke.
if (IsInvoke && ((ParsedProto.ReturnValues.Num() > 0) || (ParsedProto.ExtraReturnValues)))
{
CompilerContext.MessageLog.Error(TEXT("Lua Call in Invoke mode does not support return values"));
}
BreakAllNodeLinks();
}
@@ -457,14 +458,14 @@ UK2Node::ERedirectType UK2Node_LuaCall::DoPinsMatchForReconstruction(const UEdGr
bool UK2Node_LuaCall::IsConnectionDisallowed(const UEdGraphPin* MyPin, const UEdGraphPin* OtherPin, FString& OutReason) const
{
// The function pin cannot be connected.
if (IsFunctionPin(MyPin))
if (MyPin->PinName == FunctionPinName)
{
OutReason = LOCTEXT("Error_FunctionPrototypeMustBeHardwired", "Lua function prototype must be a hardwired constant.").ToString();
return true;
}
// The invoke-or-probe pin cannot be connected.
if (IsInvokeOrProbePin(MyPin))
if (MyPin->PinName == InvokeOrProbePinName)
{
OutReason = LOCTEXT("Error_InvokeOrProbeMustBeHardwired", "Invoke vs Probe must be a hardwired constant.").ToString();
return true;