Lots of work on lua call interface, also improved makefiles

This commit is contained in:
2025-02-24 16:46:05 -05:00
parent 4023d19247
commit bed4f3e805
10 changed files with 1870 additions and 101 deletions

Binary file not shown.

View File

@@ -0,0 +1,868 @@
{
"folders": [
{
"name": "Integration",
"path": "."
},
{
"name": "UE5",
"path": "/home/jyelon/UnrealEngine"
}
],
"settings": {
"typescript.tsc.autoDetect": "off",
"npm.autoDetect": "off"
},
"extensions": {
"recommendations": [
"ms-vscode.cpptools",
"ms-dotnettools.csharp",
"vadimcn.vscode-lldb",
"ms-vscode.mono-debug",
"dfarley1.file-picker"
]
},
"tasks": {
"version": "2.0.0",
"tasks": [
{
"label": "Integration Linux Debug Build",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"Linux",
"Debug",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration Linux Debug Rebuild",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"Linux",
"Debug",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"dependsOn": [
"Integration Linux Debug Clean"
],
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration Linux Debug Clean",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"Linux",
"Debug",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex",
"-clean"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration Linux DebugGame Build",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"Linux",
"DebugGame",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration Linux DebugGame Rebuild",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"Linux",
"DebugGame",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"dependsOn": [
"Integration Linux DebugGame Clean"
],
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration Linux DebugGame Clean",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"Linux",
"DebugGame",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex",
"-clean"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration Linux Development Build",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"Linux",
"Development",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration Linux Development Rebuild",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"Linux",
"Development",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"dependsOn": [
"Integration Linux Development Clean"
],
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration Linux Development Clean",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"Linux",
"Development",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex",
"-clean"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration Linux Test Build",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"Linux",
"Test",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration Linux Test Rebuild",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"Linux",
"Test",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"dependsOn": [
"Integration Linux Test Clean"
],
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration Linux Test Clean",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"Linux",
"Test",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex",
"-clean"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration Linux Shipping Build",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"Linux",
"Shipping",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration Linux Shipping Rebuild",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"Linux",
"Shipping",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"dependsOn": [
"Integration Linux Shipping Clean"
],
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration Linux Shipping Clean",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"Linux",
"Shipping",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex",
"-clean"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration LinuxArm64 Debug Build",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"LinuxArm64",
"Debug",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration LinuxArm64 Debug Rebuild",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"LinuxArm64",
"Debug",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"dependsOn": [
"Integration LinuxArm64 Debug Clean"
],
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration LinuxArm64 Debug Clean",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"LinuxArm64",
"Debug",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex",
"-clean"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration LinuxArm64 DebugGame Build",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"LinuxArm64",
"DebugGame",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration LinuxArm64 DebugGame Rebuild",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"LinuxArm64",
"DebugGame",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"dependsOn": [
"Integration LinuxArm64 DebugGame Clean"
],
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration LinuxArm64 DebugGame Clean",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"LinuxArm64",
"DebugGame",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex",
"-clean"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration LinuxArm64 Development Build",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"LinuxArm64",
"Development",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration LinuxArm64 Development Rebuild",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"LinuxArm64",
"Development",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"dependsOn": [
"Integration LinuxArm64 Development Clean"
],
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration LinuxArm64 Development Clean",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"LinuxArm64",
"Development",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex",
"-clean"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration LinuxArm64 Test Build",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"LinuxArm64",
"Test",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration LinuxArm64 Test Rebuild",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"LinuxArm64",
"Test",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"dependsOn": [
"Integration LinuxArm64 Test Clean"
],
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration LinuxArm64 Test Clean",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"LinuxArm64",
"Test",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex",
"-clean"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration LinuxArm64 Shipping Build",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"LinuxArm64",
"Shipping",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration LinuxArm64 Shipping Rebuild",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"LinuxArm64",
"Shipping",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"dependsOn": [
"Integration LinuxArm64 Shipping Clean"
],
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "Integration LinuxArm64 Shipping Clean",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"Integration",
"LinuxArm64",
"Shipping",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex",
"-clean"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "IntegrationEditor Linux Debug Build",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"IntegrationEditor",
"Linux",
"Debug",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "IntegrationEditor Linux Debug Rebuild",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"IntegrationEditor",
"Linux",
"Debug",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"dependsOn": [
"IntegrationEditor Linux Debug Clean"
],
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "IntegrationEditor Linux Debug Clean",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"IntegrationEditor",
"Linux",
"Debug",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex",
"-clean"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "IntegrationEditor Linux DebugGame Build",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"IntegrationEditor",
"Linux",
"DebugGame",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "IntegrationEditor Linux DebugGame Rebuild",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"IntegrationEditor",
"Linux",
"DebugGame",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"dependsOn": [
"IntegrationEditor Linux DebugGame Clean"
],
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "IntegrationEditor Linux DebugGame Clean",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"IntegrationEditor",
"Linux",
"DebugGame",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex",
"-clean"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "IntegrationEditor Linux Development Build",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"IntegrationEditor",
"Linux",
"Development",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "IntegrationEditor Linux Development Rebuild",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"IntegrationEditor",
"Linux",
"Development",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex"
],
"problemMatcher": "$msCompile",
"dependsOn": [
"IntegrationEditor Linux Development Clean"
],
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
},
{
"label": "IntegrationEditor Linux Development Clean",
"group": "build",
"command": "Engine/Build/BatchFiles/Linux/Build.sh",
"args": [
"IntegrationEditor",
"Linux",
"Development",
"/home/jyelon/integration/Integration.uproject",
"-waitmutex",
"-clean"
],
"problemMatcher": "$msCompile",
"type": "shell",
"options": {
"cwd": "/home/jyelon/UnrealEngine"
}
}
]
},
"launch": {
"version": "0.2.0",
"configurations": [
{
"name": "Launch Integration (Debug)",
"request": "launch",
"program": "/home/jyelon/integration/Binaries/Linux/Integration-Linux-Debug",
"preLaunchTask": "Integration Linux Debug Build",
"args": [
],
"cwd": "/home/jyelon/UnrealEngine",
"type": "cppdbg",
"visualizerFile": "/home/jyelon/UnrealEngine/Engine/Extras/VisualStudioDebugging/Unreal.natvis",
"showDisplayString": true
},
{
"name": "Launch Integration (DebugGame)",
"request": "launch",
"program": "/home/jyelon/integration/Binaries/Linux/Integration-Linux-DebugGame",
"preLaunchTask": "Integration Linux DebugGame Build",
"args": [
],
"cwd": "/home/jyelon/UnrealEngine",
"type": "cppdbg",
"visualizerFile": "/home/jyelon/UnrealEngine/Engine/Extras/VisualStudioDebugging/Unreal.natvis",
"showDisplayString": true
},
{
"name": "Launch Integration (Development)",
"request": "launch",
"program": "/home/jyelon/integration/Binaries/Linux/Integration",
"preLaunchTask": "Integration Linux Development Build",
"args": [
],
"cwd": "/home/jyelon/UnrealEngine",
"type": "cppdbg",
"visualizerFile": "/home/jyelon/UnrealEngine/Engine/Extras/VisualStudioDebugging/Unreal.natvis",
"showDisplayString": true
},
{
"name": "Launch Integration (Test)",
"request": "launch",
"program": "/home/jyelon/integration/Binaries/Linux/Integration-Linux-Test",
"preLaunchTask": "Integration Linux Test Build",
"args": [
],
"cwd": "/home/jyelon/UnrealEngine",
"type": "cppdbg",
"visualizerFile": "/home/jyelon/UnrealEngine/Engine/Extras/VisualStudioDebugging/Unreal.natvis",
"showDisplayString": true
},
{
"name": "Launch Integration (Shipping)",
"request": "launch",
"program": "/home/jyelon/integration/Binaries/Linux/Integration-Linux-Shipping",
"preLaunchTask": "Integration Linux Shipping Build",
"args": [
],
"cwd": "/home/jyelon/UnrealEngine",
"type": "cppdbg",
"visualizerFile": "/home/jyelon/UnrealEngine/Engine/Extras/VisualStudioDebugging/Unreal.natvis",
"showDisplayString": true
},
{
"name": "Launch IntegrationEditor (Debug)",
"request": "launch",
"program": "/home/jyelon/UnrealEngine/Engine/Binaries/Linux/UnrealEditor-Linux-Debug",
"preLaunchTask": "IntegrationEditor Linux Debug Build",
"args": [
"/home/jyelon/integration/Integration.uproject"
],
"cwd": "/home/jyelon/UnrealEngine",
"type": "cppdbg",
"visualizerFile": "/home/jyelon/UnrealEngine/Engine/Extras/VisualStudioDebugging/Unreal.natvis",
"showDisplayString": true
},
{
"name": "Launch IntegrationEditor (DebugGame)",
"request": "launch",
"program": "/home/jyelon/UnrealEngine/Engine/Binaries/Linux/UnrealEditor-Linux-DebugGame",
"preLaunchTask": "IntegrationEditor Linux DebugGame Build",
"args": [
"/home/jyelon/integration/Integration.uproject"
],
"cwd": "/home/jyelon/UnrealEngine",
"type": "cppdbg",
"visualizerFile": "/home/jyelon/UnrealEngine/Engine/Extras/VisualStudioDebugging/Unreal.natvis",
"showDisplayString": true
},
{
"name": "Launch IntegrationEditor (Development)",
"request": "launch",
"program": "/home/jyelon/UnrealEngine/Engine/Binaries/Linux/UnrealEditor",
"preLaunchTask": "IntegrationEditor Linux Development Build",
"args": [
"/home/jyelon/integration/Integration.uproject"
],
"cwd": "/home/jyelon/UnrealEngine",
"type": "cppdbg",
"visualizerFile": "/home/jyelon/UnrealEngine/Engine/Extras/VisualStudioDebugging/Unreal.natvis",
"showDisplayString": true
},
{
"name": "Generate Project Files",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "UnrealBuildTool Linux Development Build",
"program": "/home/jyelon/UnrealEngine/Engine/Build/BatchFiles/RunUBT.bat",
"args": [
"-projectfiles",
"-vscode",
"-project=/home/jyelon/integration/Integration.uproject",
"-game",
"-engine",
"-dotnet"
],
"console": "internalConsole",
"internalConsoleOptions": "openOnSessionStart",
"stopAtEntry": false,
"cwd": "/home/jyelon/UnrealEngine"
}
]
}
}

View File

@@ -267,7 +267,7 @@ FText UK2Node_FormatError::GetTooltipText() const
return NodeTooltip;
}
UEdGraphPin* FindOutputStructPinChecked(UEdGraphNode* Node)
static UEdGraphPin* FindOutputStructPinChecked(UEdGraphNode* Node)
{
check(NULL != Node);
UEdGraphPin* OutputPin = NULL;

View File

@@ -13,6 +13,37 @@ static void CheckNotEmpty(const FlxStreamBuffer &sb) {
}
}
static constexpr uint64_t ParseNameAsToken(std::string_view str) {
uint64_t result = 0;
uint64_t maxint = uint64_t(-1);
// Leading zeros are not allowed.
if ((!str.empty()) && (str[0]=='0')) return 0;
for (int i = 0; i < int(str.size()); i++) {
char c = str[i];
uint64_t digit = 0;
if ((c >= '0') && (c <= '9')) {
digit = uint64_t(c - '0');
} else if ((c >= 'a') && (c <= 'z')) {
digit = uint64_t(c - 'a' + 10);
} else if ((c >= 'A') && (c <= 'Z')) {
digit = uint64_t(c - 'A' + 10);
} else {
return maxint;
}
// Multiply existing number by 36, then add the digit.
// We have two checks to prevent integer overflow.
if (result > (maxint / 36)) return 0;
result *= 36;
if (digit > (maxint - result)) return 0;
result += digit;
}
return result;
}
void UlxLuaCallLibrary::LuaCallBegin(UObject *context, const FString &cname, const FString &fname) {
AIntegrationGameModeBase *mode = AIntegrationGameModeBase::GetFromContext(context);
FlxStreamBuffer &sb = mode->LuaCallGetBuffer();
@@ -31,11 +62,17 @@ void UlxLuaCallLibrary::LuaCallAddStringParameter(UObject *context, const FStrin
}
void UlxLuaCallLibrary::LuaCallAddNameParameter(UObject *context, const FName &pname) {
FTCHARToUTF8 utf8str(pname.ToString());
std::string_view namestr(utf8str.Get(), utf8str.Length());
uint64_t tokvalue = ParseNameAsToken(namestr);
if ((tokvalue == 0) && !namestr.empty()) {
FatalBlueprintError(TEXT("Names passed to lua must be short, and must contain only lowercase and digits"));
}
AIntegrationGameModeBase *mode = AIntegrationGameModeBase::GetFromContext(context);
FlxStreamBuffer &sb = mode->LuaCallGetBuffer();
CheckNotEmpty(sb);
sb.write_simple_dynamic_tag(SimpleDynamicTag::STRING);
sb.write_fname(pname);
sb.write_simple_dynamic_tag(SimpleDynamicTag::TOKEN);
sb.write_string(namestr);
}
void UlxLuaCallLibrary::LuaCallAddFloatParameter(UObject *context, double pfloat) {
@@ -46,6 +83,13 @@ void UlxLuaCallLibrary::LuaCallAddFloatParameter(UObject *context, double pfloat
sb.write_double(pfloat);
}
void UlxLuaCallLibrary::LuaCallAddIntParameter(UObject *context, int value) {
AIntegrationGameModeBase *mode = AIntegrationGameModeBase::GetFromContext(context);
FlxStreamBuffer &sb = mode->LuaCallGetBuffer();
CheckNotEmpty(sb);
sb.write_simple_dynamic_tag(SimpleDynamicTag::NUMBER);
sb.write_double(value);
}
void UlxLuaCallLibrary::LuaCallAddVectorParameter(UObject *context, const FVector &pvector) {
AIntegrationGameModeBase *mode = AIntegrationGameModeBase::GetFromContext(context);
@@ -55,6 +99,15 @@ void UlxLuaCallLibrary::LuaCallAddVectorParameter(UObject *context, const FVecto
sb.write_fvector(pvector);
}
void UlxLuaCallLibrary::LuaCallAddVector2DParameter(UObject *context, const FVector2D &pvector) {
AIntegrationGameModeBase *mode = AIntegrationGameModeBase::GetFromContext(context);
FlxStreamBuffer &sb = mode->LuaCallGetBuffer();
CheckNotEmpty(sb);
sb.write_simple_dynamic_tag(SimpleDynamicTag::VECTOR);
sb.write_double(pvector.X);
sb.write_double(pvector.Y);
sb.write_double(0.0);
}
void UlxLuaCallLibrary::LuaCallAddBooleanParameter(UObject *context, bool pbool) {
AIntegrationGameModeBase *mode = AIntegrationGameModeBase::GetFromContext(context);

View File

@@ -28,28 +28,34 @@ class INTEGRATION_API UlxLuaCallLibrary : public UObject
public:
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function")
static void LuaCallBegin(UObject *context, const FString &cname, const FString &fname);
static void LuaCallBegin(UObject *context, const FString &ClassName, const FString &FunctionName);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function")
static void LuaCallAddStringParameter(UObject *context, const FString &pstring);
static void LuaCallAddStringParameter(UObject *context, const FString &Value);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function")
static void LuaCallAddNameParameter(UObject *context, const FName &pname);
static void LuaCallAddNameParameter(UObject *context, const FName &Value);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function")
static void LuaCallAddFloatParameter(UObject *context, double pfloat);
static void LuaCallAddFloatParameter(UObject *context, double Value);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function")
static void LuaCallAddVectorParameter(UObject *context, const FVector &pvector);
static void LuaCallAddIntParameter(UObject *context, int Value);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function")
static void LuaCallAddBooleanParameter(UObject *context, bool pbool);
static void LuaCallAddVectorParameter(UObject *context, const FVector &Value);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function")
static void LuaCallInvoke(UObject *context, AActor *place);
static void LuaCallAddVector2DParameter(UObject *context, const FVector2D &Value);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function")
static void LuaCallProbe(UObject *context, AActor *place);
static void LuaCallAddBooleanParameter(UObject *context, bool Value);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function")
static void LuaCallInvoke(UObject *context, AActor *Place);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function")
static void LuaCallProbe(UObject *context, AActor *Place);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function")
static void InvokeEngioMove(UObject *context, const FString &action, const FVector &xyz, double facing);

View File

@@ -0,0 +1,697 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "LuaCallNode.h"
#include "BlueprintActionDatabaseRegistrar.h"
#include "BlueprintNodeSpawner.h"
#include "Containers/EnumAsByte.h"
#include "Containers/UnrealString.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphSchema.h"
#include "EdGraphSchema_K2.h"
#include "EdGraphSchema_K2_Actions.h"
#include "EditorCategoryUtils.h"
#include "Engine/Blueprint.h"
#include "HAL/PlatformCrt.h"
#include "Internationalization/Internationalization.h"
#include "K2Node_CallFunction.h"
#include "K2Node_MakeArray.h"
#include "K2Node_MakeStruct.h"
#include "Kismet/KismetMathLibrary.h"
#include "Kismet/KismetTextLibrary.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "Kismet2/CompilerResultsLog.h"
#include "KismetCompiler.h"
#include "LuaCall.h"
#include "Math/Vector2D.h"
#include "Misc/AssertionMacros.h"
#include "Misc/CString.h"
#include "ScopedTransaction.h"
#include "Templates/Casts.h"
#include "Templates/SubclassOf.h"
#include "UObject/Class.h"
#include "UObject/ObjectPtr.h"
#include "UObject/Package.h"
#include "UObject/UnrealNames.h"
#include "UObject/UnrealType.h"
#include "UObject/WeakObjectPtr.h"
#include "UObject/WeakObjectPtrTemplates.h"
#define LOCTEXT_NAMESPACE "LuaCall"
// All argument pins will have internal Names that start with "A:"
static bool IsArgumentPin(const UEdGraphPin *Pin) {
TCHAR pname[FName::StringBufferSize];
Pin->PinName.ToString(pname);
return pname[0] == 'A' && pname[1] == ':';
}
static FName ArgumentNameAddPrefix(const FString &name) {
FString Prefixed = FString("A:") + 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) {
TCHAR pname[FName::StringBufferSize];
Pin->PinName.ToString(pname);
return pname[0] == 'R' && pname[1] == ':';
}
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);
}
// A parser for lua function prototypes.
//
struct FlxParsedProto {
FString ErrorMessage;
TArray<FString> Tokens;
int NextToken;
FString ClassName;
FString FunctionName;
TArray<FString> Arguments;
TArray<FString> ReturnValues;
bool ExtraReturnValues;
// Check the next token to see if it's exactly equal to text.
//
bool IsLiteral(const TCHAR *text);
// Check the next token to see if it's an identifier.
//
bool IsIdent();
// Empty out the FlxParsedProto.
//
void Empty();
// Make a syntax error message, using the tokens.
//
void Syntax();
// Parse a function prototype.
//
void Parse(const FString &proto);
// Construct with a prototype.
//
FlxParsedProto(const FString &str) { Parse(str); }
};
bool FlxParsedProto::IsLiteral(const TCHAR *text) {
return ((NextToken < Tokens.Num()) && (Tokens[NextToken] == text));
}
bool FlxParsedProto::IsIdent() {
return ((NextToken < Tokens.Num()) && (FChar::IsAlpha(Tokens[NextToken][0])));
}
void FlxParsedProto::Empty() {
ErrorMessage = TEXT("");
Tokens.Empty();
NextToken = 0;
ClassName = TEXT("");
FunctionName = TEXT("");
Arguments.Empty();
ReturnValues.Empty();
ExtraReturnValues = false;
}
void FlxParsedProto::Syntax() {
FString Message;
if (Tokens.Num() == 0) {
Message = TEXT("Function prototype cannot be blank");
}
for (int i = 0; i < Tokens.Num(); i++) {
if (i == NextToken) {
Message.Append(TEXT(" ? "));
} else {
if ((i > 0) && (FChar::IsAlpha(Tokens[i][0])) && (FChar::IsAlpha(Tokens[i-1][0]))) {
Message.Append(TEXT(" "));
}
}
Message.Append(Tokens[i]);
}
Empty();
ErrorMessage = Message;
}
void FlxParsedProto::Parse(const FString &str) {
Empty();
// Step one: tokenize.
int offset = 0;
while (offset < str.Len()) {
TCHAR c = str[offset];
if (FChar::IsWhitespace(c)) {
offset++;
} else if (FChar::IsAlpha(c)) {
int lo = offset;
while ((offset < str.Len()) && FChar::IsAlnum(str[offset])) offset++;
Tokens.Add(str.Mid(lo, offset-lo));
} else if (str.Mid(offset, 3) == TEXT("...")) {
Tokens.Add(str.Mid(offset, 3));
offset += 3;
} else if (FChar::IsPunct(c)) {
Tokens.Add(str.Mid(offset, 1));
offset += 1;
} else {
Empty();
ErrorMessage = FString::Printf(TEXT("%s ? %s"), *str.Mid(0, offset), *str.Mid(offset));
return;
}
}
NextToken = 0;
// Step two: Parse.
if (!IsLiteral(TEXT("function"))) return Syntax();
NextToken++;
if (!IsLiteral(TEXT("*")) && !IsIdent()) return Syntax();
ClassName = Tokens[NextToken++];
if (!IsLiteral(TEXT("."))) return Syntax();
NextToken++;
if (!IsIdent()) return Syntax();
FunctionName = Tokens[NextToken++];
if (!IsLiteral(TEXT("("))) return Syntax();
NextToken++;
if (IsIdent()) {
while (true) {
if (!IsIdent()) return Syntax();
Arguments.Add(Tokens[NextToken++]);
if (!IsLiteral(TEXT(","))) break;
NextToken++;
}
}
if (!IsLiteral(TEXT(")"))) return Syntax();
NextToken++;
if (IsLiteral(TEXT(":"))) {
NextToken++;
while (true) {
if (IsLiteral(TEXT("..."))) {
ExtraReturnValues = true;
NextToken++;
break;
} else if (IsIdent()) {
ReturnValues.Add(Tokens[NextToken++]);
if (!IsLiteral(TEXT(","))) break;
NextToken++;
} else {
return Syntax();
}
}
}
if (NextToken != Tokens.Num()) return Syntax();
}
UK2Node_LuaCall::UK2Node_LuaCall(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
NodeTooltip = LOCTEXT("NodeTooltip",
"Probe or Invoke a Lua function.\n"
"\n"
"The lua function prototype must be a hardwired string which must look like\n"
"one of the following:"
"\n"
" function cname.fname(arg1, arg2)"
" function cname.fname(arg1, arg2) : ret1, ret2\n"
" function cname.fname(arg1, arg2) : ret1, ret2, ...\n"
"\n"
"The prototype is parsed to determine what lua function to call.\n"
"The lua call node will automatically add pins for the arguments and\n"
"return values. If the function has no return values, you can omit those\n"
"from the proto. If you put an ellipsis at the end of the return values,\n"
"then any additional return values will be collected into a\n"
"dynamically typed array of values which you can iterate over later.\n"
"\n"
"Optionally, you may use the * wildcard for the classname. In that\n"
"case, the class of the 'place' tangible will be used.\n"
"\n"
"Argument and return value pins have wildcard types initially, you can\n"
"hook them to inputs and outputs of the following types:\n"
"\n"
" string, name, float, boolean, vector\n"
"\n");
}
void UK2Node_LuaCall::AllocateDefaultPins()
{
Super::AllocateDefaultPins();
CreateCorrectPins();
}
void UK2Node_LuaCall::CreateCorrectPins()
{
if (LuaFunctionPrototype.IsEmpty())
{
LuaFunctionPrototype = TEXT("function class.func(arg1, arg2) : ret1, 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())
{
bHasCompilerMessage = true;
ErrorType = EMessageSeverity::Error;
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;
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();
}
}
// Create Argument pins in the correct order, reusing old pins where possible.
for (const FString& Name : ParsedProto.Arguments)
{
FName PrefixedName = ArgumentNameAddPrefix(Name);
UEdGraphPin **OldPin = OldArgumentPins.Find(PrefixedName);
if (OldPin != nullptr) {
Pins.Emplace(*OldPin);
OldArgumentPins.Remove(PrefixedName);
} else {
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Wildcard, PrefixedName);
}
}
// Create ReturnValue pins in the correct order, reusing old pins where possible.
for (const FString& Name : ParsedProto.ReturnValues)
{
FName PrefixedName = ReturnValueNameAddPrefix(Name);
UEdGraphPin **OldPin = OldReturnValuePins.Find(PrefixedName);
if (OldPin != nullptr) {
Pins.Emplace(*OldPin);
OldReturnValuePins.Remove(PrefixedName);
} else {
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Wildcard, PrefixedName);
}
}
// Delete any unused pins.
for (auto &iter : OldArgumentPins)
{
iter.Value->Modify();
iter.Value->MarkAsGarbage();
}
for (auto &iter : OldReturnValuePins)
{
iter.Value->Modify();
iter.Value->MarkAsGarbage();
}
OldArgumentPins.Empty();
OldReturnValuePins.Empty();
}
void UK2Node_LuaCall::SynchronizePinType(UEdGraphPin* Pin)
{
if (IsArgumentPin(Pin) || IsReturnValuePin(Pin))
{
const UEdGraphSchema_K2* K2Schema = Cast<const UEdGraphSchema_K2>(GetSchema());
bool bPinTypeChanged = false;
if (Pin->LinkedTo.Num() == 0)
{
static const FEdGraphPinType WildcardPinType = FEdGraphPinType(UEdGraphSchema_K2::PC_Wildcard, NAME_None, nullptr, EPinContainerType::None, false, FEdGraphTerminalType());
// Ensure wildcard
if (Pin->PinType != WildcardPinType)
{
Pin->PinType = WildcardPinType;
bPinTypeChanged = true;
}
}
else
{
UEdGraphPin* OtherPin = Pin->LinkedTo[0];
// Take the type of the connected pin
if (Pin->PinType != OtherPin->PinType)
{
Pin->PinType = OtherPin->PinType;
bPinTypeChanged = true;
}
}
if (bPinTypeChanged)
{
// Let the graph know to refresh
GetGraph()->NotifyNodeChanged(this);
UBlueprint* Blueprint = GetBlueprint();
if (!Blueprint->bBeingCompiled)
{
FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
}
}
}
}
FText UK2Node_LuaCall::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
return LOCTEXT("LuaCall_Title", "Probe or Invoke a Lua Function");
}
FText UK2Node_LuaCall::GetPinDisplayName(const UEdGraphPin* Pin) const
{
// The exec pins don't need labels.
if (Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_Exec)
{
return FText::GetEmpty();
}
// Many pins can go unlabeled if they have default values.
if (IsFunctionPin(Pin) || IsInvokeOrProbePin(Pin))
{
if (Pin->LinkedTo.Num() == 0)
{
return FText::GetEmpty();
}
}
// For argument pins, we must strip off the Argument Pin Prefix.
if (IsArgumentPin(Pin)) {
return FText::FromString(ArgumentNameRemovePrefix(Pin->PinName));
}
// For return value pins, we must strip off the Return Value Pin Prefix.
if (IsReturnValuePin(Pin)) {
return FText::FromString(ReturnValueNameRemovePrefix(Pin->PinName));
}
// Otherwise, just return the Pin Name the normal way.
return FText::FromName(Pin->PinName);
}
void UK2Node_LuaCall::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
GetGraph()->NotifyNodeChanged(this);
}
void UK2Node_LuaCall::PinConnectionListChanged(UEdGraphPin* Pin)
{
Modify();
SynchronizePinType(Pin);
}
void UK2Node_LuaCall::PinDefaultValueChanged(UEdGraphPin* Pin)
{
if(IsFunctionPin(Pin))
{
LuaFunctionPrototype = Pin->DefaultValue;
CreateCorrectPins();
GetGraph()->NotifyNodeChanged(this);
}
}
void UK2Node_LuaCall::PinTypeChanged(UEdGraphPin* Pin)
{
SynchronizePinType(Pin);
Super::PinTypeChanged(Pin);
}
FText UK2Node_LuaCall::GetTooltipText() const
{
return NodeTooltip;
}
void UK2Node_LuaCall::PostReconstructNode()
{
Super::PostReconstructNode();
UEdGraph* OuterGraph = GetGraph();
if (!IsTemplate() && OuterGraph && OuterGraph->Schema) {
for (UEdGraphPin* CurrentPin : Pins)
{
SynchronizePinType(CurrentPin);
}
}
CreateCorrectPins();
}
#define LuaCallLibraryFunction(name) (UlxLuaCallLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UlxLuaCallLibrary, name)))
static UFunction *GetArgumentPackingFunction(const FEdGraphPinType &Type)
{
if (Type.PinCategory == UEdGraphSchema_K2::PC_Real)
{
return LuaCallLibraryFunction(LuaCallAddFloatParameter);
}
if (Type.PinCategory == UEdGraphSchema_K2::PC_Int)
{
return LuaCallLibraryFunction(LuaCallAddIntParameter);
}
else if (Type.PinCategory == UEdGraphSchema_K2::PC_Boolean)
{
return LuaCallLibraryFunction(LuaCallAddBooleanParameter);
}
else if (Type.PinCategory == UEdGraphSchema_K2::PC_Name)
{
return LuaCallLibraryFunction(LuaCallAddNameParameter);
}
else if (Type.PinCategory == UEdGraphSchema_K2::PC_String)
{
return LuaCallLibraryFunction(LuaCallAddStringParameter);
}
else if ((Type.PinCategory == UEdGraphSchema_K2::PC_Struct) && (Type.PinSubCategoryObject == TBaseStructure<FVector>::Get()))
{
return LuaCallLibraryFunction(LuaCallAddVectorParameter);
}
else if ((Type.PinCategory == UEdGraphSchema_K2::PC_Struct) && (Type.PinSubCategoryObject == TBaseStructure<FVector2D>::Get()))
{
return LuaCallLibraryFunction(LuaCallAddVector2DParameter);
}
else
{
return nullptr;
}
}
void UK2Node_LuaCall::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
Super::ExpandNode(CompilerContext, SourceGraph);
const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema();
// Define a local function that creates a CallFunctionNode
auto MakeCallFunctionNode = [&](UFunction *func)
{
UK2Node_CallFunction* CallNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
CallNode->SetFromFunction(func);
CallNode->AllocateDefaultPins();
CompilerContext.MessageLog.NotifyIntermediateObjectCreation(CallNode, this);
return CallNode;
};
// The BeginNode function packs the class name and function name into the call buffer.
FlxParsedProto ParsedProto(LuaFunctionPrototype);
UK2Node_CallFunction* BeginNode = MakeCallFunctionNode(LuaCallLibraryFunction(LuaCallBegin));
Schema->TrySetDefaultValue(*BeginNode->FindPinChecked(TEXT("ClassName")), ParsedProto.ClassName);
Schema->TrySetDefaultValue(*BeginNode->FindPinChecked(TEXT("FunctionName")), ParsedProto.FunctionName);
UK2Node_CallFunction* PrevNode = BeginNode;
// Add Packing operations for all argument pins.
for (UEdGraphPin* Pin : Pins)
{
if (IsArgumentPin(Pin))
{
UFunction *PackingFunc = GetArgumentPackingFunction(Pin->PinType);
if (PackingFunc != nullptr)
{
UK2Node_CallFunction *PackNode = MakeCallFunctionNode(PackingFunc);
CompilerContext.MovePinLinksToIntermediate(*Pin, *PackNode->FindPinChecked(TEXT("Value")));
PrevNode->GetThenPin()->MakeLinkTo(PackNode->GetExecPin());
PrevNode = PackNode;
}
else
{
FText PinName = GetPinDisplayName(Pin);
FText PinType = FText::FromName(Pin->PinType.PinCategory);
FText Error = FText::Format(LOCTEXT("Error_UnexpectedPinType", "Pin '{0}' has an unexpected type: {1}"), PinName, PinType);
CompilerContext.MessageLog.Error(*Error.ToString());
}
}
}
// Add the invoke or probe node.
bool IsInvoke = (FindPin(InvokeOrProbePinName, EGPD_Input)->DefaultValue == TEXT("Invoke"));
UFunction *Action = IsInvoke ? LuaCallLibraryFunction(LuaCallInvoke) : LuaCallLibraryFunction(LuaCallProbe);
UK2Node_CallFunction* ActionNode = MakeCallFunctionNode(Action);
CompilerContext.MovePinLinksToIntermediate(*FindPin(PlacePinName, EGPD_Input), *ActionNode->FindPinChecked(TEXT("Place")));
PrevNode->GetThenPin()->MakeLinkTo(ActionNode->GetExecPin());
// Link up the Exec pins.
CompilerContext.MovePinLinksToIntermediate(*GetExecPin(), *BeginNode->GetExecPin());
CompilerContext.MovePinLinksToIntermediate(*GetThenPin(), *ActionNode->GetThenPin());
BreakAllNodeLinks();
}
UK2Node::ERedirectType UK2Node_LuaCall::DoPinsMatchForReconstruction(const UEdGraphPin* NewPin, int32 NewPinIndex, const UEdGraphPin* OldPin, int32 OldPinIndex) const
{
ERedirectType RedirectType = ERedirectType_None;
// if the pin names do match
if (NewPin->PinName.ToString().Equals(OldPin->PinName.ToString(), ESearchCase::CaseSensitive))
{
// Make sure we're not dealing with a menu node
UEdGraph* OuterGraph = GetGraph();
if( OuterGraph && OuterGraph->Schema )
{
const UEdGraphSchema_K2* K2Schema = Cast<const UEdGraphSchema_K2>(GetSchema());
if( !K2Schema || K2Schema->IsSelfPin(*NewPin) || K2Schema->ArePinTypesCompatible(OldPin->PinType, NewPin->PinType) )
{
RedirectType = ERedirectType_Name;
}
else
{
RedirectType = ERedirectType_None;
}
}
}
else
{
// try looking for a redirect if it's a K2 node
if (UK2Node* Node = Cast<UK2Node>(NewPin->GetOwningNode()))
{
// if you don't have matching pin, now check if there is any redirect param set
TArray<FString> OldPinNames;
GetRedirectPinNames(*OldPin, OldPinNames);
FName NewPinName;
RedirectType = ShouldRedirectParam(OldPinNames, /*out*/ NewPinName, Node);
// make sure they match
if ((RedirectType != ERedirectType_None) && (!NewPin->PinName.ToString().Equals(NewPinName.ToString(), ESearchCase::CaseSensitive)))
{
RedirectType = ERedirectType_None;
}
}
}
return RedirectType;
}
bool UK2Node_LuaCall::IsConnectionDisallowed(const UEdGraphPin* MyPin, const UEdGraphPin* OtherPin, FString& OutReason) const
{
// The function pin cannot be connected.
if (IsFunctionPin(MyPin))
{
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))
{
OutReason = LOCTEXT("Error_InvokeOrProbeMustBeHardwired", "Invoke vs Probe must be a hardwired constant.").ToString();
return true;
}
// Argument input pins may only be connected to packable types.
if (IsArgumentPin(MyPin))
{
UFunction *Packer = GetArgumentPackingFunction(OtherPin->PinType);
if (Packer == nullptr)
{
OutReason = LOCTEXT("Error_InvalidArgumentType", "Lua Call Arguments may be float, boolean, string, name, or vector.").ToString();
return true;
}
}
return Super::IsConnectionDisallowed(MyPin, OtherPin, OutReason);
}
void UK2Node_LuaCall::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
{
// actions get registered under specific object-keys; the idea is that
// actions might have to be updated (or deleted) if their object-key is
// mutated (or removed)... here we use the node's class (so if the node
// type disappears, then the action should go with it)
UClass* ActionKey = GetClass();
// to keep from needlessly instantiating a UBlueprintNodeSpawner, first
// check to make sure that the registrar is looking for actions of this type
// (could be regenerating actions for a specific asset, and therefore the
// registrar would only accept actions corresponding to that asset)
if (ActionRegistrar.IsOpenForRegistration(ActionKey))
{
UBlueprintNodeSpawner* NodeSpawner = UBlueprintNodeSpawner::Create(GetClass());
check(NodeSpawner != nullptr);
ActionRegistrar.AddBlueprintAction(ActionKey, NodeSpawner);
}
}
FText UK2Node_LuaCall::GetMenuCategory() const
{
return FEditorCategoryUtils::GetCommonCategory(FCommonEditorCategory::Text);
}
#undef LOCTEXT_NAMESPACE

View File

@@ -0,0 +1,87 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "BlueprintErrors.h"
#include "Containers/Array.h"
#include "CoreMinimal.h"
#include "EdGraph/EdGraphNode.h"
#include "EdGraph/EdGraphPin.h"
#include "HAL/Platform.h"
#include "Internationalization/Text.h"
#include "K2Node.h"
#include "UObject/NameTypes.h"
#include "UObject/ObjectMacros.h"
#include "UObject/UObjectGlobals.h"
#include "BlueprintErrors.h"
#include "LuaCallNode.generated.h"
class FBlueprintActionDatabaseRegistrar;
class FString;
class UEdGraph;
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.
//
UCLASS(MinimalAPI)
class UK2Node_LuaCall : public UK2Node
{
GENERATED_UCLASS_BODY()
//~ Begin UObject Interface
virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override;
//~ End UObject Interface
//~ Begin UEdGraphNode Interface.
virtual void AllocateDefaultPins() override;
virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
virtual bool ShouldShowNodeProperties() const override { return true; }
virtual void PinConnectionListChanged(UEdGraphPin* Pin) override;
virtual void PinDefaultValueChanged(UEdGraphPin* Pin) override;
virtual void PinTypeChanged(UEdGraphPin* Pin) override;
virtual FText GetTooltipText() const override;
virtual FText GetPinDisplayName(const UEdGraphPin* Pin) const override;
//~ End UEdGraphNode Interface.
//~ Begin UK2Node Interface.
virtual bool IsNodePure() const override { return false; }
virtual void PostReconstructNode() override;
virtual bool NodeCausesStructuralBlueprintChange() const override { return true; }
virtual void ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) override;
virtual ERedirectType DoPinsMatchForReconstruction(const UEdGraphPin* NewPin, int32 NewPinIndex, const UEdGraphPin* OldPin, int32 OldPinIndex) const override;
virtual bool IsConnectionDisallowed(const UEdGraphPin* MyPin, const UEdGraphPin* OtherPin, FString& OutReason) const override;
virtual void GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const override;
virtual FText GetMenuCategory() const override;
virtual int32 GetNodeRefreshPriority() const override { return EBaseNodeRefreshPriority::Low_UsesDependentWildcard; }
//~ End UK2Node Interface.
private:
/** Create all necessary pins. */
void CreateCorrectPins();
/** Synchronize the type of the given pin with the type its connected to, or reset it to a wildcard pin if there's no connection */
void SynchronizePinType(UEdGraphPin* Pin);
private:
/** The lua function prototype, which must be saved as a property **/
UPROPERTY()
FString LuaFunctionPrototype;
/** Tooltip text for this node. */
FText NodeTooltip;
};

View File

@@ -140,109 +140,154 @@ shell(UNREALENGINE, f"{UNREALENGINE}/Setup.{BAT}")
#
# Use UnrealBuildTool to generate a rough draft of Integration.code-workspace.
# We're not going to use it, but we set it aside as a reference that you can
# study to make changes to this script.
#
Path(f"{INTEGRATION}/Integration.code-workspace").unlink(missing_ok=True)
Path(f"{INTEGRATION}/Integration.code-workspace.old").unlink(missing_ok=True)
shell(INTEGRATION, f'{UNREALENGINE}/GenerateProjectFiles.{BAT} -projectfiles -project="{INTEGRATION}/Integration.uproject" -game')
Path(f"{INTEGRATION}/Integration.code-workspace").rename(f"{INTEGRATION}/Integration.code-workspace.old")
#
# Load the rough Integration.code-workspace into RAM, then delete the rough draft.
# Create a trivial makefile that calls into the unreal build system.
#
with open(f"{INTEGRATION}/Integration.code-workspace") as original:
WORKSPACE=json.load(original)
Path(f"{INTEGRATION}/Integration.code-workspace").unlink()
writefile(f"{INTEGRATION}/Makefile", f"""
# This makefile just invokes the unreal build system, then the luprex build system.
all:
\t{UNREALENGINE}/Engine/Build/BatchFiles/Linux/Build.sh IntegrationEditor Linux DebugGame {INTEGRATION}/Integration.uproject -waitmutex
\t(cd luprex ; make all)
clean:
\t{UNREALENGINE}/Engine/Build/BatchFiles/Linux/Build.sh IntegrationEditor Linux DebugGame {INTEGRATION}/Integration.uproject -waitmutex -clean
\t(cd luprex ; make clean)
""")
#
# Configure the correct build task as the default task.
# Build our own Integration.code-workspace from scratch.
#
for task in WORKSPACE["tasks"]["tasks"]:
if task["label"] == f"IntegrationEditor {OS} DebugGame Build":
task["group"] = { "kind": "build", "isDefault": True }
WORKSPACE={}
#
# Delete all build tasks that aren't relevant.
#
WORKSPACE["folders"] = []
WORKSPACE["folders"].append({ "name": "Integration", "path": "." })
WORKSPACE["folders"].append({ "name": "UE5", "path": UNREALENGINE })
def goodtask(task):
return task["label"].startswith(f"IntegrationEditor {OS} DebugGame")
WORKSPACE["settings"] = {}
WORKSPACE["settings"]["typescript.tsc.autoDetect"] = "off"
WORKSPACE["settings"]["lldb.dereferencePointers"] = False
WORKSPACE["settings"]["npm.autoDetect"] = "off"
WORKSPACE["tasks"]["tasks"] = [x for x in WORKSPACE["tasks"]["tasks"] if goodtask(x)]
#
# Add a build task for Luprex
#
LUPREXBUILDTASK={}
WORKSPACE["tasks"]["tasks"].append(LUPREXBUILDTASK)
LUPREXBUILDTASK["label"] = "Build Luprex"
LUPREXBUILDTASK["group"] = "build"
LUPREXBUILDTASK["command"] = "make"
LUPREXBUILDTASK["problemMatcher"] = "$msCompile"
LUPREXBUILDTASK["type"] = "shell"
LUPREXBUILDTASK["options"] = {}
LUPREXBUILDTASK["options"]["cwd"] = f"{INTEGRATION}/luprex"
#
# Add a presentation { clear=true } to all build tasks.
#
for task in WORKSPACE["tasks"]["tasks"]:
task["presentation"] = {}
task["presentation"]["clear"] = True
#
# Convert all launch configurations to lldb.
#
LLDBINIT=[
f'command script import {UNREALENGINE}/Engine/Extras/LLDBDataFormatters/UEDataFormatters_2ByteChars.py',
f'settings set target.inline-breakpoint-strategy always',
f'target stop-hook add --one-liner "p ::UngrabAllInputImpl()"',
]
for config in WORKSPACE["launch"]["configurations"]:
config["type"] = "lldb"
config["initCommands"] = LLDBINIT
config["args"] = [ f"{INTEGRATION}/Integration.uproject", f"-userdir=User/{USER}" ]
config.pop("visualizerFile", None)
config.pop("showDisplayString", None)
#
# Delete all but the relevant launch configuration.
#
def goodconf(config):
return config["name"] == "Launch IntegrationEditor (DebugGame)"
WORKSPACE["launch"]["configurations"] = [x for x in WORKSPACE["launch"]["configurations"] if goodconf(x)]
#
# Add some recommended extensions.
#
EXTENSIONS=set(WORKSPACE["extensions"]["recommendations"])
EXTENSIONS.add("ms-python.python")
EXTENSIONS.add("vadimcn.vscode-lldb")
WORKSPACE["extensions"]["recommendations"] = list(EXTENSIONS)
#
# Tell vscode not to try watching all the UnrealEngine source code for modifications.
# Attempting this overruns a Linux hardwired limit on file watches.
#
WORKSPACE["settings"]["files.watcherExclude"] = {
f'{UNREALENGINE}/Engine/**' : True,
f'{UNREALENGINE}/Samples/**' : True,
f'{UNREALENGINE}/Templates/**' : True
WORKSPACE["settings"]["files.watcherExclude"] = {}
WORKSPACE["settings"]["files.watcherExclude"]["/home/jyelon/UnrealEngine/Engine/**"] = True
WORKSPACE["settings"]["files.watcherExclude"]["/home/jyelon/UnrealEngine/Samples/**"] = True
WORKSPACE["settings"]["files.watcherExclude"]["/home/jyelon/UnrealEngine/Templates/**"] = True
WORKSPACE["settings"]["files.associations"] = {
"*.ipp": "cpp",
"locale": "cpp",
"random": "cpp",
"queue": "cpp",
"stack": "cpp",
"__locale": "cpp",
"functional": "cpp",
"sstream": "cpp",
"regex": "cpp",
"*.inc": "cpp",
"strstream": "cpp",
"string_view": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"scoped_allocator": "cpp",
"array": "cpp",
"hash_map": "cpp",
"hash_set": "cpp",
"bitset": "cpp",
"slist": "cpp",
"initializer_list": "cpp",
"valarray": "cpp",
"__hash_table": "cpp",
"__split_buffer": "cpp",
"__tree": "cpp",
"deque": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"span": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"ranges": "cpp",
"utility": "cpp",
"ratio": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"__bit_reference": "cpp",
"__node_handle": "cpp",
"atomic": "cpp",
"__memory": "cpp",
"limits": "cpp",
"optional": "cpp",
"variant": "cpp"
}
#
# Tell the LLDB plugin not to dereference pointers. This is dumb behavior,
# it dereferences "char *" and shows only the first character. Not dereferencing
# the pointer shows the whole string.
#
WORKSPACE["settings"]["lldb.dereferencePointers"] = False
WORKSPACE["extensions"] = {}
WORKSPACE["extensions"]["recommendations"] = [
"vadimcn.vscode-lldb",
"dfarley1.file-picker",
"ms-python.python",
"ms-vscode.cpptools",
"ms-dotnettools.csharp",
"ms-vscode.mono-debug"
]
WORKSPACE["tasks"] = {}
WORKSPACE["tasks"]["version"] = "2.0.0"
WORKSPACE["tasks"]["tasks"] = []
WORKSPACE["tasks"]["tasks"].append({
"label": "Make All",
"group": { "kind": "build", "isDefault": True },
"command": "make all",
"presentation" : { "clear" : True },
"problemMatcher": "$msCompile",
"type": "shell",
})
WORKSPACE["tasks"]["tasks"].append({
"label": "Make Clean",
"group": "build",
"command": "make clean",
"presentation" : { "clear" : True },
"problemMatcher": "$msCompile",
"type": "shell",
})
WORKSPACE["launch"] = {}
WORKSPACE["launch"]["version"] = "0.2.0"
WORKSPACE["launch"]["configurations"] = []
WORKSPACE["launch"]["configurations"].append({
"name": "Launch Editor with Luprex",
"request": "launch",
"program": f"{UNREALENGINE}/Engine/Binaries/Linux/UnrealEditor-Linux-DebugGame",
"preLaunchTask": "Make All",
"args": [
f"{INTEGRATION}/Integration.uproject",
"-userdir=User/jyelon"
],
"cwd": UNREALENGINE,
"type": "lldb",
"initCommands": [
f"command script import {UNREALENGINE}/Engine/Extras/LLDBDataFormatters/UEDataFormatters_2ByteChars.py",
"settings set target.inline-breakpoint-strategy always",
"target stop-hook add --one-liner \"p ::UngrabAllInputImpl()\""
]
})
#
# Write Integration.code-workspace.

View File

@@ -19,7 +19,11 @@ void push_simple_dynamic(lua_State *L, StreamBuffer *sb) {
break;
}
case SimpleDynamicTag::TOKEN: {
LuaToken token(sb->read_string_view());
std::string_view toktext = sb->read_string_view();
LuaToken token(toktext);
if (token.empty() && !toktext.empty()) {
throw StreamCorruption();
}
lua_pushlightuserdata(L, token.voidvalue());
break;
}
@@ -860,6 +864,7 @@ void World::invoke_lua_expr(int64_t actor_id, int64_t place_id, std::string_view
assert(stack_is_clear());
}
volatile int vx;
void World::invoke_lua_call(int64_t actor_id, int64_t place_id, std::string_view datapack) {
assert(stack_is_clear());
@@ -879,8 +884,12 @@ void World::invoke_lua_call(int64_t actor_id, int64_t place_id, std::string_view
if ((!sv::is_lua_id(classname)) || (!sv::is_lua_id(funcname))) {
return;
}
// TODO: Add support for the wildcard classname.
// TODO: Add check for permit_invoke(classname, funcname)
if (funcname == "printhi") {
vx = 0;
}
{
lua_State *L = state();
LuaVar lclass, lfunc;

View File

@@ -22,3 +22,7 @@ function engio.move(actor, place, action, xyz, facing)
dprint("engio.move ", action, " ", xyz[1], " ", xyz[2], " ", xyz[3])
tangible.animate(actor, nil, {action=action, xyz=xyz, facing=facing})
end
function engio.printhi(a1, a2, a3, a4, a5)
pprint("Hi there", a1, a2, a3, a4, a5)
end