diff --git a/Content/Widgets/WB_Console.uasset b/Content/Widgets/WB_Console.uasset index 9e08ec34..fb6b0e8a 100644 --- a/Content/Widgets/WB_Console.uasset +++ b/Content/Widgets/WB_Console.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:13b0fa7e4c14f8a0f2a9d891be892637a7da5ba255196c0a39339f196da1ca57 -size 169046 +oid sha256:01689b32f2395130506cfac6d4399a7cdccd9253918dc6ba168df39af72cc45e +size 176686 diff --git a/Source/Integration/LuaCall.cpp b/Source/Integration/LuaCall.cpp index 157f2822..7b1091bb 100644 --- a/Source/Integration/LuaCall.cpp +++ b/Source/Integration/LuaCall.cpp @@ -202,37 +202,44 @@ FString UlxLuaCallLibrary::AllFunctionsWithPrefix(const TCHAR *Prefix) // ///////////////////////////////////////////////////////////////// -void UlxLuaCallLibrary::ValidateLua( - ElxLuaSyntaxCheck &Result, FString &ErrorMessage, UObject *context, const FString &Code) +void UlxLuaCallLibrary::ValidateLuaExpr( + ElxLuaSyntaxCheck &Status, FString &ErrorMessage, UObject *context, const FString &Code) { if (Code.StartsWith(TEXT("/"))) { ErrorMessage = "SlashCommand"; - Result = ElxLuaSyntaxCheck::SlashCommand; + Status = ElxLuaSyntaxCheck::SlashCommand; return; } if (Code.TrimStart().IsEmpty()) { ErrorMessage = ""; - Result = ElxLuaSyntaxCheck::Whitespace; + Status = ElxLuaSyntaxCheck::Whitespace; return; } ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context); - ErrorMessage = mode->LuaValidate(Code); + ErrorMessage = mode->ValidateLuaExpr(Code); if (ErrorMessage.IsEmpty()) { - Result = ElxLuaSyntaxCheck::ValidLua; + Status = ElxLuaSyntaxCheck::ValidLua; } else if (ErrorMessage.Contains(TEXT(""))) { - Result = ElxLuaSyntaxCheck::TruncatedLua; + Status = ElxLuaSyntaxCheck::TruncatedLua; } else { - Result = ElxLuaSyntaxCheck::InvalidLua; + Status = ElxLuaSyntaxCheck::InvalidLua; } } +void UlxLuaCallLibrary::InvokeLuaExpr(UObject *context, const FString &Code) +{ + ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context); + mode->InvokeLuaExpr(Code); +} + + void UlxLuaCallLibrary::LuaCallBegin(UObject *context, const FString &cname, const FString &fname) { ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context); diff --git a/Source/Integration/LuaCall.h b/Source/Integration/LuaCall.h index 276d5756..804f773c 100644 --- a/Source/Integration/LuaCall.h +++ b/Source/Integration/LuaCall.h @@ -139,8 +139,11 @@ public: // returns an error message. If the code is error-free, the // error message is the empty string. // - UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", ExpandEnumAsExecs="Result"), Category = "Luprex|Call Lua Function") - static void ValidateLua(ElxLuaSyntaxCheck &Result, FString &ErrorMessage, UObject *context, const FString &Code); + UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function") + static void ValidateLuaExpr(ElxLuaSyntaxCheck &Status, FString &ErrorMessage, UObject *context, const FString &Code); + + UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function") + static void InvokeLuaExpr(UObject *context, const FString &Code); UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function") static void LuaCallBegin(UObject *context, const FString &ClassName, const FString &FunctionName); diff --git a/Source/Integration/LuprexGameModeBase.cpp b/Source/Integration/LuprexGameModeBase.cpp index fde43b89..a3be1077 100644 --- a/Source/Integration/LuprexGameModeBase.cpp +++ b/Source/Integration/LuprexGameModeBase.cpp @@ -223,17 +223,26 @@ UlxLuaValues *ALuprexGameModeBase::LuaCallEnd(AccessKind kind, AActor *place) { } } -FString ALuprexGameModeBase::LuaValidate(const FString &Code) +FString ALuprexGameModeBase::ValidateLuaExpr(const FString &Code) { FTCHARToUTF8 UCode(*Code); FlxLockedWrapper w(LockableWrapper); uint32_t retpklen; const char *retpk; - w->play_access(w.Get(), AccessKind::VALIDATE_LUA, 0, UCode.Length(), UCode.Get(), &retpklen, &retpk); + w->play_access(w.Get(), AccessKind::VALIDATE_LUA_EXPR, 0, UCode.Length(), UCode.Get(), &retpklen, &retpk); FString Result(retpklen, (const UTF8CHAR*)retpk); return Result; } +void ALuprexGameModeBase::InvokeLuaExpr(const FString &Code) +{ + FTCHARToUTF8 UCode(*Code); + FlxLockedWrapper w(LockableWrapper); + uint32_t retpklen; + const char *retpk; + w->play_access(w.Get(), AccessKind::INVOKE_LUA_EXPR, 0, UCode.Length(), UCode.Get(), &retpklen, &retpk); +} + void ALuprexGameModeBase::OnWorldPreActorTick(UWorld* InWorld, ELevelTick InLevelTick, float deltaseconds) { if(Playing && TickEnabled && (GetWorld() == InWorld) && (InLevelTick == LEVELTICK_All)) diff --git a/Source/Integration/LuprexGameModeBase.h b/Source/Integration/LuprexGameModeBase.h index 8379549c..bc84a07b 100644 --- a/Source/Integration/LuprexGameModeBase.h +++ b/Source/Integration/LuprexGameModeBase.h @@ -116,7 +116,11 @@ public: // an otherwise empty lua interpreter, so this is purely // a syntax check. // - FString LuaValidate(const FString &Code); + FString ValidateLuaExpr(const FString &Code); + + // Invoke some lua code. + // + void InvokeLuaExpr(const FString &Code); // Get the Asset Lookup table. const UlxAssetLookup *GetAssetLookup() const { return AssetLookup; } diff --git a/luprex/cpp/core/enginewrapper.hpp b/luprex/cpp/core/enginewrapper.hpp index 97ef68ff..dcbce268 100644 --- a/luprex/cpp/core/enginewrapper.hpp +++ b/luprex/cpp/core/enginewrapper.hpp @@ -32,7 +32,7 @@ enum class AccessKind { INVOKE_LUA_SOURCE, PROBE_LUA_CALL, CONNECT_TO_SERVER, - VALIDATE_LUA, + VALIDATE_LUA_EXPR, }; class DrivenEngine; diff --git a/luprex/cpp/core/lpxclient.cpp b/luprex/cpp/core/lpxclient.cpp index b2c79265..eb538e40 100644 --- a/luprex/cpp/core/lpxclient.cpp +++ b/luprex/cpp/core/lpxclient.cpp @@ -263,7 +263,7 @@ public: set_initial_state_connect(util::ss("nocert:", datapk, ":8085")); break; } - case AccessKind::VALIDATE_LUA: { + case AccessKind::VALIDATE_LUA_EXPR: { LuaVar closure; LuaExtStack LS(lua_syntax_checker_, closure); eng::string errmsg = LS.load(closure, datapk, "stdin"); diff --git a/luprex/cpp/core/lpxserver.cpp b/luprex/cpp/core/lpxserver.cpp index 8103c5d9..b5f8f4f1 100644 --- a/luprex/cpp/core/lpxserver.cpp +++ b/luprex/cpp/core/lpxserver.cpp @@ -187,7 +187,7 @@ public: master_->rollback(); break; } - case AccessKind::VALIDATE_LUA: { + case AccessKind::VALIDATE_LUA_EXPR: { LuaVar closure; LuaExtStack LS(lua_syntax_checker_, closure); eng::string errmsg = LS.load(closure, datapk, "stdin"); diff --git a/luprex/cpp/core/luastack.cpp b/luprex/cpp/core/luastack.cpp index 75c4d9bf..fc8b7331 100644 --- a/luprex/cpp/core/luastack.cpp +++ b/luprex/cpp/core/luastack.cpp @@ -325,6 +325,14 @@ bool LuaCoreStack::next(LuaSlot tab, LuaSlot key, LuaSlot value) const { eng::string LuaCoreStack::load(LuaSlot result, std::string_view code, std::string_view context) { + // We interpret "=x" as syntactic sugar for "return x" + eng::string expanded; + if (sv::has_prefix(code, "=")) + { + expanded = eng::string("return ") + eng::string(code.substr(1)); + code = expanded; + } + eng::string fullcontext = eng::string("=") + eng::string(context); luaL_loadbuffer(L_, code.data(), code.size(), fullcontext.c_str()); int type = lua_type(L_, -1); diff --git a/luprex/cpp/core/world-core.cpp b/luprex/cpp/core/world-core.cpp index ac6e106e..eb2c0d5b 100644 --- a/luprex/cpp/core/world-core.cpp +++ b/luprex/cpp/core/world-core.cpp @@ -874,9 +874,8 @@ void World::invoke_lua_expr(int64_t actor_id, int64_t place_id, std::string_view LuaExtStack LS(L, func); // create the compiled closure. - int status = luaL_loadbuffer(L, datapack.data(), datapack.size(), "=invoke"); - lua_replace(L, func.index()); - if (status != LUA_OK) { + eng::string error = LS.load(func, datapack, "=invoke"); + if (!error.empty()) { // The closure is actually an error message. Do nothing. // This should normally not happen: LuaConsole should filter // out syntax errors.