Console overhaul, part 2. New console is mostly working.

This commit is contained in:
2025-12-09 15:51:35 -05:00
parent 2d1def8dc6
commit a0703effc3
10 changed files with 51 additions and 21 deletions

Binary file not shown.

View File

@@ -202,37 +202,44 @@ FString UlxLuaCallLibrary::AllFunctionsWithPrefix(const TCHAR *Prefix)
// //
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
void UlxLuaCallLibrary::ValidateLua( void UlxLuaCallLibrary::ValidateLuaExpr(
ElxLuaSyntaxCheck &Result, FString &ErrorMessage, UObject *context, const FString &Code) ElxLuaSyntaxCheck &Status, FString &ErrorMessage, UObject *context, const FString &Code)
{ {
if (Code.StartsWith(TEXT("/"))) if (Code.StartsWith(TEXT("/")))
{ {
ErrorMessage = "SlashCommand"; ErrorMessage = "SlashCommand";
Result = ElxLuaSyntaxCheck::SlashCommand; Status = ElxLuaSyntaxCheck::SlashCommand;
return; return;
} }
if (Code.TrimStart().IsEmpty()) if (Code.TrimStart().IsEmpty())
{ {
ErrorMessage = ""; ErrorMessage = "";
Result = ElxLuaSyntaxCheck::Whitespace; Status = ElxLuaSyntaxCheck::Whitespace;
return; return;
} }
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context); ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
ErrorMessage = mode->LuaValidate(Code); ErrorMessage = mode->ValidateLuaExpr(Code);
if (ErrorMessage.IsEmpty()) if (ErrorMessage.IsEmpty())
{ {
Result = ElxLuaSyntaxCheck::ValidLua; Status = ElxLuaSyntaxCheck::ValidLua;
} }
else if (ErrorMessage.Contains(TEXT("<eof>"))) else if (ErrorMessage.Contains(TEXT("<eof>")))
{ {
Result = ElxLuaSyntaxCheck::TruncatedLua; Status = ElxLuaSyntaxCheck::TruncatedLua;
} }
else 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) void UlxLuaCallLibrary::LuaCallBegin(UObject *context, const FString &cname, const FString &fname)
{ {
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context); ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);

View File

@@ -139,8 +139,11 @@ public:
// returns an error message. If the code is error-free, the // returns an error message. If the code is error-free, the
// error message is the empty string. // error message is the empty string.
// //
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", ExpandEnumAsExecs="Result"), Category = "Luprex|Call Lua Function") UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Call Lua Function")
static void ValidateLua(ElxLuaSyntaxCheck &Result, FString &ErrorMessage, UObject *context, const FString &Code); 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") UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function")
static void LuaCallBegin(UObject *context, const FString &ClassName, const FString &FunctionName); static void LuaCallBegin(UObject *context, const FString &ClassName, const FString &FunctionName);

View File

@@ -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); FTCHARToUTF8 UCode(*Code);
FlxLockedWrapper w(LockableWrapper); FlxLockedWrapper w(LockableWrapper);
uint32_t retpklen; uint32_t retpklen;
const char *retpk; 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); FString Result(retpklen, (const UTF8CHAR*)retpk);
return Result; 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) void ALuprexGameModeBase::OnWorldPreActorTick(UWorld* InWorld, ELevelTick InLevelTick, float deltaseconds)
{ {
if(Playing && TickEnabled && (GetWorld() == InWorld) && (InLevelTick == LEVELTICK_All)) if(Playing && TickEnabled && (GetWorld() == InWorld) && (InLevelTick == LEVELTICK_All))

View File

@@ -116,7 +116,11 @@ public:
// an otherwise empty lua interpreter, so this is purely // an otherwise empty lua interpreter, so this is purely
// a syntax check. // 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. // Get the Asset Lookup table.
const UlxAssetLookup *GetAssetLookup() const { return AssetLookup; } const UlxAssetLookup *GetAssetLookup() const { return AssetLookup; }

View File

@@ -32,7 +32,7 @@ enum class AccessKind {
INVOKE_LUA_SOURCE, INVOKE_LUA_SOURCE,
PROBE_LUA_CALL, PROBE_LUA_CALL,
CONNECT_TO_SERVER, CONNECT_TO_SERVER,
VALIDATE_LUA, VALIDATE_LUA_EXPR,
}; };
class DrivenEngine; class DrivenEngine;

View File

@@ -263,7 +263,7 @@ public:
set_initial_state_connect(util::ss("nocert:", datapk, ":8085")); set_initial_state_connect(util::ss("nocert:", datapk, ":8085"));
break; break;
} }
case AccessKind::VALIDATE_LUA: { case AccessKind::VALIDATE_LUA_EXPR: {
LuaVar closure; LuaVar closure;
LuaExtStack LS(lua_syntax_checker_, closure); LuaExtStack LS(lua_syntax_checker_, closure);
eng::string errmsg = LS.load(closure, datapk, "stdin"); eng::string errmsg = LS.load(closure, datapk, "stdin");

View File

@@ -187,7 +187,7 @@ public:
master_->rollback(); master_->rollback();
break; break;
} }
case AccessKind::VALIDATE_LUA: { case AccessKind::VALIDATE_LUA_EXPR: {
LuaVar closure; LuaVar closure;
LuaExtStack LS(lua_syntax_checker_, closure); LuaExtStack LS(lua_syntax_checker_, closure);
eng::string errmsg = LS.load(closure, datapk, "stdin"); eng::string errmsg = LS.load(closure, datapk, "stdin");

View File

@@ -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) 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); eng::string fullcontext = eng::string("=") + eng::string(context);
luaL_loadbuffer(L_, code.data(), code.size(), fullcontext.c_str()); luaL_loadbuffer(L_, code.data(), code.size(), fullcontext.c_str());
int type = lua_type(L_, -1); int type = lua_type(L_, -1);

View File

@@ -874,9 +874,8 @@ void World::invoke_lua_expr(int64_t actor_id, int64_t place_id, std::string_view
LuaExtStack LS(L, func); LuaExtStack LS(L, func);
// create the compiled closure. // create the compiled closure.
int status = luaL_loadbuffer(L, datapack.data(), datapack.size(), "=invoke"); eng::string error = LS.load(func, datapack, "=invoke");
lua_replace(L, func.index()); if (!error.empty()) {
if (status != LUA_OK) {
// The closure is actually an error message. Do nothing. // The closure is actually an error message. Do nothing.
// This should normally not happen: LuaConsole should filter // This should normally not happen: LuaConsole should filter
// out syntax errors. // out syntax errors.