Lua Console Overhaul in progress
This commit is contained in:
BIN
Content/Luprex/lxGameMode.uasset
LFS
BIN
Content/Luprex/lxGameMode.uasset
LFS
Binary file not shown.
Binary file not shown.
@@ -5,12 +5,12 @@
|
||||
//
|
||||
// ConsoleOutput
|
||||
//
|
||||
// Storing the text that goes in the unreal console.
|
||||
// Storing the text that goes in the command console.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void FlxConsoleOutput::Truncate() {
|
||||
void UlxConsoleOutput::Truncate() {
|
||||
int lines = 50;
|
||||
int csize = Content.Len();
|
||||
int total = 0;
|
||||
@@ -25,7 +25,7 @@ void FlxConsoleOutput::Truncate() {
|
||||
}
|
||||
}
|
||||
|
||||
bool FlxConsoleOutput::MaybeAppendNewline() {
|
||||
bool UlxConsoleOutput::MaybeAppendNewline() {
|
||||
int csize = Content.Len();
|
||||
if ((csize > 0) && (Content[csize - 1] != '\n')) {
|
||||
Content += TEXT("\n");
|
||||
@@ -36,7 +36,7 @@ bool FlxConsoleOutput::MaybeAppendNewline() {
|
||||
}
|
||||
}
|
||||
|
||||
bool FlxConsoleOutput::MaybeAppendText(const FString& text) {
|
||||
bool UlxConsoleOutput::MaybeAppendText(const FString& text) {
|
||||
if (!text.IsEmpty()) {
|
||||
Content += text;
|
||||
return true;
|
||||
@@ -46,7 +46,7 @@ bool FlxConsoleOutput::MaybeAppendText(const FString& text) {
|
||||
}
|
||||
}
|
||||
|
||||
void FlxConsoleOutput::Append(const FString& text) {
|
||||
void UlxConsoleOutput::Append(const FString& text) {
|
||||
bool modified = MaybeAppendText(text);
|
||||
if (modified) {
|
||||
Dirty = true;
|
||||
@@ -54,7 +54,7 @@ void FlxConsoleOutput::Append(const FString& text) {
|
||||
}
|
||||
}
|
||||
|
||||
void FlxConsoleOutput::AppendLine(const FString& text) {
|
||||
void UlxConsoleOutput::AppendLine(const FString& text) {
|
||||
bool modified = MaybeAppendNewline();
|
||||
modified |= MaybeAppendText(text);
|
||||
modified |= MaybeAppendNewline();
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
#include "Containers/UnrealString.h"
|
||||
|
||||
#include "ConsoleOutput.generated.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ConsoleOutput
|
||||
@@ -19,11 +22,16 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
class FlxConsoleOutput {
|
||||
UCLASS(BlueprintType)
|
||||
class UlxConsoleOutput : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
private:
|
||||
FString Content;
|
||||
bool Dirty;
|
||||
|
||||
private:
|
||||
// Truncate the console to a reasonable number of
|
||||
// lines. The length is hardwired.
|
||||
void Truncate();
|
||||
@@ -36,18 +44,23 @@ private:
|
||||
|
||||
public:
|
||||
// Append a line of text to the console.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void Append(const FString& text);
|
||||
|
||||
// Append a line of text to the console on a line by itself.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void AppendLine(const FString& text);
|
||||
|
||||
// Get the console text as a string.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
const FString& Get() const { return Content; }
|
||||
|
||||
// Return if the dirty flag is set.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
bool IsDirty() const { return Dirty; }
|
||||
|
||||
// Clear the dirty flag.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void ClearDirty() { Dirty = false; }
|
||||
};
|
||||
|
||||
|
||||
@@ -202,6 +202,37 @@ FString UlxLuaCallLibrary::AllFunctionsWithPrefix(const TCHAR *Prefix)
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void UlxLuaCallLibrary::ValidateLua(
|
||||
ElxLuaSyntaxCheck &Result, FString &ErrorMessage, UObject *context, const FString &Code)
|
||||
{
|
||||
if (Code.StartsWith(TEXT("/")))
|
||||
{
|
||||
ErrorMessage = "SlashCommand";
|
||||
Result = ElxLuaSyntaxCheck::SlashCommand;
|
||||
return;
|
||||
}
|
||||
if (Code.TrimStart().IsEmpty())
|
||||
{
|
||||
ErrorMessage = "";
|
||||
Result = ElxLuaSyntaxCheck::Whitespace;
|
||||
return;
|
||||
}
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
ErrorMessage = mode->LuaValidate(Code);
|
||||
if (ErrorMessage.IsEmpty())
|
||||
{
|
||||
Result = ElxLuaSyntaxCheck::ValidLua;
|
||||
}
|
||||
else if (ErrorMessage.Contains(TEXT("<eof>")))
|
||||
{
|
||||
Result = ElxLuaSyntaxCheck::TruncatedLua;
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = ElxLuaSyntaxCheck::InvalidLua;
|
||||
}
|
||||
}
|
||||
|
||||
void UlxLuaCallLibrary::LuaCallBegin(UObject *context, const FString &cname, const FString &fname)
|
||||
{
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
@@ -211,7 +242,6 @@ void UlxLuaCallLibrary::LuaCallBegin(UObject *context, const FString &cname, con
|
||||
sb.write_string(fname);
|
||||
}
|
||||
|
||||
|
||||
void UlxLuaCallLibrary::LuaCallInvoke(UObject *context, AActor *place)
|
||||
{
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
|
||||
@@ -9,6 +9,23 @@
|
||||
|
||||
class UlxLuaValues;
|
||||
|
||||
// Classify lua code syntactically:
|
||||
//
|
||||
// SlashCommand: starts with a slash, therefore, not lua
|
||||
// WhitespaceOnly: the input only contains whitespace
|
||||
// ValidSyntax: the input is valid lua code
|
||||
// TruncatedCode: the input is truncated
|
||||
// InvalidSyntax: invalid lua
|
||||
//
|
||||
UENUM(BlueprintType)
|
||||
enum class ElxLuaSyntaxCheck : uint8 {
|
||||
SlashCommand,
|
||||
Whitespace,
|
||||
ValidLua,
|
||||
TruncatedLua,
|
||||
InvalidLua,
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// These are the types that can actually be packed into
|
||||
@@ -118,9 +135,12 @@ public:
|
||||
static FString AllKnownReturnValueTypes() { return AllFunctionsWithPrefix(TEXT("LuaCallReturnValue_")); }
|
||||
|
||||
public:
|
||||
// Syntactically validate lua code. Parses the code and
|
||||
// returns an error message. If the code is error-free, the
|
||||
// error message is the empty string.
|
||||
//
|
||||
// Functions that do miscellaneous things.
|
||||
//
|
||||
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", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function")
|
||||
static void LuaCallBegin(UObject *context, const FString &ClassName, const FString &FunctionName);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "LuprexGameModeBase.h"
|
||||
#include "lpx-drvutil.hpp"
|
||||
#include "lpx-paths.hpp"
|
||||
#include "ConsoleOutput.h"
|
||||
#include "Tangible.h"
|
||||
#include "TangibleManager.h"
|
||||
#include "LuaCall.h"
|
||||
@@ -124,18 +123,15 @@ void ALuprexGameModeBase::ResetToInitialState()
|
||||
NextRotateCube = 1.0;
|
||||
}
|
||||
|
||||
|
||||
void ALuprexGameModeBase::UpdateConsoleOutput() {
|
||||
// Copy Luprex Stdout into the console.
|
||||
FlxLockedWrapper lockedwrap(LockableWrapper);
|
||||
if (Playing) {
|
||||
ConsoleOutput.Append(lockedwrap.FetchStdout());
|
||||
}
|
||||
|
||||
// If the Console text has changed, update the widget.
|
||||
if (ConsoleOutput.IsDirty()) {
|
||||
ConsoleSetOutput(ConsoleOutput.Get());
|
||||
ConsoleOutput.ClearDirty();
|
||||
FString Text = lockedwrap.FetchStdout();
|
||||
if (!Text.IsEmpty())
|
||||
{
|
||||
ConsoleAddOutput(Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,32 +223,15 @@ UlxLuaValues *ALuprexGameModeBase::LuaCallEnd(AccessKind kind, AActor *place) {
|
||||
}
|
||||
}
|
||||
|
||||
void ALuprexGameModeBase::ExecuteDebuggingCommand(FlxLockedWrapper &w, const FString &fs) {
|
||||
// Nothing here right now.
|
||||
}
|
||||
|
||||
void ALuprexGameModeBase::ConsoleSendInput(const FString& fs)
|
||||
FString ALuprexGameModeBase::LuaValidate(const FString &Code)
|
||||
{
|
||||
if (fs.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
FTCHARToUTF8 UCode(*Code);
|
||||
FlxLockedWrapper w(LockableWrapper);
|
||||
if (w->engine != nullptr)
|
||||
{
|
||||
ConsoleOutput.AppendLine(FString("> ") + fs);
|
||||
// This is a bad way to do this. The problem is that if some
|
||||
// lua code contains '\\', we'll catch it instead of passing it
|
||||
// through. There's no simple solution, though.
|
||||
if (fs[0] == '\\') {
|
||||
ExecuteDebuggingCommand(w, fs);
|
||||
} else {
|
||||
FTCHARToUTF8 utf8fs(fs);
|
||||
std::string ufs(utf8fs.Get(), utf8fs.Length());
|
||||
ufs = ufs + "\n";
|
||||
w->play_recv_incoming(w.Get(), 0, ufs.size(), ufs.c_str());
|
||||
}
|
||||
}
|
||||
uint32_t retpklen;
|
||||
const char *retpk;
|
||||
w->play_access(w.Get(), AccessKind::VALIDATE_LUA, 0, UCode.Length(), UCode.Get(), &retpklen, &retpk);
|
||||
FString Result(retpklen, (const UTF8CHAR*)retpk);
|
||||
return Result;
|
||||
}
|
||||
|
||||
void ALuprexGameModeBase::OnWorldPreActorTick(UWorld* InWorld, ELevelTick InLevelTick, float deltaseconds)
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/GameModeBase.h"
|
||||
#include "lpx-enginewrapper.hpp"
|
||||
#include "ConsoleOutput.h"
|
||||
#include "StringDecoder.h"
|
||||
#include "TangibleManager.h"
|
||||
#include "AssetLookup.h"
|
||||
@@ -59,11 +58,7 @@ public:
|
||||
|
||||
// Set the entire contents of the console output box.
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "Luprex|Miscellaneous")
|
||||
void ConsoleSetOutput(const FString& text);
|
||||
|
||||
// This is called by the GUI whenever the user hits enter.
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Miscellaneous")
|
||||
void ConsoleSendInput(const FString& text);
|
||||
void ConsoleAddOutput(const FString& text);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Miscellaneous")
|
||||
int64 GetPlayerId();
|
||||
@@ -94,7 +89,11 @@ public:
|
||||
void LookAtChanged();
|
||||
|
||||
|
||||
// Assemble a lua call. To call into lua:
|
||||
// Assemble a lua call. Note that this is the lowest-level interface.
|
||||
// These functions are wrapped by the functions in UlxLuaCallLibrary,
|
||||
// and those in turn are wrapped by the K2Node "LuaInvoke" and "LuaProbe".
|
||||
//
|
||||
// At this level, the process of calling Lua is:
|
||||
//
|
||||
// * Use LuaCallBegin
|
||||
// * Get the lua call buffer:
|
||||
@@ -102,8 +101,7 @@ public:
|
||||
// - add a function name
|
||||
// - add function parameters
|
||||
// * Use LuaCallEnd.
|
||||
// * Get the lua call result.
|
||||
// - parse out any return values
|
||||
// * Process any return values in the UlxLuaValues array.
|
||||
//
|
||||
FlxStreamBuffer &LuaCallBegin() { LuaCallBuffer.clear(); return LuaCallBuffer; }
|
||||
FlxStreamBuffer &LuaCallGetBuffer() { return LuaCallBuffer; }
|
||||
@@ -112,8 +110,13 @@ public:
|
||||
UlxLuaValues *LuaCallEnd(AccessKind kind, AActor *place);
|
||||
void LuaCallClear() { LuaCallBuffer.clear(); }
|
||||
|
||||
// Execute a debugging command, typed on the GUI.
|
||||
void ExecuteDebuggingCommand(FlxLockedWrapper &w, const FString &fs);
|
||||
// Validate some lua code. Returns an error message.
|
||||
// If the lua is well-formed, the error message is the
|
||||
// empty string. The syntax of the code is checked using
|
||||
// an otherwise empty lua interpreter, so this is purely
|
||||
// a syntax check.
|
||||
//
|
||||
FString LuaValidate(const FString &Code);
|
||||
|
||||
// Get the Asset Lookup table.
|
||||
const UlxAssetLookup *GetAssetLookup() const { return AssetLookup; }
|
||||
@@ -162,9 +165,6 @@ public:
|
||||
UPROPERTY(EditAnywhere, Category="Debugging Tools")
|
||||
ElxLogVerbosity BreakToDebuggerLogVerbosity;
|
||||
|
||||
// This stores the entire text currently visible in the console.
|
||||
FlxConsoleOutput ConsoleOutput;
|
||||
|
||||
// The Luprex EngineWrapper, with a Mutex to protect it.
|
||||
// To access it, construct a FlxLockedWrapper.
|
||||
FlxLockableWrapper LockableWrapper;
|
||||
|
||||
@@ -265,7 +265,7 @@ public:
|
||||
}
|
||||
case AccessKind::VALIDATE_LUA: {
|
||||
LuaVar closure;
|
||||
LuaDefStack LS(lua_syntax_checker_, closure);
|
||||
LuaExtStack LS(lua_syntax_checker_, closure);
|
||||
eng::string errmsg = LS.load(closure, datapk, "stdin");
|
||||
retpk->write_bytes(errmsg);
|
||||
break;
|
||||
|
||||
@@ -189,7 +189,7 @@ public:
|
||||
}
|
||||
case AccessKind::VALIDATE_LUA: {
|
||||
LuaVar closure;
|
||||
LuaDefStack LS(lua_syntax_checker_, closure);
|
||||
LuaExtStack LS(lua_syntax_checker_, closure);
|
||||
eng::string errmsg = LS.load(closure, datapk, "stdin");
|
||||
retpk->write_bytes(errmsg);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user