More work on look-at, split LuaCall into LuaInvoke/LuaProbe

This commit is contained in:
2025-04-08 16:31:16 -04:00
parent c060b87556
commit 8a9d5550d9
10 changed files with 126 additions and 111 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -93,87 +93,104 @@ FString UlxAssetLookup::WidgetLoadPath(const FName &AssetName) const
return *Result; return *Result;
} }
UStaticMesh *UlxAssetLookup::GetStaticMeshByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound, bool ErrorIfInvalid) void UlxAssetLookup::LogMaybeError(bool Error, const TCHAR *Message, const TCHAR *Path)
{
if (Error)
{
UE_LOG(LogLuprexIntegration, Error, TEXT("%s: %s"), Message, Path);
}
else
{
UE_LOG(LogLuprexIntegration, Display, TEXT("%s: %s"), Message, Path);
}
}
UStaticMesh *UlxAssetLookup::GetStaticMeshByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound)
{ {
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context); ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context);
FString Path = mode->GetAssetLookup()->StaticMeshLoadPath(FName(FString("SM_") + Name)); FString Path = mode->GetAssetLookup()->StaticMeshLoadPath(FName(FString("SM_") + Name));
if (Path.IsEmpty()) if (Path.IsEmpty())
{ {
if (ErrorIfNotFound) UE_LOG(LogLuprexIntegration, Error, TEXT("Static mesh not on search path: %s"), *Name); LogMaybeError(ErrorIfNotFound, TEXT("Static mesh not on search path"), *Name);
return nullptr; return nullptr;
} }
UStaticMesh *Result = LoadObject<UStaticMesh>(nullptr, *Path); UStaticMesh *Result = LoadObject<UStaticMesh>(nullptr, *Path);
if (Result == nullptr) { if (Result == nullptr)
if (ErrorIfInvalid) UE_LOG(LogLuprexIntegration, Error, TEXT("Cannot load static mesh: %s"), *Path); {
LogMaybeError(ErrorIfNotFound, TEXT("Cannot load static mesh"), *Path);
return nullptr; return nullptr;
} }
return Result; return Result;
} }
TSubclassOf<AActor> UlxAssetLookup::GetTangibleClassByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound, bool ErrorIfInvalid) { TSubclassOf<AActor> UlxAssetLookup::GetTangibleClassByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound) {
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context); ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context);
FString Path = mode->GetAssetLookup()->TangibleLoadPath(FName(FString("TAN_") + Name)); FString Path = mode->GetAssetLookup()->TangibleLoadPath(FName(FString("TAN_") + Name));
if (Path.IsEmpty()) if (Path.IsEmpty())
{ {
if (ErrorIfNotFound) UE_LOG(LogLuprexIntegration, Error, TEXT("Tangible not on search path: %s"), *Name); LogMaybeError(ErrorIfNotFound, TEXT("Tangible not on search path"), *Name);
return nullptr; return nullptr;
} }
UClass *Result = LoadObject<UClass>(nullptr, *Path); UClass *Result = LoadObject<UClass>(nullptr, *Path);
if (Result == nullptr) { if (Result == nullptr)
if (ErrorIfInvalid) UE_LOG(LogLuprexIntegration, Error, TEXT("Cannot load tangible class: %s"), *Path); {
LogMaybeError(ErrorIfNotFound, TEXT("Cannot load tangible class"), *Path);
return nullptr; return nullptr;
} }
if (!Result->IsChildOf(AActor::StaticClass())) { if (!Result->IsChildOf(AActor::StaticClass()))
if (ErrorIfInvalid) UE_LOG(LogLuprexIntegration, Error, TEXT("Tangible class is not an actor: %s"), *Path); {
LogMaybeError(ErrorIfNotFound, TEXT("Tangible class is not an actor"), *Path);
return nullptr; return nullptr;
} }
UFunction *aqchanged = Result->FindFunctionByName(FName(TEXT("Animation Queue Changed"))); UFunction *aqchanged = Result->FindFunctionByName(FName(TEXT("Animation Queue Changed")));
if ((aqchanged == nullptr)||(aqchanged->ParmsSize != 0)) if ((aqchanged == nullptr)||(aqchanged->ParmsSize != 0))
{ {
if (ErrorIfInvalid) UE_LOG(LogLuprexIntegration, Error, TEXT("Tangible does not have 'Animation Queue Changed' function: %s"), *Path); LogMaybeError(ErrorIfNotFound, TEXT("Tangible does not have 'Animation Queue Changed' function"), *Path);
return nullptr; return nullptr;
} }
return Result; return Result;
} }
TSubclassOf<UUserWidget> UlxAssetLookup::GetWidgetByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound, bool ErrorIfInvalid) { TSubclassOf<UUserWidget> UlxAssetLookup::GetWidgetByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound) {
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context); ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context);
FString Path = mode->GetAssetLookup()->WidgetLoadPath(FName(FString("WB_") + Name)); FString Path = mode->GetAssetLookup()->WidgetLoadPath(FName(FString("WB_") + Name));
if (Path.IsEmpty()) if (Path.IsEmpty())
{ {
if (ErrorIfNotFound) UE_LOG(LogLuprexIntegration, Error, TEXT("Widget not on search path: %s"), *Name); LogMaybeError(ErrorIfNotFound, TEXT("Widget not on search path"), *Name);
return nullptr; return nullptr;
} }
UClass *Result = LoadObject<UClass>(nullptr, *Path); UClass *Result = LoadObject<UClass>(nullptr, *Path);
if (Result == nullptr) { if (Result == nullptr)
if (ErrorIfInvalid) UE_LOG(LogLuprexIntegration, Error, TEXT("Cannot load widget blueprint: %s"), *Path); {
LogMaybeError(ErrorIfNotFound, TEXT("Cannot load widget blueprint"), *Path);
return nullptr; return nullptr;
} }
if (!Result->IsChildOf(UUserWidget::StaticClass())) if (!Result->IsChildOf(UUserWidget::StaticClass()))
{ {
if (ErrorIfInvalid) UE_LOG(LogLuprexIntegration, Error, TEXT("Blueprint is not a Widget Blueprint: %s"), *Path); LogMaybeError(ErrorIfNotFound, TEXT("Blueprint is not a Widget Blueprint"), *Path);
return nullptr; return nullptr;
} }
return Result; return Result;
} }
TSubclassOf<UlxLookAtWidget> UlxAssetLookup::GetLookAtWidgetByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound, bool ErrorIfInvalid) { TSubclassOf<UlxLookAtWidget> UlxAssetLookup::GetLookAtWidgetByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound) {
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context); ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context);
FString Path = mode->GetAssetLookup()->WidgetLoadPath(FName(FString("WB_") + Name)); FString Path = mode->GetAssetLookup()->WidgetLoadPath(FName(FString("WB_") + Name));
if (Path.IsEmpty()) if (Path.IsEmpty())
{ {
if (ErrorIfNotFound) UE_LOG(LogLuprexIntegration, Error, TEXT("Widget not on search path: %s"), *Name); LogMaybeError(ErrorIfNotFound, TEXT("Widget not on search path"), *Name);
return nullptr; return nullptr;
} }
UClass *Result = LoadObject<UClass>(nullptr, *Path); UClass *Result = LoadObject<UClass>(nullptr, *Path);
if (Result == nullptr) { if (Result == nullptr)
if (ErrorIfInvalid) UE_LOG(LogLuprexIntegration, Error, TEXT("Cannot load widget blueprint: %s"), *Path); {
LogMaybeError(ErrorIfNotFound, TEXT("Cannot load widget blueprint"), *Path);
return nullptr; return nullptr;
} }
if (!Result->IsChildOf(UlxLookAtWidget::StaticClass())) if (!Result->IsChildOf(UlxLookAtWidget::StaticClass()))
{ {
if (ErrorIfInvalid) UE_LOG(LogLuprexIntegration, Error, TEXT("Blueprint is not a Luprex Look-At Widget: %s"), *Path); LogMaybeError(ErrorIfNotFound, TEXT("Blueprint is not a Luprex Look-At Widget"), *Path);
return nullptr; return nullptr;
} }
return Result; return Result;

View File

@@ -34,6 +34,8 @@ private:
void ScanStaticMeshes(); void ScanStaticMeshes();
void ScanWidgets(); void ScanWidgets();
static void LogMaybeError(bool ErrorIfNotFound, const TCHAR *Format, const TCHAR *Data);
public: public:
void RebuildIndex(); void RebuildIndex();
@@ -48,17 +50,17 @@ public:
// Get a static mesh by name // Get a static mesh by name
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous") UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous")
static UStaticMesh *GetStaticMeshByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound = false, bool ErrorIfInvalid = true); static UStaticMesh *GetStaticMeshByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
// Get a tangible class by name // Get a tangible class by name
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous") UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous")
static TSubclassOf<AActor> GetTangibleClassByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound = false, bool ErrorIfInvalid = true); static TSubclassOf<AActor> GetTangibleClassByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
// Get a widget blueprint by name // Get a widget blueprint by name
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous") UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous")
static TSubclassOf<UUserWidget> GetWidgetByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound = false, bool ErrorIfInvalid = true); static TSubclassOf<UUserWidget> GetWidgetByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
// Get a look-at widget blueprint by name // Get a look-at widget blueprint by name
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous") UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous")
static TSubclassOf<UlxLookAtWidget> GetLookAtWidgetByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound = false, bool ErrorIfInvalid = true); static TSubclassOf<UlxLookAtWidget> GetLookAtWidgetByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
}; };

View File

@@ -519,8 +519,8 @@ ElxSuccessOrError UlxLuaValues::CheckType(ElxLuaValueType Type, ElxLuaValueType
ElxLuaValueType UlxLuaValues::NextType() const ElxLuaValueType UlxLuaValues::NextType() const
{ {
if (Cursor < 0) return ElxLuaValueType::None; if (Cursor < 0) return ElxLuaValueType::End;
if (Cursor >= Types.Num()) return ElxLuaValueType::None; if (Cursor >= Types.Num()) return ElxLuaValueType::End;
return Types[Cursor]; return Types[Cursor];
} }

View File

@@ -17,7 +17,7 @@ class UlxLuaValues;
UENUM(BlueprintType) UENUM(BlueprintType)
enum class ElxLuaValueType : uint8 { enum class ElxLuaValueType : uint8 {
None, End,
String, String,
Name, Name,
Float, Float,
@@ -272,7 +272,7 @@ public:
bool IsNextType(ElxLuaValueType Type) const { return NextType() == Type; } bool IsNextType(ElxLuaValueType Type) const { return NextType() == Type; }
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "ReturnValue"), Category = "Luprex|Lua Value Array") UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "ReturnValue"), Category = "Luprex|Lua Value Array")
ElxLuaValueType SwitchNextType() const { return NextType(); } ElxLuaValueType SwitchNextType() { return NextType(); }
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Status"), Category = "Luprex|Lua Value Array") UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Status"), Category = "Luprex|Lua Value Array")
void ReadString(ElxSuccessOrError &Status, FString &Result); void ReadString(ElxSuccessOrError &Status, FString &Result);

View File

@@ -45,20 +45,19 @@
// All argument pins will have internal Names that start with "A:" // All argument pins will have internal Names that start with "A:"
const FName UK2Node_LuaCall::FunctionPinName(TEXT("Lua Function Prototype")); const FName UK2Node_LuaInvoke::FunctionPinName(TEXT("Lua Function Prototype"));
const FName UK2Node_LuaCall::InvokeOrProbePinName(TEXT("Invoke or Probe")); const FName UK2Node_LuaInvoke::PlacePinName(TEXT("Place Tangible"));
const FName UK2Node_LuaCall::PlacePinName(TEXT("Place Tangible")); const FName UK2Node_LuaInvoke::ExtraResultsPinName(TEXT("Extra Results"));
const FName UK2Node_LuaCall::ExtraResultsPinName(TEXT("Extra Results")); const FName UK2Node_LuaInvoke::ErrorPinName(TEXT("Lua Error"));
const FName UK2Node_LuaCall::ErrorPinName(TEXT("Lua Error"));
bool UK2Node_LuaCall::IsPrefix(const UEdGraphPin *Pin, char Prefix) bool UK2Node_LuaInvoke::IsPrefix(const UEdGraphPin *Pin, char Prefix)
{ {
TCHAR pname[FName::StringBufferSize]; TCHAR pname[FName::StringBufferSize];
Pin->PinName.ToString(pname); Pin->PinName.ToString(pname);
return pname[0] == Prefix && pname[1] == ':'; return pname[0] == Prefix && pname[1] == ':';
} }
FName UK2Node_LuaCall::AddPrefix(const FString &Name, char Prefix) FName UK2Node_LuaInvoke::AddPrefix(const FString &Name, char Prefix)
{ {
TCHAR PrefixChars[3]; TCHAR PrefixChars[3];
PrefixChars[0] = Prefix; PrefixChars[0] = Prefix;
@@ -68,7 +67,7 @@ FName UK2Node_LuaCall::AddPrefix(const FString &Name, char Prefix)
return FName(*Prefixed); return FName(*Prefixed);
} }
FString UK2Node_LuaCall::RemovePrefix(FName Name, char Prefix) FString UK2Node_LuaInvoke::RemovePrefix(FName Name, char Prefix)
{ {
TCHAR pname[FName::StringBufferSize]; TCHAR pname[FName::StringBufferSize];
Name.ToString(pname); Name.ToString(pname);
@@ -91,12 +90,23 @@ static FEdGraphPinType GetPinType(const FProperty *Property)
} }
UK2Node_LuaCall::UK2Node_LuaCall(const FObjectInitializer& ObjectInitializer) UK2Node_LuaInvoke::UK2Node_LuaInvoke(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer), NodeTooltip(MakeTooltip())
{
}
UK2Node_LuaProbe::UK2Node_LuaProbe(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer) : Super(ObjectInitializer)
{ {
}
FText UK2Node_LuaInvoke::MakeTooltip() const
{
// TODO: replace this string manipulation with text manipulation.
FString ArgTypes = UlxLuaCallLibrary::AllKnownArgumentTypes(); FString ArgTypes = UlxLuaCallLibrary::AllKnownArgumentTypes();
FString RetTypes = UlxLuaCallLibrary::AllKnownReturnValueTypes(); FString RetTypes = UlxLuaCallLibrary::AllKnownReturnValueTypes();
NodeTooltip = FText::FromString(FString::Printf(TEXT( return FText::FromString(FString::Printf(TEXT(
"Call a Lua function.\n" "Call a Lua function.\n"
"\n" "\n"
"The lua function prototype must be a hardwired string which must look like\n" "The lua function prototype must be a hardwired string which must look like\n"
@@ -124,16 +134,14 @@ UK2Node_LuaCall::UK2Node_LuaCall(const FObjectInitializer& ObjectInitializer)
"\n"), *ArgTypes, *RetTypes)); "\n"), *ArgTypes, *RetTypes));
} }
void UK2Node_LuaCall::AllocateDefaultPins() void UK2Node_LuaInvoke::AllocateDefaultPins()
{ {
Super::AllocateDefaultPins(); Super::AllocateDefaultPins();
CreateCorrectPins(); CreateCorrectPins();
} }
void UK2Node_LuaCall::CreateCorrectPins() void UK2Node_LuaInvoke::CreateCorrectPins()
{ {
UEnum *IPEnum = StaticEnum<ElxInvokeOrProbe>();
if (LuaFunctionPrototype.IsEmpty()) if (LuaFunctionPrototype.IsEmpty())
{ {
LuaFunctionPrototype = TEXT("class.func(int arg1, int arg2) : int ret1, int ret2"); LuaFunctionPrototype = TEXT("class.func(int arg1, int arg2) : int ret1, int ret2");
@@ -180,7 +188,7 @@ void UK2Node_LuaCall::CreateCorrectPins()
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Then); CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Then);
} }
if (InvokeOrProbe == TEXT("Probe")) if (!IsInvoke())
{ {
if (!KeepPin(ErrorPinName)) if (!KeepPin(ErrorPinName))
{ {
@@ -193,11 +201,6 @@ void UK2Node_LuaCall::CreateCorrectPins()
UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_String, FunctionPinName); UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_String, FunctionPinName);
} }
if (!KeepPin(InvokeOrProbePinName))
{
UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Byte, IPEnum, InvokeOrProbePinName);
}
if (!KeepPin(PlacePinName)) if (!KeepPin(PlacePinName))
{ {
UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Object, AActor::StaticClass(), PlacePinName); UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Object, AActor::StaticClass(), PlacePinName);
@@ -205,9 +208,7 @@ void UK2Node_LuaCall::CreateCorrectPins()
// Copy the property names into the pins. // Copy the property names into the pins.
UEdGraphPin *FunctionPin = FindPinChecked(FunctionPinName); UEdGraphPin *FunctionPin = FindPinChecked(FunctionPinName);
UEdGraphPin *InvokeOrProbePin = FindPinChecked(InvokeOrProbePinName);
FunctionPin->DefaultValue = LuaFunctionPrototype; FunctionPin->DefaultValue = LuaFunctionPrototype;
InvokeOrProbePin->DefaultValue = InvokeOrProbe;
// Create Argument pins in the correct order, reusing old pins where possible. // Create Argument pins in the correct order, reusing old pins where possible.
for (const FlxParsedProto::Pin & Pin : ParsedProto.Arguments) for (const FlxParsedProto::Pin & Pin : ParsedProto.Arguments)
@@ -263,12 +264,19 @@ void UK2Node_LuaCall::CreateCorrectPins()
} }
FText UK2Node_LuaCall::GetNodeTitle(ENodeTitleType::Type TitleType) const FText UK2Node_LuaInvoke::GetNodeTitle(ENodeTitleType::Type TitleType) const
{ {
return LOCTEXT("LuaCall_Title", "Call a Lua Function"); if (IsInvoke())
{
return LOCTEXT("LuaInvoke_Title", "Invoke a Lua Function");
}
else
{
return LOCTEXT("LuaProbe_Title", "Probe a Lua Function");
}
} }
FText UK2Node_LuaCall::GetPinDisplayName(const UEdGraphPin* Pin) const FText UK2Node_LuaInvoke::GetPinDisplayName(const UEdGraphPin* Pin) const
{ {
// The exec pins don't need labels. // The exec pins don't need labels.
if ((Pin->PinName == UEdGraphSchema_K2::PN_Execute) || (Pin->PinName == UEdGraphSchema_K2::PN_Then)) if ((Pin->PinName == UEdGraphSchema_K2::PN_Execute) || (Pin->PinName == UEdGraphSchema_K2::PN_Then))
@@ -277,7 +285,7 @@ FText UK2Node_LuaCall::GetPinDisplayName(const UEdGraphPin* Pin) const
} }
// Many pins can go unlabeled if they have default values. // Many pins can go unlabeled if they have default values.
if ((Pin->PinName == FunctionPinName) || (Pin->PinName == InvokeOrProbePinName)) if (Pin->PinName == FunctionPinName)
{ {
if (Pin->LinkedTo.Num() == 0) if (Pin->LinkedTo.Num() == 0)
{ {
@@ -301,18 +309,18 @@ FText UK2Node_LuaCall::GetPinDisplayName(const UEdGraphPin* Pin) const
return FText::FromName(Pin->PinName); return FText::FromName(Pin->PinName);
} }
void UK2Node_LuaCall::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) void UK2Node_LuaInvoke::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
{ {
Super::PostEditChangeProperty(PropertyChangedEvent); Super::PostEditChangeProperty(PropertyChangedEvent);
GetGraph()->NotifyNodeChanged(this); GetGraph()->NotifyNodeChanged(this);
} }
void UK2Node_LuaCall::PinConnectionListChanged(UEdGraphPin* Pin) void UK2Node_LuaInvoke::PinConnectionListChanged(UEdGraphPin* Pin)
{ {
Modify(); Modify();
} }
void UK2Node_LuaCall::PinDefaultValueChanged(UEdGraphPin* Pin) void UK2Node_LuaInvoke::PinDefaultValueChanged(UEdGraphPin* Pin)
{ {
if(Pin->PinName == FunctionPinName) if(Pin->PinName == FunctionPinName)
{ {
@@ -320,20 +328,14 @@ void UK2Node_LuaCall::PinDefaultValueChanged(UEdGraphPin* Pin)
CreateCorrectPins(); CreateCorrectPins();
GetGraph()->NotifyNodeChanged(this); GetGraph()->NotifyNodeChanged(this);
} }
else if (Pin->PinName == InvokeOrProbePinName)
{
InvokeOrProbe = Pin->DefaultValue;
CreateCorrectPins();
GetGraph()->NotifyNodeChanged(this);
}
} }
FText UK2Node_LuaCall::GetTooltipText() const FText UK2Node_LuaInvoke::GetTooltipText() const
{ {
return NodeTooltip; return NodeTooltip;
} }
void UK2Node_LuaCall::PostReconstructNode() void UK2Node_LuaInvoke::PostReconstructNode()
{ {
Super::PostReconstructNode(); Super::PostReconstructNode();
CreateCorrectPins(); CreateCorrectPins();
@@ -342,7 +344,7 @@ void UK2Node_LuaCall::PostReconstructNode()
#define LuaCallLibraryFunction(name) (UlxLuaCallLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UlxLuaCallLibrary, name))) #define LuaCallLibraryFunction(name) (UlxLuaCallLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UlxLuaCallLibrary, name)))
void UK2Node_LuaCall::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) void UK2Node_LuaInvoke::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{ {
Super::ExpandNode(CompilerContext, SourceGraph); Super::ExpandNode(CompilerContext, SourceGraph);
const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema();
@@ -382,7 +384,14 @@ void UK2Node_LuaCall::ExpandNode(class FKismetCompilerContext& CompilerContext,
} }
// Add the invoke or probe node. // Add the invoke or probe node.
if (InvokeOrProbe == TEXT("Probe")) if (IsInvoke())
{
UK2Node_CallFunction* ActionNode = MakeCallFunctionNode(LuaCallLibraryFunction(LuaCallInvoke));
CompilerContext.MovePinLinksToIntermediate(*FindPinChecked(PlacePinName, EGPD_Input), *ActionNode->FindPinChecked(TEXT("Place")));
ThenPin->MakeLinkTo(ActionNode->GetExecPin());
ThenPin = ActionNode->GetThenPin();
}
else
{ {
UK2Node_CallFunction* ActionNode = MakeCallFunctionNode(LuaCallLibraryFunction(LuaCallProbe)); UK2Node_CallFunction* ActionNode = MakeCallFunctionNode(LuaCallLibraryFunction(LuaCallProbe));
CompilerContext.MovePinLinksToIntermediate(*FindPinChecked(PlacePinName, EGPD_Input), *ActionNode->FindPinChecked(TEXT("Place"))); CompilerContext.MovePinLinksToIntermediate(*FindPinChecked(PlacePinName, EGPD_Input), *ActionNode->FindPinChecked(TEXT("Place")));
@@ -390,13 +399,6 @@ void UK2Node_LuaCall::ExpandNode(class FKismetCompilerContext& CompilerContext,
ThenPin->MakeLinkTo(ActionNode->GetExecPin()); ThenPin->MakeLinkTo(ActionNode->GetExecPin());
ThenPin = ActionNode->FindPinChecked(TEXT("True")); ThenPin = ActionNode->FindPinChecked(TEXT("True"));
} }
else
{
UK2Node_CallFunction* ActionNode = MakeCallFunctionNode(LuaCallLibraryFunction(LuaCallInvoke));
CompilerContext.MovePinLinksToIntermediate(*FindPinChecked(PlacePinName, EGPD_Input), *ActionNode->FindPinChecked(TEXT("Place")));
ThenPin->MakeLinkTo(ActionNode->GetExecPin());
ThenPin = ActionNode->GetThenPin();
}
// Add Unpacking operations for all return value pins. // Add Unpacking operations for all return value pins.
for (const FlxParsedProto::Pin &PinInfo : ParsedProto.ReturnValues) for (const FlxParsedProto::Pin &PinInfo : ParsedProto.ReturnValues)
@@ -430,7 +432,7 @@ void UK2Node_LuaCall::ExpandNode(class FKismetCompilerContext& CompilerContext,
CompilerContext.MovePinLinksToIntermediate(*GetThenPin(), *ThenPin); CompilerContext.MovePinLinksToIntermediate(*GetThenPin(), *ThenPin);
// Make sure we didn't have return values for an invoke. // Make sure we didn't have return values for an invoke.
if ((InvokeOrProbe != TEXT("Probe")) && ((ParsedProto.ReturnValues.Num() > 0) || (ParsedProto.ExtraReturnValues))) if (IsInvoke() && ((ParsedProto.ReturnValues.Num() > 0) || (ParsedProto.ExtraReturnValues)))
{ {
CompilerContext.MessageLog.Error(TEXT("Lua Call in Invoke mode does not support return values")); CompilerContext.MessageLog.Error(TEXT("Lua Call in Invoke mode does not support return values"));
} }
@@ -439,7 +441,7 @@ void UK2Node_LuaCall::ExpandNode(class FKismetCompilerContext& CompilerContext,
} }
UK2Node::ERedirectType UK2Node_LuaCall::DoPinsMatchForReconstruction(const UEdGraphPin* NewPin, int32 NewPinIndex, const UEdGraphPin* OldPin, int32 OldPinIndex) const UK2Node::ERedirectType UK2Node_LuaInvoke::DoPinsMatchForReconstruction(const UEdGraphPin* NewPin, int32 NewPinIndex, const UEdGraphPin* OldPin, int32 OldPinIndex) const
{ {
ERedirectType RedirectType = ERedirectType_None; ERedirectType RedirectType = ERedirectType_None;
@@ -484,7 +486,7 @@ UK2Node::ERedirectType UK2Node_LuaCall::DoPinsMatchForReconstruction(const UEdGr
return RedirectType; return RedirectType;
} }
bool UK2Node_LuaCall::IsConnectionDisallowed(const UEdGraphPin* MyPin, const UEdGraphPin* OtherPin, FString& OutReason) const bool UK2Node_LuaInvoke::IsConnectionDisallowed(const UEdGraphPin* MyPin, const UEdGraphPin* OtherPin, FString& OutReason) const
{ {
// The function pin cannot be connected. // The function pin cannot be connected.
if (MyPin->PinName == FunctionPinName) if (MyPin->PinName == FunctionPinName)
@@ -493,17 +495,10 @@ bool UK2Node_LuaCall::IsConnectionDisallowed(const UEdGraphPin* MyPin, const UEd
return true; return true;
} }
// The invoke-or-probe pin cannot be connected.
if (MyPin->PinName == InvokeOrProbePinName)
{
OutReason = LOCTEXT("Error_InvokeOrProbeMustBeHardwired", "Invoke vs Probe must be a hardwired constant.").ToString();
return true;
}
return Super::IsConnectionDisallowed(MyPin, OtherPin, OutReason); return Super::IsConnectionDisallowed(MyPin, OtherPin, OutReason);
} }
void UK2Node_LuaCall::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const void UK2Node_LuaInvoke::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
{ {
// actions get registered under specific object-keys; the idea is that // actions get registered under specific object-keys; the idea is that
// actions might have to be updated (or deleted) if their object-key is // actions might have to be updated (or deleted) if their object-key is
@@ -523,7 +518,7 @@ void UK2Node_LuaCall::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRe
} }
} }
FText UK2Node_LuaCall::GetMenuCategory() const FText UK2Node_LuaInvoke::GetMenuCategory() const
{ {
return FText::FromString(FString(TEXT("Luprex|Lua"))); return FText::FromString(FString(TEXT("Luprex|Lua")));
} }

View File

@@ -22,23 +22,12 @@ class FString;
class UEdGraph; class UEdGraph;
class UObject; class UObject;
UENUM(BlueprintType)
enum class ElxInvokeOrProbe : uint8 {
/* Invoke the lua function: call it on the server, mutating the world state. */
Invoke,
/* Probe the lua function: call it locally, not mutating the world state. */
Probe,
};
// //
// The Lua Call K2Node. // The Lua Call K2Node.
// //
UCLASS(MinimalAPI) UCLASS(MinimalAPI)
class UK2Node_LuaCall : public UK2Node class UK2Node_LuaInvoke : public UK2Node
{ {
GENERATED_UCLASS_BODY() GENERATED_UCLASS_BODY()
@@ -70,12 +59,15 @@ class UK2Node_LuaCall : public UK2Node
private: private:
virtual bool IsInvoke() const { return true; }
FText MakeTooltip() const;
/** Create all necessary pins. */ /** Create all necessary pins. */
void CreateCorrectPins(); void CreateCorrectPins();
/** Pin Names for the three built-in Pins **/ /** Pin Names for the three built-in Pins **/
static const FName FunctionPinName; static const FName FunctionPinName;
static const FName InvokeOrProbePinName;
static const FName PlacePinName; static const FName PlacePinName;
static const FName ExtraResultsPinName; static const FName ExtraResultsPinName;
static const FName ErrorPinName; static const FName ErrorPinName;
@@ -90,12 +82,18 @@ private:
UPROPERTY() UPROPERTY()
FString LuaFunctionPrototype; FString LuaFunctionPrototype;
/** Equal to the invoke-or-probe property **/
UPROPERTY()
FString InvokeOrProbe;
/** Tooltip text for this node. */ /** Tooltip text for this node. */
FText NodeTooltip; FText NodeTooltip;
}; };
UCLASS(MinimalAPI)
class UK2Node_LuaProbe : public UK2Node_LuaInvoke
{
GENERATED_UCLASS_BODY()
// Setting this flag alters the behavior of LuaInvoke, making it
// probe instead of invoke.
//
virtual bool IsInvoke() const override { return false; }
};