2026-02-14 02:14:19 -05:00
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// LuaCall.h
|
|
|
|
|
//
|
|
|
|
|
// Low-level functions for calling Lua from blueprints.
|
|
|
|
|
// The "Call Lua" K2Node macroexpands into sequences
|
|
|
|
|
// of these functions.
|
|
|
|
|
//
|
|
|
|
|
// Also contains UlxLuaValues, which stores return
|
|
|
|
|
// values from Lua calls, and FlxParsedProto, which
|
|
|
|
|
// parses Lua function prototype strings.
|
|
|
|
|
//
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
|
2024-08-31 16:42:07 -04:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include "CoreMinimal.h"
|
2025-02-26 14:47:53 -05:00
|
|
|
#include "EdGraph/EdGraphPin.h"
|
2025-06-18 16:25:46 -04:00
|
|
|
#include <string_view>
|
|
|
|
|
#include <string>
|
2026-02-27 18:40:29 -05:00
|
|
|
#include "Kismet/BlueprintFunctionLibrary.h"
|
2024-08-31 16:42:07 -04:00
|
|
|
#include "LuaCall.generated.h"
|
|
|
|
|
|
2025-03-28 23:31:44 -04:00
|
|
|
class UlxLuaValues;
|
2025-02-26 14:47:53 -05:00
|
|
|
|
2026-02-14 02:14:19 -05:00
|
|
|
////////////////////////////////////////////////////////////
|
2025-02-26 14:47:53 -05:00
|
|
|
//
|
2026-02-14 02:14:19 -05:00
|
|
|
// FlxParsedProto
|
2025-02-26 14:47:53 -05:00
|
|
|
//
|
2026-02-14 02:14:19 -05:00
|
|
|
// The first argument to LuaCallNode is a function
|
|
|
|
|
// prototype of the form:
|
2025-02-26 14:47:53 -05:00
|
|
|
//
|
2026-02-14 02:14:19 -05:00
|
|
|
// class.name(int arg1, int arg2) : int ret1
|
2025-02-26 14:47:53 -05:00
|
|
|
//
|
2026-02-14 02:14:19 -05:00
|
|
|
// Return values can be omitted. The last return
|
|
|
|
|
// value can be an ellipsis. The class name can be
|
|
|
|
|
// asterisk.
|
2025-02-26 14:47:53 -05:00
|
|
|
//
|
2026-02-14 02:14:19 -05:00
|
|
|
////////////////////////////////////////////////////////////
|
2025-02-26 14:47:53 -05:00
|
|
|
|
|
|
|
|
class FlxParsedProto
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
struct Pin
|
|
|
|
|
{
|
|
|
|
|
FString Type;
|
|
|
|
|
FString Name;
|
|
|
|
|
Pin(const FString &T, const FString &N) : Type(T), Name(N) {}
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-14 02:14:19 -05:00
|
|
|
// If parsing generated an error, the error
|
|
|
|
|
// message is stored here.
|
|
|
|
|
//
|
2025-02-26 14:47:53 -05:00
|
|
|
FString ErrorMessage;
|
2026-02-14 02:14:19 -05:00
|
|
|
|
|
|
|
|
// The results of parsing the prototype.
|
|
|
|
|
//
|
2025-02-26 14:47:53 -05:00
|
|
|
FString ClassName;
|
|
|
|
|
FString FunctionName;
|
|
|
|
|
TArray<Pin> Arguments;
|
|
|
|
|
TArray<Pin> ReturnValues;
|
|
|
|
|
bool ExtraReturnValues;
|
|
|
|
|
|
2026-02-14 02:14:19 -05:00
|
|
|
// Used internally to help generate the error
|
|
|
|
|
// message.
|
|
|
|
|
//
|
|
|
|
|
TArray<FString> Tokens;
|
|
|
|
|
int NextToken;
|
|
|
|
|
|
2025-02-26 14:47:53 -05:00
|
|
|
private:
|
2026-02-14 02:14:19 -05:00
|
|
|
// Check the next token to see if it's exactly
|
|
|
|
|
// equal to text.
|
2025-02-26 14:47:53 -05:00
|
|
|
//
|
|
|
|
|
bool IsLiteral(const TCHAR *text);
|
|
|
|
|
|
2026-02-14 02:14:19 -05:00
|
|
|
// Check the next token to see if it's an
|
|
|
|
|
// identifier.
|
2025-02-26 14:47:53 -05:00
|
|
|
//
|
|
|
|
|
bool IsIdent();
|
|
|
|
|
|
|
|
|
|
// Make a syntax error message, using the tokens.
|
|
|
|
|
//
|
|
|
|
|
void Syntax();
|
|
|
|
|
|
|
|
|
|
// Empty out the FlxParsedProto.
|
|
|
|
|
//
|
|
|
|
|
void Empty();
|
|
|
|
|
|
|
|
|
|
// Parse a function prototype.
|
|
|
|
|
//
|
|
|
|
|
void Parse(const FString &proto);
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// Construct with a prototype.
|
|
|
|
|
//
|
|
|
|
|
FlxParsedProto(const FString &str) { Parse(str); }
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-14 02:14:19 -05:00
|
|
|
////////////////////////////////////////////////////////////
|
2024-08-31 16:42:07 -04:00
|
|
|
//
|
2026-02-14 02:14:19 -05:00
|
|
|
// UlxLuaCallLibrary
|
2024-08-31 16:42:07 -04:00
|
|
|
//
|
2026-02-14 02:14:19 -05:00
|
|
|
// Low-level functions that LuaCallNode macroexpands
|
|
|
|
|
// into. Every LuaCallNode expands into the following
|
|
|
|
|
// sequence of functions:
|
2025-02-26 14:47:53 -05:00
|
|
|
//
|
2026-02-14 02:14:19 -05:00
|
|
|
// * LuaCallBegin to set class/function name.
|
|
|
|
|
// * LuaCallArgument_XXX to pack arguments.
|
|
|
|
|
// * LuaCallInvoke or LuaCallProbe to call.
|
|
|
|
|
// * LuaCallReturnValue_XXX to fetch results.
|
2025-02-26 14:47:53 -05:00
|
|
|
//
|
2026-02-14 02:14:19 -05:00
|
|
|
// The buffers used by these functions are global
|
|
|
|
|
// variables in LuprexGameModeBase. It is ok to use
|
|
|
|
|
// globals, because blueprint is single-threaded.
|
2025-02-26 14:47:53 -05:00
|
|
|
//
|
2026-02-14 02:14:19 -05:00
|
|
|
////////////////////////////////////////////////////////////
|
2024-08-31 16:42:07 -04:00
|
|
|
|
|
|
|
|
UCLASS()
|
2026-02-27 18:40:29 -05:00
|
|
|
class INTEGRATION_API UlxLuaCallLibrary : public UBlueprintFunctionLibrary
|
2024-08-31 16:42:07 -04:00
|
|
|
{
|
|
|
|
|
GENERATED_BODY()
|
|
|
|
|
|
|
|
|
|
public:
|
2026-02-14 02:14:19 -05:00
|
|
|
// Get an argument packing function or a return
|
|
|
|
|
// value unpacking function.
|
2025-02-26 14:47:53 -05:00
|
|
|
//
|
|
|
|
|
static UFunction *GetArgumentPacker(const FString &Type);
|
|
|
|
|
static UFunction *GetReturnValueUnpacker(const FString &Type);
|
|
|
|
|
|
2026-02-14 02:14:19 -05:00
|
|
|
// Get the types supported for arguments and
|
|
|
|
|
// return values, as a documentation string.
|
2025-02-26 14:47:53 -05:00
|
|
|
//
|
|
|
|
|
static FString AllFunctionsWithPrefix(const TCHAR *Prefix);
|
|
|
|
|
static FString AllKnownArgumentTypes() { return AllFunctionsWithPrefix(TEXT("LuaCallArgument_")); }
|
|
|
|
|
static FString AllKnownReturnValueTypes() { return AllFunctionsWithPrefix(TEXT("LuaCallReturnValue_")); }
|
|
|
|
|
|
|
|
|
|
public:
|
2026-02-14 02:14:19 -05:00
|
|
|
////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Functions that initiate and complete the lua call.
|
|
|
|
|
//
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
|
|
|
|
2025-12-09 15:51:35 -05:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function")
|
|
|
|
|
static void InvokeLuaExpr(UObject *context, const FString &Code);
|
2025-02-26 14:47:53 -05:00
|
|
|
|
2025-03-19 16:01:38 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function")
|
2025-02-24 16:46:05 -05:00
|
|
|
static void LuaCallBegin(UObject *context, const FString &ClassName, const FString &FunctionName);
|
2026-02-14 02:14:19 -05:00
|
|
|
|
2025-03-19 16:01:38 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function")
|
2025-02-26 14:47:53 -05:00
|
|
|
static void LuaCallInvoke(UObject *context, AActor *Place);
|
2025-02-05 16:08:34 -05:00
|
|
|
|
2025-04-07 18:00:45 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", ExpandBoolAsExecs="ReturnValue", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function")
|
2025-04-08 18:53:26 -04:00
|
|
|
static bool LuaCallProbe(UObject *context, AActor *Place, UlxLuaValues *&ReturnArray);
|
2026-02-14 02:14:19 -05:00
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
2025-02-26 14:47:53 -05:00
|
|
|
//
|
|
|
|
|
// Functions that pack arguments into the call buffer.
|
|
|
|
|
//
|
2026-02-14 02:14:19 -05:00
|
|
|
////////////////////////////////////////////////////////
|
2024-08-31 16:42:07 -04:00
|
|
|
|
2025-03-19 16:01:38 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function")
|
2025-02-26 14:47:53 -05:00
|
|
|
static void LuaCallArgument_string(UObject *context, const FString &Value);
|
2025-02-24 16:46:05 -05:00
|
|
|
|
2025-03-19 16:01:38 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function")
|
2025-02-26 14:47:53 -05:00
|
|
|
static void LuaCallArgument_name(UObject *context, const FName &Value);
|
2025-02-24 16:46:05 -05:00
|
|
|
|
2025-03-19 16:01:38 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function")
|
2025-02-26 14:47:53 -05:00
|
|
|
static void LuaCallArgument_float(UObject *context, double Value);
|
|
|
|
|
|
2025-03-19 16:01:38 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function")
|
2025-02-26 14:47:53 -05:00
|
|
|
static void LuaCallArgument_int(UObject *context, int Value);
|
2024-08-31 16:42:07 -04:00
|
|
|
|
2025-03-19 16:01:38 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function")
|
2025-02-26 14:47:53 -05:00
|
|
|
static void LuaCallArgument_vector(UObject *context, const FVector &Value);
|
2024-09-05 01:33:37 -04:00
|
|
|
|
2025-03-19 16:01:38 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function")
|
2025-02-26 14:47:53 -05:00
|
|
|
static void LuaCallArgument_vector2d(UObject *context, const FVector2D &Value);
|
2024-09-05 01:33:37 -04:00
|
|
|
|
2025-03-19 16:01:38 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function")
|
2025-02-26 14:47:53 -05:00
|
|
|
static void LuaCallArgument_boolean(UObject *context, bool Value);
|
2024-08-31 16:42:07 -04:00
|
|
|
};
|
|
|
|
|
|
2026-02-14 02:14:19 -05:00
|
|
|
////////////////////////////////////////////////////////////
|
2025-04-07 16:48:27 -04:00
|
|
|
//
|
2026-02-14 02:14:19 -05:00
|
|
|
// UlxLuaValues
|
2025-04-07 16:48:27 -04:00
|
|
|
//
|
2026-02-14 02:14:19 -05:00
|
|
|
// Stores an array of values returned by Lua.
|
|
|
|
|
// Provides a cursor-based API for reading values
|
|
|
|
|
// one at a time with type checking.
|
|
|
|
|
//
|
|
|
|
|
////////////////////////////////////////////////////////////
|
2025-04-07 16:48:27 -04:00
|
|
|
|
|
|
|
|
UCLASS(BlueprintType)
|
|
|
|
|
class INTEGRATION_API UlxLuaValues : public UObject
|
|
|
|
|
{
|
|
|
|
|
GENERATED_BODY()
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// The raw serialized data returned by Lua.
|
|
|
|
|
//
|
|
|
|
|
std::string Serialized;
|
|
|
|
|
|
|
|
|
|
// For each chunk, the type of the chunk.
|
|
|
|
|
//
|
|
|
|
|
TArray<ElxLuaValueType> Types;
|
|
|
|
|
|
2026-02-14 02:14:19 -05:00
|
|
|
// For each chunk, a pointer to the serialized
|
|
|
|
|
// data.
|
2025-04-07 16:48:27 -04:00
|
|
|
//
|
|
|
|
|
TArray<std::string_view> Data;
|
|
|
|
|
|
|
|
|
|
// The current cursor.
|
|
|
|
|
//
|
|
|
|
|
int Cursor;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// Clear everything.
|
|
|
|
|
//
|
|
|
|
|
void Empty();
|
|
|
|
|
|
2026-02-14 02:14:19 -05:00
|
|
|
// Compare two types. If they aren't equal,
|
|
|
|
|
// possibly log an error, and return a status
|
|
|
|
|
// code.
|
2025-04-07 16:48:27 -04:00
|
|
|
//
|
2025-05-23 15:33:18 -04:00
|
|
|
static ElxSuccessOrWrongType CheckType(bool LogErrorOnWrongType, ElxLuaValueType Type, ElxLuaValueType Desired);
|
2025-04-07 16:48:27 -04:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
UlxLuaValues() { Cursor = 0; }
|
|
|
|
|
|
2026-02-14 02:14:19 -05:00
|
|
|
// Copies the data, then preprocesses it to make
|
|
|
|
|
// sure it's all valid. Returns false if invalid.
|
|
|
|
|
//
|
2025-04-07 16:48:27 -04:00
|
|
|
bool Initialize(std::string_view data);
|
|
|
|
|
|
2025-04-08 18:53:26 -04:00
|
|
|
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
|
|
|
|
void DiscardBeforeCursor();
|
|
|
|
|
|
2025-04-07 16:48:27 -04:00
|
|
|
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
|
|
|
|
FString DebugString() const;
|
|
|
|
|
|
|
|
|
|
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
|
|
|
|
int Length() const { return Types.Num(); }
|
|
|
|
|
|
|
|
|
|
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
|
|
|
|
int GetCursor() const { return Cursor; }
|
|
|
|
|
|
|
|
|
|
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
|
|
|
|
void SetCursor(int n) { Cursor = n; }
|
|
|
|
|
|
|
|
|
|
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
2025-04-07 19:29:47 -04:00
|
|
|
ElxLuaValueType NextType() const;
|
2026-02-14 02:14:19 -05:00
|
|
|
|
2025-04-07 16:48:27 -04:00
|
|
|
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
2025-04-07 19:29:47 -04:00
|
|
|
bool IsNextType(ElxLuaValueType Type) const { return NextType() == Type; }
|
2025-04-07 16:48:27 -04:00
|
|
|
|
2025-04-07 19:29:47 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "ReturnValue"), Category = "Luprex|Lua Value Array")
|
2025-04-08 16:31:16 -04:00
|
|
|
ElxLuaValueType SwitchNextType() { return NextType(); }
|
2026-02-14 02:14:19 -05:00
|
|
|
|
2025-04-07 19:29:47 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Status"), Category = "Luprex|Lua Value Array")
|
2025-05-23 15:33:18 -04:00
|
|
|
void ReadString(ElxSuccessOrWrongType &Status, FString &Result, bool LogErrorOnWrongType = false);
|
2026-02-14 02:14:19 -05:00
|
|
|
|
2025-04-07 19:29:47 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Status"), Category = "Luprex|Lua Value Array")
|
2025-05-23 15:33:18 -04:00
|
|
|
void ReadName(ElxSuccessOrWrongType &Status, FName &Result, bool LogErrorOnWrongType = false);
|
2026-02-14 02:14:19 -05:00
|
|
|
|
2025-04-07 19:29:47 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Status"), Category = "Luprex|Lua Value Array")
|
2025-05-23 15:33:18 -04:00
|
|
|
void ReadFloat(ElxSuccessOrWrongType &Status, double &Result, bool LogErrorOnWrongType = false);
|
2025-04-07 16:48:27 -04:00
|
|
|
|
2025-04-07 19:29:47 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Status"), Category = "Luprex|Lua Value Array")
|
2025-05-23 15:33:18 -04:00
|
|
|
void ReadInt(ElxSuccessOrWrongType &Status, int &Result, bool LogErrorOnWrongType = false);
|
2025-04-07 16:48:27 -04:00
|
|
|
|
2025-04-07 19:29:47 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Status"), Category = "Luprex|Lua Value Array")
|
2025-05-23 15:33:18 -04:00
|
|
|
void ReadVector(ElxSuccessOrWrongType &Status, FVector &Result, bool LogErrorOnWrongType = false);
|
2025-04-07 16:48:27 -04:00
|
|
|
|
2025-04-07 19:29:47 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Status"), Category = "Luprex|Lua Value Array")
|
2025-05-23 15:33:18 -04:00
|
|
|
void ReadVector2D(ElxSuccessOrWrongType &Status, FVector2D &Result, bool LogErrorOnWrongType = false);
|
2025-04-07 16:48:27 -04:00
|
|
|
|
2025-04-07 19:29:47 -04:00
|
|
|
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Status"), Category = "Luprex|Lua Value Array")
|
2025-05-23 15:33:18 -04:00
|
|
|
void ReadBoolean(ElxSuccessOrWrongType &Status, bool &Result, bool LogErrorOnWrongType = false);
|
2026-02-25 16:49:37 -05:00
|
|
|
|
|
|
|
|
// Allows you to pass a LuaValues to Format Message.
|
|
|
|
|
//
|
|
|
|
|
UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Lua Value Array")
|
|
|
|
|
static FFormatArgumentData FormatArgumentDataLuaValues(const UlxLuaValues *AutoConvertedValue, const FString &Name);
|
2026-02-14 02:14:19 -05:00
|
|
|
};
|