Lots of work on several unrelated things.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
|
||||
#include "BlueprintErrors.h"
|
||||
#include "StringDecoder.h"
|
||||
#include "Internationalization/TextFormatter.h"
|
||||
#include "Kismet/KismetSystemLibrary.h"
|
||||
#include "Kismet2/KismetDebugUtilities.h"
|
||||
@@ -209,6 +210,15 @@ FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataTransform(const FTra
|
||||
return Result;
|
||||
}
|
||||
|
||||
FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataLuaValues(const UlxLuaValues *Value, const FString &Name)
|
||||
{
|
||||
FFormatArgumentData Result;
|
||||
Result.ArgumentValueType = EFormatArgumentType::Text;
|
||||
Result.ArgumentName = Name;
|
||||
Result.ArgumentValue = FText::FromString(Value->DebugString());
|
||||
return Result;
|
||||
}
|
||||
|
||||
FFormatArgumentData UlxBlueprintErrorLibrary::FormatArgumentDataBlank(const FString &Name)
|
||||
{
|
||||
FFormatArgumentData Result;
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include "BlueprintErrors.generated.h"
|
||||
|
||||
class UlxLuaValues;
|
||||
|
||||
/*
|
||||
* enum class ElxLogVerbosity, below, contains all the same error severity levels
|
||||
* as ELogVerbosity, but in a form that the blueprint editor can manipulate.
|
||||
@@ -213,6 +215,9 @@ public:
|
||||
|
||||
UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility")
|
||||
static FFormatArgumentData FormatArgumentDataTransform(const FTransform &Value, const FString &Name);
|
||||
|
||||
UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility")
|
||||
static FFormatArgumentData FormatArgumentDataLuaValues(const UlxLuaValues *Value, const FString &Name);
|
||||
};
|
||||
|
||||
/* Debug Blueprint Errors output device.
|
||||
|
||||
65
Source/Integration/ConsoleOutput.cpp
Normal file
65
Source/Integration/ConsoleOutput.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#include "ConsoleOutput.h"
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ConsoleOutput
|
||||
//
|
||||
// Storing the text that goes in the unreal console.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void FlxConsoleOutput::Truncate() {
|
||||
int lines = 50;
|
||||
int csize = Content.Len();
|
||||
int total = 0;
|
||||
for (int i = csize - 1; i >= 0; i--) {
|
||||
if (Content[i] == '\n') {
|
||||
total += 1;
|
||||
if (total == lines) {
|
||||
Content = Content.RightChop(i + 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FlxConsoleOutput::MaybeAppendNewline() {
|
||||
int csize = Content.Len();
|
||||
if ((csize > 0) && (Content[csize - 1] != '\n')) {
|
||||
Content += TEXT("\n");
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool FlxConsoleOutput::MaybeAppendText(const FString& text) {
|
||||
if (!text.IsEmpty()) {
|
||||
Content += text;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void FlxConsoleOutput::Append(const FString& text) {
|
||||
bool modified = MaybeAppendText(text);
|
||||
if (modified) {
|
||||
Dirty = true;
|
||||
Truncate();
|
||||
}
|
||||
}
|
||||
|
||||
void FlxConsoleOutput::AppendLine(const FString& text) {
|
||||
bool modified = MaybeAppendNewline();
|
||||
modified |= MaybeAppendText(text);
|
||||
modified |= MaybeAppendNewline();
|
||||
if (modified) {
|
||||
Dirty = true;
|
||||
Truncate();
|
||||
}
|
||||
}
|
||||
52
Source/Integration/ConsoleOutput.h
Normal file
52
Source/Integration/ConsoleOutput.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ConsoleOutput
|
||||
//
|
||||
// This class stores the text that's in the unreal console.
|
||||
// It stores it as one great big string, which contains
|
||||
// newlines to denote line breaks.
|
||||
//
|
||||
// This class also contains a 'dirty' bit. Each time somebody
|
||||
// appends a line of text to the console, the dirty bit is
|
||||
// automatically set. The bit can be checked using 'IsDirty'
|
||||
// and cleared using 'ClearDirty'. This makes it so that
|
||||
// you don't have to update the unreal widget unless the
|
||||
// text has actually changed.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
class FlxConsoleOutput {
|
||||
private:
|
||||
FString Content;
|
||||
bool Dirty;
|
||||
|
||||
// Truncate the console to a reasonable number of
|
||||
// lines. The length is hardwired.
|
||||
void Truncate();
|
||||
|
||||
// Add a newline if there isn't one. Returns true if it changed anything.
|
||||
bool MaybeAppendNewline();
|
||||
|
||||
// Append text. Returns true if it changed anything.
|
||||
bool MaybeAppendText(const FString& text);
|
||||
|
||||
public:
|
||||
// Append a line of text to the console.
|
||||
void Append(const FString& text);
|
||||
|
||||
// Append a line of text to the console on a line by itself.
|
||||
void AppendLine(const FString& text);
|
||||
|
||||
// Get the console text as a string.
|
||||
const FString& Get() const { return Content; }
|
||||
|
||||
// Return if the dirty flag is set.
|
||||
bool IsDirty() const { return Dirty; }
|
||||
|
||||
// Clear the dirty flag.
|
||||
void ClearDirty() { Dirty = false; }
|
||||
};
|
||||
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
#include "DebugPrint.h"
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
using DPrintCallback = DebugPrintControl::DPrintCallback;
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DPrintState
|
||||
//
|
||||
// The global state of the DPrint routine. There is only
|
||||
// ever one of these, and it is owned by DPrintAccess below.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
struct DPrintState {
|
||||
// True if buffering is enabled.
|
||||
bool Collect;
|
||||
|
||||
// The array of buffered messages.
|
||||
TArray<FString> Messages;
|
||||
|
||||
// The array of callback functions.
|
||||
TArray<DPrintCallback> Callbacks;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DPrintAccess
|
||||
//
|
||||
// This class grants you safe access to the global state
|
||||
// of the DPrint routine. Constructing an object of
|
||||
// class DPrintAccess will lock the global mutex and make
|
||||
// sure that the DPrintState is initialized. Then it will
|
||||
// give you unrestricted access to the DPrintState through
|
||||
// operator right arrow.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
class DPrintAccess {
|
||||
private:
|
||||
// The Mutex that protects the global state.
|
||||
static FCriticalSection Mutex;
|
||||
|
||||
// The Global State. A pointer, to avoid static init issues.
|
||||
static DPrintState* State;
|
||||
|
||||
public:
|
||||
// Constructor. Locks mutex and initializes state if necessary.
|
||||
DPrintAccess() {
|
||||
Mutex.Lock();
|
||||
if (State == nullptr) {
|
||||
State = new DPrintState;
|
||||
State->Collect = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Destructor. Releases mutex.
|
||||
~DPrintAccess() {
|
||||
Mutex.Unlock();
|
||||
}
|
||||
|
||||
// Access the DPrintState.
|
||||
DPrintState* operator ->() {
|
||||
return State;
|
||||
}
|
||||
};
|
||||
|
||||
FCriticalSection DPrintAccess::Mutex;
|
||||
DPrintState* DPrintAccess::State;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Namespace DebugPrint.
|
||||
//
|
||||
// This contains all the various versions of the DPrint routine.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
namespace DebugPrint {
|
||||
|
||||
// DPrint. Invoke all the callbacks, and store the message.
|
||||
void DPrint(const FString& fs) {
|
||||
DPrintAccess state;
|
||||
for (DPrintCallback cb : state->Callbacks) {
|
||||
cb(fs);
|
||||
}
|
||||
if (state->Collect) {
|
||||
state->Messages.Emplace(fs);
|
||||
}
|
||||
}
|
||||
|
||||
// Alternative interface to the dispatcher.
|
||||
void DPrint(const char* msg) {
|
||||
DPrint(FString(msg));
|
||||
}
|
||||
|
||||
// Alternative interface to the dispatcher.
|
||||
void DPrint(const char* msg, size_t len) {
|
||||
DPrint(FString(len, (const UTF8CHAR*)msg));
|
||||
}
|
||||
|
||||
} // namespace DebugPrint
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Namespace DebugPrintControl.
|
||||
//
|
||||
// Configuration and control for the DPrint routine.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
namespace DebugPrintControl {
|
||||
|
||||
// Register a callback. Check for duplication.
|
||||
void RegisterCallback(DPrintCallback cb) {
|
||||
DPrintAccess state;
|
||||
for (DPrintCallback old : state->Callbacks) {
|
||||
if (cb == old) return;
|
||||
}
|
||||
state->Callbacks.Add(cb);
|
||||
}
|
||||
|
||||
// Set the collection bit in the global state.
|
||||
void EnableCollection() {
|
||||
DPrintAccess state;
|
||||
state->Collect = true;
|
||||
}
|
||||
|
||||
// Get the array of collected messages, if any.
|
||||
TArray<FString> GetStored() {
|
||||
DPrintAccess state;
|
||||
TArray<FString> result = std::move(state->Messages);
|
||||
state->Messages.Empty();
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ConsoleOutput
|
||||
//
|
||||
// Storing the text that goes in the unreal console.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void FlxConsoleOutput::Truncate() {
|
||||
int lines = 50;
|
||||
int csize = Content.Len();
|
||||
int total = 0;
|
||||
for (int i = csize - 1; i >= 0; i--) {
|
||||
if (Content[i] == '\n') {
|
||||
total += 1;
|
||||
if (total == lines) {
|
||||
Content = Content.RightChop(i + 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FlxConsoleOutput::MaybeAppendNewline() {
|
||||
int csize = Content.Len();
|
||||
if ((csize > 0) && (Content[csize - 1] != '\n')) {
|
||||
Content += TEXT("\n");
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool FlxConsoleOutput::MaybeAppendText(const FString& text) {
|
||||
if (!text.IsEmpty()) {
|
||||
Content += text;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void FlxConsoleOutput::Append(const FString& text) {
|
||||
bool modified = MaybeAppendText(text);
|
||||
if (modified) {
|
||||
Dirty = true;
|
||||
Truncate();
|
||||
}
|
||||
}
|
||||
|
||||
void FlxConsoleOutput::AppendLine(const FString& text) {
|
||||
bool modified = MaybeAppendNewline();
|
||||
modified |= MaybeAppendText(text);
|
||||
modified |= MaybeAppendNewline();
|
||||
if (modified) {
|
||||
Dirty = true;
|
||||
Truncate();
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Namespace DebugPrint
|
||||
//
|
||||
// This namespace contains the function "DPrint",
|
||||
// which is short for debugging print. This
|
||||
// is what you should use if you want to print
|
||||
// a debugging message.
|
||||
//
|
||||
// Messages printed using "DPrint" will
|
||||
// be routed to several destinations. These
|
||||
// might include a logfile, the unreal console,
|
||||
// and the visual studio debugging log.
|
||||
//
|
||||
// In order for "DPrint" to work, you have to
|
||||
// configure them once, at program initialization
|
||||
// time. This is done using the functions in
|
||||
// namespace DebugPrintConfig, below.
|
||||
//
|
||||
// We promise that namespace DebugPrint will
|
||||
// only ever contain one function, 'DPrint.'
|
||||
// that way, it's safe for you to put
|
||||
// 'using namespace DebugPrint' in your code.
|
||||
//
|
||||
// All DPrint-related functionality is
|
||||
// thread-safe. A single 'DPrint' is meant to
|
||||
// be output atomically.
|
||||
//
|
||||
// It is fine for the content of the DPrint
|
||||
// string to contain newlines.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
namespace DebugPrint {
|
||||
// Print text into the debug log.
|
||||
void DPrint(const FString& fs);
|
||||
|
||||
// Print text into the debug log.
|
||||
void DPrint(const char* msg);
|
||||
|
||||
// Print text into the debug log.
|
||||
void DPrint(const char* msg, size_t len);
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// namespace DebugPrintControl
|
||||
//
|
||||
// This namespace contains the functions
|
||||
// necessary to initialize "DPrint", and
|
||||
// route its output to several destinations.
|
||||
//
|
||||
// "DPrint" is a callback-based design.
|
||||
// Initialization might consist of: register a
|
||||
// callback that sends a string to a logfile,
|
||||
// register another callback that sends a string
|
||||
// to visual studio's debug console, and register
|
||||
// a third one that sends a string to the
|
||||
// unreal console. Each time somebody calls
|
||||
// 'DPrint', all three callbacks will get invoked.
|
||||
//
|
||||
// There is also a 'collect' option where you
|
||||
// can ask "DPrint" to save the messages in a
|
||||
// buffer, which you can then collect at
|
||||
// your leisure. You can use buffering and
|
||||
// callbacks at the same time. Note that
|
||||
// buffering is inherently less than ideal for
|
||||
// messages that warn of imminent program aborts.
|
||||
// So it is recommended that you use at least one
|
||||
// callback that sends its output without delay.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
namespace DebugPrintControl {
|
||||
// The prototype for a callback function.
|
||||
//
|
||||
using DPrintCallback = void (*)(const FString& fs);
|
||||
|
||||
// Register a callback.
|
||||
//
|
||||
// Registering a callback that is already
|
||||
// registered is a no-op.
|
||||
//
|
||||
void RegisterCallback(DPrintCallback f);
|
||||
|
||||
// Enable collection in a buffer.
|
||||
//
|
||||
// If collection is already enabled, this is a no-op.
|
||||
//
|
||||
void EnableCollection();
|
||||
|
||||
// Collect all the stored messages, and clear the storage.
|
||||
//
|
||||
TArray<FString> GetStored();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ConsoleOutput
|
||||
//
|
||||
// This class stores the text that's in the unreal console.
|
||||
// It stores it as one great big string, which contains
|
||||
// newlines to denote line breaks.
|
||||
//
|
||||
// This class also contains a 'dirty' bit. Each time somebody
|
||||
// appends a line of text to the console, the dirty bit is
|
||||
// automatically set. The bit can be checked using 'IsDirty'
|
||||
// and cleared using 'ClearDirty'. This makes it so that
|
||||
// you don't have to update the unreal widget unless the
|
||||
// text has actually changed.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
class FlxConsoleOutput {
|
||||
private:
|
||||
FString Content;
|
||||
bool Dirty;
|
||||
|
||||
// Truncate the console to a reasonable number of
|
||||
// lines. The length is hardwired.
|
||||
void Truncate();
|
||||
|
||||
// Add a newline if there isn't one. Returns true if it changed anything.
|
||||
bool MaybeAppendNewline();
|
||||
|
||||
// Append text. Returns true if it changed anything.
|
||||
bool MaybeAppendText(const FString& text);
|
||||
|
||||
public:
|
||||
// Append a line of text to the console.
|
||||
void Append(const FString& text);
|
||||
|
||||
// Append a line of text to the console on a line by itself.
|
||||
void AppendLine(const FString& text);
|
||||
|
||||
// Get the console text as a string.
|
||||
const FString& Get() const { return Content; }
|
||||
|
||||
// Return if the dirty flag is set.
|
||||
bool IsDirty() const { return Dirty; }
|
||||
|
||||
// Clear the dirty flag.
|
||||
void ClearDirty() { Dirty = false; }
|
||||
};
|
||||
|
||||
|
||||
@@ -1,25 +1,32 @@
|
||||
|
||||
#include "LockedWrapper.h"
|
||||
#include "DebugPrint.h"
|
||||
#include "LuprexGameModeBase.h"
|
||||
#include "lpx-drvutil.hpp"
|
||||
#include "lpx-paths.hpp"
|
||||
|
||||
using namespace CommonTypes;
|
||||
|
||||
|
||||
void FlxLockedWrapper::DPrintHook(const char *Msg, size_t Size)
|
||||
{
|
||||
FString FMessage(Size, (const UTF8CHAR *)Msg);
|
||||
UE_LOG(LogLuprex, Error, TEXT("%s"), *FMessage);
|
||||
}
|
||||
|
||||
void FlxLockedWrapper::InitWrapper() {
|
||||
if (Lockable.Wrapper.play_initialize != nullptr) {
|
||||
// Already initialized.
|
||||
return;
|
||||
}
|
||||
FString dll((const UTF8CHAR*)LUPREX_DLL_PATH);
|
||||
DebugPrint::DPrint(dll);
|
||||
UE_LOG(LogLuprex, Verbose, TEXT("Luprex DLL Path: %s"), *dll);
|
||||
void* DLL = FPlatformProcess::GetDllHandle(*dll);
|
||||
if (DLL != nullptr) {
|
||||
using InitFn = void (*)(EngineWrapper*);
|
||||
InitFn init = (InitFn)FPlatformProcess::GetDllExport(DLL, TEXT("init_engine_wrapper"));
|
||||
if (init != nullptr) {
|
||||
init(&Lockable.Wrapper);
|
||||
Lockable.Wrapper.hook_dprint(DebugPrint::DPrint);
|
||||
Lockable.Wrapper.hook_dprint(DPrintHook);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,16 +34,9 @@ void FlxLockedWrapper::InitWrapper() {
|
||||
FString FlxLockedWrapper::FetchStdout() {
|
||||
uint32_t ndata; const char* data;
|
||||
Lockable.Wrapper.get_outgoing(Get(), 0, &ndata, &data);
|
||||
|
||||
if (ndata == 0) {
|
||||
return FString();
|
||||
}
|
||||
|
||||
std::string_view src(data, ndata);
|
||||
int consumed;
|
||||
std::u16string cps = drvutil::utf8_to_ucs2(src, &consumed);
|
||||
Lockable.Wrapper.play_sent_outgoing(Get(), 0, consumed);
|
||||
return FString(cps.size(), (const UCS2CHAR*)(&cps[0]));
|
||||
FString result(ndata, (const UTF8CHAR *)data);
|
||||
Lockable.Wrapper.play_sent_outgoing(Get(), 0, ndata);
|
||||
return result;
|
||||
}
|
||||
|
||||
int64 FlxLockedWrapper::GetActor() {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "lpx-enginewrapper.hpp"
|
||||
#include "CommonTypes.h"
|
||||
|
||||
|
||||
// Class FlxLockableWrapper
|
||||
//
|
||||
// Contains the EngineWrapper and a Mutex to lock it.
|
||||
@@ -31,11 +32,17 @@ class FlxLockedWrapper {
|
||||
private:
|
||||
FlxLockableWrapper& Lockable;
|
||||
|
||||
// This function is called by luprex to output debugging
|
||||
// messages. It is a thin wrapper around UE_LOG.
|
||||
//
|
||||
static void DPrintHook(const char *Msg, size_t Size);
|
||||
|
||||
public:
|
||||
// Import these types into our Namespace.
|
||||
using IdArray = CommonTypes::IdArray;
|
||||
using IdView = CommonTypes::IdView;
|
||||
using StringViewVec = CommonTypes::StringViewVec;
|
||||
// Import these types into our Namespace.
|
||||
using IdArray = CommonTypes::IdArray;
|
||||
using IdView = CommonTypes::IdView;
|
||||
using StringViewVec = CommonTypes::StringViewVec;
|
||||
|
||||
|
||||
public:
|
||||
// The constructor of the FlxLockedWrapper claims the mutex.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
|
||||
#include "LuaCall.h"
|
||||
#include "LuprexGameModeBase.h"
|
||||
#include "StringDecoder.h"
|
||||
|
||||
#include "EdGraphSchema_K2.h"
|
||||
|
||||
static void FatalBlueprintError(const TCHAR *message) {
|
||||
@@ -203,7 +205,8 @@ FString UlxLuaCallLibrary::AllFunctionsWithPrefix(const TCHAR *Prefix)
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
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);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetBuffer();
|
||||
mode->LuaCallBegin();
|
||||
@@ -212,7 +215,8 @@ void UlxLuaCallLibrary::LuaCallBegin(UObject *context, const FString &cname, con
|
||||
}
|
||||
|
||||
|
||||
void UlxLuaCallLibrary::LuaCallInvoke(UObject *context, AActor *place) {
|
||||
void UlxLuaCallLibrary::LuaCallInvoke(UObject *context, AActor *place)
|
||||
{
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetBuffer();
|
||||
CheckNotEmpty(sb);
|
||||
@@ -220,31 +224,26 @@ void UlxLuaCallLibrary::LuaCallInvoke(UObject *context, AActor *place) {
|
||||
}
|
||||
|
||||
|
||||
void UlxLuaCallLibrary::LuaCallProbe(UObject *context, AActor *place) {
|
||||
void UlxLuaCallLibrary::LuaCallProbe(UObject *context, AActor *place)
|
||||
{
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetBuffer();
|
||||
CheckNotEmpty(sb);
|
||||
mode->LuaCallEnd(InvocationKind::LUA_PROBE, place);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ELpxSimpleDynamicTag UlxLuaCallLibrary::LuaCallNextResultType(UObject *context) {
|
||||
// ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
// FlxStreamBuffer &sb = mode->LuaCallGetResult();
|
||||
// if (sb.empty()) return ELpxSimpleDynamicTag::None;
|
||||
// int64_t total_reads = sb.total_reads();
|
||||
// SimpleDynamicTag tag = sb.read_simple_dynamic_tag();
|
||||
// sb.unread_to(total_reads);
|
||||
// switch (tag) {
|
||||
// case SimpleDynamicTag::STRING: return ELpxSimpleDynamicTag::String;
|
||||
// case SimpleDynamicTag::TOKEN: return ELpxSimpleDynamicTag::Name;
|
||||
// case SimpleDynamicTag::NUMBER: return ELpxSimpleDynamicTag::Float;
|
||||
// case SimpleDynamicTag::VECTOR: return ELpxSimpleDynamicTag::Vector;
|
||||
// case SimpleDynamicTag::BOOLEAN: return ELpxSimpleDynamicTag::Boolean;
|
||||
// default: return ELpxSimpleDynamicTag::None;
|
||||
// }
|
||||
// }
|
||||
UlxLuaValues *UlxLuaCallLibrary::LuaCallGetRest(UObject *context)
|
||||
{
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetResult();
|
||||
UlxLuaValues *Values = NewObject<UlxLuaValues>(context);
|
||||
if (!Values->Initialize(sb.view()))
|
||||
{
|
||||
UE_LOG(LogBlueprint, Error, TEXT("Lua call returned corrupt data"));
|
||||
return nullptr;
|
||||
}
|
||||
return Values;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "EdGraph/EdGraphPin.h"
|
||||
|
||||
#include "LuaCall.generated.h"
|
||||
|
||||
class UlxLuaValues;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
@@ -119,6 +121,9 @@ public:
|
||||
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function")
|
||||
static void LuaCallProbe(UObject *context, AActor *Place);
|
||||
|
||||
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context", BlueprintInternalUseOnly = "true"), Category = "Luprex|Call Lua Function")
|
||||
static UlxLuaValues *LuaCallGetRest(UObject *context);
|
||||
|
||||
//
|
||||
// Functions that pack arguments into the call buffer.
|
||||
//
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
|
||||
#include "LuaCallNode.h"
|
||||
#include "StringDecoder.h"
|
||||
|
||||
#include "BlueprintActionDatabaseRegistrar.h"
|
||||
#include "BlueprintNodeSpawner.h"
|
||||
@@ -40,59 +41,41 @@
|
||||
|
||||
#define LOCTEXT_NAMESPACE "LuaCall"
|
||||
|
||||
#define LuaCallLibraryFunction(name) (UlxLuaCallLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UlxLuaCallLibrary, name)))
|
||||
|
||||
// All argument pins will have internal Names that start with "A:"
|
||||
|
||||
static bool IsArgumentPin(const UEdGraphPin *Pin) {
|
||||
const FName UK2Node_LuaCall::FunctionPinName(TEXT("Lua Function Prototype"));
|
||||
const FName UK2Node_LuaCall::InvokeOrProbePinName(TEXT("Invoke or Probe"));
|
||||
const FName UK2Node_LuaCall::PlacePinName(TEXT("Place Tangible"));
|
||||
const FName UK2Node_LuaCall::ExtraResultsPinName(TEXT("Extra Results"));
|
||||
|
||||
bool UK2Node_LuaCall::IsPrefix(const UEdGraphPin *Pin, char Prefix)
|
||||
{
|
||||
TCHAR pname[FName::StringBufferSize];
|
||||
Pin->PinName.ToString(pname);
|
||||
return pname[0] == 'A' && pname[1] == ':';
|
||||
return pname[0] == Prefix && pname[1] == ':';
|
||||
}
|
||||
|
||||
static FName ArgumentNameAddPrefix(const FString &name) {
|
||||
FString Prefixed = FString("A:") + name;
|
||||
FName UK2Node_LuaCall::AddPrefix(const FString &Name, char Prefix)
|
||||
{
|
||||
TCHAR PrefixChars[3];
|
||||
PrefixChars[0] = Prefix;
|
||||
PrefixChars[1] = ':';
|
||||
PrefixChars[2] = 0;
|
||||
FString Prefixed = PrefixChars + 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) {
|
||||
FString UK2Node_LuaCall::RemovePrefix(FName Name, char Prefix)
|
||||
{
|
||||
TCHAR pname[FName::StringBufferSize];
|
||||
Pin->PinName.ToString(pname);
|
||||
return pname[0] == 'R' && pname[1] == ':';
|
||||
Name.ToString(pname);
|
||||
check(pname[0] == Prefix);
|
||||
check(pname[1] == ':');
|
||||
return FString(pname + 2);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#define LuaCallLibraryFunction(name) (UlxLuaCallLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UlxLuaCallLibrary, name)))
|
||||
|
||||
static FEdGraphPinType GetPinType(const FProperty *Property)
|
||||
{
|
||||
FEdGraphPinType PinType;
|
||||
@@ -107,7 +90,6 @@ static FEdGraphPinType GetPinType(const FProperty *Property)
|
||||
}
|
||||
|
||||
|
||||
|
||||
UK2Node_LuaCall::UK2Node_LuaCall(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
@@ -154,29 +136,6 @@ void UK2Node_LuaCall::CreateCorrectPins()
|
||||
LuaFunctionPrototype = TEXT("class.func(int arg1, int arg2) : int ret1, int 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())
|
||||
@@ -186,26 +145,60 @@ void UK2Node_LuaCall::CreateCorrectPins()
|
||||
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;
|
||||
// Transfer all pins to the old pins map and clear the pin list.
|
||||
TMap<FName, UEdGraphPin *> OldPins;
|
||||
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();
|
||||
OldPins.Add(CheckPin->PinName, CheckPin);
|
||||
}
|
||||
Pins.Empty();
|
||||
|
||||
// KeepPin is a function that moves a pin from the old pins
|
||||
// map back onto the pins list.
|
||||
auto KeepPin = [&](FName Name, FEdGraphPinType Type = FEdGraphPinType()) -> bool
|
||||
{
|
||||
UEdGraphPin **OldPin = OldPins.Find(Name);
|
||||
if ((OldPin != nullptr) && (((*OldPin)->PinType == Type) || (Type.PinCategory == FName())))
|
||||
{
|
||||
Pins.Emplace(*OldPin);
|
||||
OldPins.Remove(Name);
|
||||
}
|
||||
return OldPin != nullptr;
|
||||
};
|
||||
|
||||
if (!KeepPin(UEdGraphSchema_K2::PN_Execute))
|
||||
{
|
||||
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Execute);
|
||||
}
|
||||
|
||||
if (!KeepPin(UEdGraphSchema_K2::PN_Then))
|
||||
{
|
||||
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Then);
|
||||
}
|
||||
|
||||
if (!KeepPin(FunctionPinName))
|
||||
{
|
||||
UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_String, FunctionPinName);
|
||||
P->DefaultValue = LuaFunctionPrototype;
|
||||
}
|
||||
|
||||
if (!KeepPin(InvokeOrProbePinName))
|
||||
{
|
||||
UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Byte, StaticEnum<ElxInvokeOrProbe>(), InvokeOrProbePinName);
|
||||
P->DefaultValue = TEXT("Probe");
|
||||
P->AutogeneratedDefaultValue = P->DefaultValue;
|
||||
}
|
||||
|
||||
if (!KeepPin(PlacePinName))
|
||||
{
|
||||
UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Object, AActor::StaticClass(), PlacePinName);
|
||||
}
|
||||
|
||||
// Create Argument pins in the correct order, reusing old pins where possible.
|
||||
for (const FlxParsedProto::Pin & Pin : ParsedProto.Arguments)
|
||||
{
|
||||
FName PrefixedName = ArgumentNameAddPrefix(Pin.Name);
|
||||
FName PrefixedName = AddPrefix(Pin.Name, 'A');
|
||||
UFunction *Accessor = UlxLuaCallLibrary::GetArgumentPacker(Pin.Type);
|
||||
if (Accessor == nullptr) {
|
||||
bHasCompilerMessage = true;
|
||||
@@ -214,11 +207,8 @@ void UK2Node_LuaCall::CreateCorrectPins()
|
||||
continue;
|
||||
}
|
||||
FEdGraphPinType PinType = GetPinType(Accessor->FindPropertyByName(TEXT("Value")));
|
||||
UEdGraphPin **OldPin = OldArgumentPins.Find(PrefixedName);
|
||||
if ((OldPin != nullptr) && ((*OldPin)->PinType == PinType)) {
|
||||
Pins.Emplace(*OldPin);
|
||||
OldArgumentPins.Remove(PrefixedName);
|
||||
} else {
|
||||
if (!KeepPin(PrefixedName, PinType))
|
||||
{
|
||||
CreatePin(EGPD_Input, PinType, PrefixedName);
|
||||
}
|
||||
}
|
||||
@@ -226,7 +216,7 @@ void UK2Node_LuaCall::CreateCorrectPins()
|
||||
// Create ReturnValue pins in the correct order, reusing old pins where possible.
|
||||
for (const FlxParsedProto::Pin & Pin : ParsedProto.ReturnValues)
|
||||
{
|
||||
FName PrefixedName = ReturnValueNameAddPrefix(Pin.Name);
|
||||
FName PrefixedName = AddPrefix(Pin.Name, 'R');
|
||||
UFunction *Accessor = UlxLuaCallLibrary::GetReturnValueUnpacker(Pin.Type);
|
||||
if (Accessor == nullptr) {
|
||||
bHasCompilerMessage = true;
|
||||
@@ -235,28 +225,27 @@ void UK2Node_LuaCall::CreateCorrectPins()
|
||||
continue;
|
||||
}
|
||||
FEdGraphPinType PinType = GetPinType(Accessor->GetReturnProperty());
|
||||
UEdGraphPin **OldPin = OldReturnValuePins.Find(PrefixedName);
|
||||
if ((OldPin != nullptr) && ((*OldPin)->PinType == PinType)) {
|
||||
Pins.Emplace(*OldPin);
|
||||
OldReturnValuePins.Remove(PrefixedName);
|
||||
} else {
|
||||
if (!KeepPin(PrefixedName, PinType))
|
||||
{
|
||||
CreatePin(EGPD_Output, PinType, PrefixedName);
|
||||
}
|
||||
}
|
||||
|
||||
if (ParsedProto.ExtraReturnValues)
|
||||
{
|
||||
if (!KeepPin(ExtraResultsPinName))
|
||||
{
|
||||
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Object, UlxLuaValues::StaticClass(), ExtraResultsPinName);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete any unused pins.
|
||||
for (auto &iter : OldArgumentPins)
|
||||
for (auto &iter : OldPins)
|
||||
{
|
||||
iter.Value->Modify();
|
||||
iter.Value->MarkAsGarbage();
|
||||
}
|
||||
for (auto &iter : OldReturnValuePins)
|
||||
{
|
||||
iter.Value->Modify();
|
||||
iter.Value->MarkAsGarbage();
|
||||
}
|
||||
OldArgumentPins.Empty();
|
||||
OldReturnValuePins.Empty();
|
||||
OldPins.Empty();
|
||||
}
|
||||
|
||||
|
||||
@@ -274,7 +263,7 @@ FText UK2Node_LuaCall::GetPinDisplayName(const UEdGraphPin* Pin) const
|
||||
}
|
||||
|
||||
// Many pins can go unlabeled if they have default values.
|
||||
if (IsFunctionPin(Pin) || IsInvokeOrProbePin(Pin))
|
||||
if ((Pin->PinName == FunctionPinName) || (Pin->PinName == InvokeOrProbePinName))
|
||||
{
|
||||
if (Pin->LinkedTo.Num() == 0)
|
||||
{
|
||||
@@ -283,13 +272,15 @@ FText UK2Node_LuaCall::GetPinDisplayName(const UEdGraphPin* Pin) const
|
||||
}
|
||||
|
||||
// For argument pins, we must strip off the Argument Pin Prefix.
|
||||
if (IsArgumentPin(Pin)) {
|
||||
return FText::FromString(ArgumentNameRemovePrefix(Pin->PinName));
|
||||
if (IsPrefix(Pin, 'A'))
|
||||
{
|
||||
return FText::FromString(RemovePrefix(Pin->PinName, 'A'));
|
||||
}
|
||||
|
||||
// For return value pins, we must strip off the Return Value Pin Prefix.
|
||||
if (IsReturnValuePin(Pin)) {
|
||||
return FText::FromString(ReturnValueNameRemovePrefix(Pin->PinName));
|
||||
if (IsPrefix(Pin, 'R'))
|
||||
{
|
||||
return FText::FromString(RemovePrefix(Pin->PinName, 'R'));
|
||||
}
|
||||
|
||||
// Otherwise, just return the Pin Name the normal way.
|
||||
@@ -309,7 +300,7 @@ void UK2Node_LuaCall::PinConnectionListChanged(UEdGraphPin* Pin)
|
||||
|
||||
void UK2Node_LuaCall::PinDefaultValueChanged(UEdGraphPin* Pin)
|
||||
{
|
||||
if(IsFunctionPin(Pin))
|
||||
if(Pin->PinName == FunctionPinName)
|
||||
{
|
||||
LuaFunctionPrototype = Pin->DefaultValue;
|
||||
CreateCorrectPins();
|
||||
@@ -356,7 +347,7 @@ void UK2Node_LuaCall::ExpandNode(class FKismetCompilerContext& CompilerContext,
|
||||
// Add Packing operations for all argument pins.
|
||||
for (const FlxParsedProto::Pin &PinInfo : ParsedProto.Arguments)
|
||||
{
|
||||
UEdGraphPin *Pin = FindPinChecked(ArgumentNameAddPrefix(PinInfo.Name));
|
||||
UEdGraphPin *Pin = FindPinChecked(AddPrefix(PinInfo.Name, 'A'));
|
||||
UFunction *PackingFunc = UlxLuaCallLibrary::GetArgumentPacker(PinInfo.Type);
|
||||
if (PackingFunc == nullptr)
|
||||
{
|
||||
@@ -378,10 +369,10 @@ void UK2Node_LuaCall::ExpandNode(class FKismetCompilerContext& CompilerContext,
|
||||
PrevNode->GetThenPin()->MakeLinkTo(ActionNode->GetExecPin());
|
||||
PrevNode = ActionNode;
|
||||
|
||||
// Add Unpacking operations for all argument pins.
|
||||
// Add Unpacking operations for all return value pins.
|
||||
for (const FlxParsedProto::Pin &PinInfo : ParsedProto.ReturnValues)
|
||||
{
|
||||
UEdGraphPin *Pin = FindPinChecked(ReturnValueNameAddPrefix(PinInfo.Name));
|
||||
UEdGraphPin *Pin = FindPinChecked(AddPrefix(PinInfo.Name, 'R'));
|
||||
UFunction *UnpackingFunc = UlxLuaCallLibrary::GetReturnValueUnpacker(PinInfo.Type);
|
||||
if (UnpackingFunc == nullptr)
|
||||
{
|
||||
@@ -395,16 +386,26 @@ void UK2Node_LuaCall::ExpandNode(class FKismetCompilerContext& CompilerContext,
|
||||
PrevNode = UnpackNode;
|
||||
}
|
||||
|
||||
// Make sure we didn't have return values for an invoke.
|
||||
if (IsInvoke && (ParsedProto.ReturnValues.Num() > 0))
|
||||
// If there is an extra results pin, hook it up.
|
||||
if (ParsedProto.ExtraReturnValues)
|
||||
{
|
||||
CompilerContext.MessageLog.Error(TEXT("Lua Call in Invoke mode does not support return values"));
|
||||
UEdGraphPin *Pin = FindPinChecked(ExtraResultsPinName);
|
||||
UK2Node_CallFunction *UnpackNode = MakeCallFunctionNode(LuaCallLibraryFunction(LuaCallGetRest));
|
||||
CompilerContext.MovePinLinksToIntermediate(*Pin, *UnpackNode->FindPinChecked(UEdGraphSchema_K2::PN_ReturnValue));
|
||||
PrevNode->GetThenPin()->MakeLinkTo(UnpackNode->GetExecPin());
|
||||
PrevNode = UnpackNode;
|
||||
}
|
||||
|
||||
// Link up the Exec pins.
|
||||
CompilerContext.MovePinLinksToIntermediate(*GetExecPin(), *BeginNode->GetExecPin());
|
||||
CompilerContext.MovePinLinksToIntermediate(*GetThenPin(), *PrevNode->GetThenPin());
|
||||
|
||||
// Make sure we didn't have return values for an invoke.
|
||||
if (IsInvoke && ((ParsedProto.ReturnValues.Num() > 0) || (ParsedProto.ExtraReturnValues)))
|
||||
{
|
||||
CompilerContext.MessageLog.Error(TEXT("Lua Call in Invoke mode does not support return values"));
|
||||
}
|
||||
|
||||
BreakAllNodeLinks();
|
||||
}
|
||||
|
||||
@@ -457,14 +458,14 @@ UK2Node::ERedirectType UK2Node_LuaCall::DoPinsMatchForReconstruction(const UEdGr
|
||||
bool UK2Node_LuaCall::IsConnectionDisallowed(const UEdGraphPin* MyPin, const UEdGraphPin* OtherPin, FString& OutReason) const
|
||||
{
|
||||
// The function pin cannot be connected.
|
||||
if (IsFunctionPin(MyPin))
|
||||
if (MyPin->PinName == FunctionPinName)
|
||||
{
|
||||
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))
|
||||
if (MyPin->PinName == InvokeOrProbePinName)
|
||||
{
|
||||
OutReason = LOCTEXT("Error_InvokeOrProbeMustBeHardwired", "Invoke vs Probe must be a hardwired constant.").ToString();
|
||||
return true;
|
||||
|
||||
@@ -69,9 +69,21 @@ class UK2Node_LuaCall : public UK2Node
|
||||
//~ End UK2Node Interface.
|
||||
|
||||
private:
|
||||
|
||||
/** Create all necessary pins. */
|
||||
void CreateCorrectPins();
|
||||
|
||||
/** Pin Names for the three built-in Pins **/
|
||||
static const FName FunctionPinName;
|
||||
static const FName InvokeOrProbePinName;
|
||||
static const FName PlacePinName;
|
||||
static const FName ExtraResultsPinName;
|
||||
|
||||
/** Utility functions for manipulating pin names with prefixes **/
|
||||
static bool IsPrefix(const UEdGraphPin *Pin, char Prefix);
|
||||
static FName AddPrefix(const FString &String, char Prefix);
|
||||
static FString RemovePrefix(FName Name, char Prefix);
|
||||
|
||||
private:
|
||||
/** The lua function prototype, which must be saved as a property **/
|
||||
UPROPERTY()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "LuprexGameModeBase.h"
|
||||
#include "lpx-drvutil.hpp"
|
||||
#include "lpx-paths.hpp"
|
||||
#include "DebugPrint.h"
|
||||
#include "ConsoleOutput.h"
|
||||
#include "Tangible.h"
|
||||
#include "TangibleManager.h"
|
||||
#include "CommonTypes.h"
|
||||
@@ -11,9 +11,11 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
using namespace DebugPrint;
|
||||
using namespace CommonTypes;
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogLuprex);
|
||||
DEFINE_LOG_CATEGORY(LogLuprexIntegration);
|
||||
|
||||
ALuprexGameModeBase::ALuprexGameModeBase()
|
||||
{
|
||||
TangibleManager = NewObject<UlxTangibleManager>();
|
||||
@@ -24,7 +26,6 @@ ALuprexGameModeBase::ALuprexGameModeBase()
|
||||
//PrimaryActorTick.TickGroup = TG_PrePhysics; // Probably wrong
|
||||
SetActorTickEnabled(true);
|
||||
SetActorTickInterval(0.0f);
|
||||
DebugPrintControl::EnableCollection();
|
||||
ResetToInitialState();
|
||||
OnWorldPreActorTickHandle = FWorldDelegates::OnWorldPreActorTick.AddUObject(this, &ALuprexGameModeBase::OnWorldPreActorTick);
|
||||
OnWorldPostActorTickHandle = FWorldDelegates::OnWorldPostActorTick.AddUObject(this, &ALuprexGameModeBase::OnWorldPostActorTick);
|
||||
@@ -103,12 +104,6 @@ void ALuprexGameModeBase::UpdateConsoleOutput() {
|
||||
ConsoleOutput.Append(lockedwrap.FetchStdout());
|
||||
}
|
||||
|
||||
// Copy Debugging Prints into the console.
|
||||
TArray<FString> prints = DebugPrintControl::GetStored();
|
||||
for (const FString& fs : prints) {
|
||||
ConsoleOutput.AppendLine(fs);
|
||||
}
|
||||
|
||||
// If the Console text has changed, update the widget.
|
||||
if (ConsoleOutput.IsDirty()) {
|
||||
ConsoleSetOutput(ConsoleOutput.Get());
|
||||
@@ -192,21 +187,7 @@ void ALuprexGameModeBase::LuaCallEnd(InvocationKind kind, AActor *place) {
|
||||
}
|
||||
|
||||
void ALuprexGameModeBase::ExecuteDebuggingCommand(FlxLockedWrapper &w, const FString &fs) {
|
||||
if (fs == "\\invokeplayer") {
|
||||
DPrint(TEXT("Trying to invoke 'myfunction' in lua"));
|
||||
FlxStreamBuffer &sb = LuaCallBegin();
|
||||
sb.write_string("engio");
|
||||
sb.write_string("myfunction");
|
||||
sb.write_simple_dynamic_tag(SimpleDynamicTag::NUMBER);
|
||||
sb.write_double(3.0);
|
||||
sb.write_simple_dynamic_tag(SimpleDynamicTag::STRING);
|
||||
sb.write_string("Howdy");
|
||||
sb.write_simple_dynamic_tag(SimpleDynamicTag::VECTOR);
|
||||
sb.write_fvector(FVector(2,3,4));
|
||||
LuaCallEnd(InvocationKind::LUA_INVOKE);
|
||||
} else {
|
||||
ConsoleOutput.AppendLine(TEXT("Unknown Command"));
|
||||
}
|
||||
// Nothing here right now.
|
||||
}
|
||||
|
||||
void ALuprexGameModeBase::ConsoleSendInput(const FString& fs)
|
||||
@@ -262,16 +243,13 @@ void ALuprexGameModeBase::Tick(float deltaseconds)
|
||||
|
||||
void ALuprexGameModeBase::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
// Make sure we're starting from a clean slate.
|
||||
// Note: this claims the wrapper lock, so don't claim
|
||||
// the lock before calling this.
|
||||
ResetToInitialState();
|
||||
InitializeGlobalState();
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
// Now we're just going to claim the wrapper
|
||||
// lock for the remainder. When we create the thread,
|
||||
// the thread will hang until we release this lock.
|
||||
void ALuprexGameModeBase::InitializeGlobalState()
|
||||
{
|
||||
FlxLockedWrapper w(LockableWrapper);
|
||||
|
||||
// Sanity checks. Make sure everything is clean.
|
||||
@@ -284,7 +262,7 @@ void ALuprexGameModeBase::BeginPlay()
|
||||
// If we failed to initialize the wrapper, print an error message.
|
||||
if (w->play_initialize == nullptr)
|
||||
{
|
||||
DPrint("Luprex wrapper initialization failed");
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Luprex wrapper initialization failed"));
|
||||
}
|
||||
|
||||
// If wrapper is initialized, try to initialize the luprex engine.
|
||||
@@ -294,7 +272,8 @@ void ALuprexGameModeBase::BeginPlay()
|
||||
std::string srcpakerr = drvutil::package_lua_source(LUPREX_ROOT_PATH, &srcpak);
|
||||
if (!srcpakerr.empty())
|
||||
{
|
||||
DPrint(srcpakerr.c_str());
|
||||
FString FMessage((const UTF8CHAR *)(srcpakerr.c_str()));
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Trying to read Lua source: %s"), *FMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -304,10 +283,11 @@ void ALuprexGameModeBase::BeginPlay()
|
||||
w->play_initialize(w.Get(), 1, argv, srcpakv.size(), srcpakv.data(), "");
|
||||
if (w->error[0])
|
||||
{
|
||||
DPrint(w->error);
|
||||
FString FMessage((const UTF8CHAR *)w->error);
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Calling Luprex play_initialize: %s"), *FMessage);
|
||||
}
|
||||
if (w->engine != nullptr) {
|
||||
DPrint("Luprex initialize success");
|
||||
UE_LOG(LogLuprexIntegration, Verbose, TEXT("Luprex initialization success."));
|
||||
Playing = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/GameModeBase.h"
|
||||
#include "lpx-enginewrapper.hpp"
|
||||
#include "DebugPrint.h"
|
||||
#include "ConsoleOutput.h"
|
||||
#include "StringDecoder.h"
|
||||
#include "TangibleManager.h"
|
||||
#include "LuprexSockets.h"
|
||||
@@ -13,6 +13,11 @@
|
||||
#include "BlueprintErrors.h"
|
||||
#include "LuprexGameModeBase.generated.h"
|
||||
|
||||
// Messages that come from inside the Luprex Core.
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogLuprex, Warning, All);
|
||||
|
||||
// Messages that pertain to our Luprex integration with Unreal.
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogLuprexIntegration, Warning, All);
|
||||
|
||||
class LookAtDetector;
|
||||
|
||||
@@ -35,6 +40,9 @@ public:
|
||||
// includes: the Luprex engine, the thread, and the socket state.
|
||||
void ResetToInitialState();
|
||||
|
||||
// Initialize the Luprex DLL, and do other global initialization.
|
||||
void InitializeGlobalState();
|
||||
|
||||
// Set the entire contents of the console output box.
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "Luprex|Miscellaneous")
|
||||
void ConsoleSetOutput(const FString& text);
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
|
||||
#include "LuprexSockets.h"
|
||||
#include "LuprexGameModeBase.h"
|
||||
#include "lpx-enginewrapper.hpp"
|
||||
#include "lpx-drvutil.hpp"
|
||||
#include "DebugPrint.h"
|
||||
#include "Sockets.h"
|
||||
#include "SocketTypes.h"
|
||||
#include "SocketSubsystem.h"
|
||||
#include "AddressInfoTypes.h"
|
||||
|
||||
using namespace DebugPrint;
|
||||
|
||||
#define UI UI_ST
|
||||
THIRD_PARTY_INCLUDES_START
|
||||
@@ -215,9 +214,9 @@ public:
|
||||
FlxSocketsI(FlxLockedWrapper &w);
|
||||
virtual ~FlxSocketsI() override;
|
||||
|
||||
// Copy the trace to the DPrint output.
|
||||
void DPrintTrace();
|
||||
|
||||
// Copy the trace to UE_LOG.
|
||||
void LogTrace();
|
||||
|
||||
// Error handling.
|
||||
void SetError(const std::string& s);
|
||||
virtual std::string GetError() override { return FatalError; }
|
||||
@@ -686,7 +685,7 @@ void FLpxChannel::AdvanceAccepting()
|
||||
{
|
||||
CloseChannelIfSSLErrorIsSerious( retval);
|
||||
}
|
||||
LSI->DPrintTrace();
|
||||
LSI->LogTrace();
|
||||
}
|
||||
|
||||
void FLpxChannel::AdvanceReadWrite()
|
||||
@@ -933,12 +932,13 @@ FlxSocketsI::~FlxSocketsI()
|
||||
// TODO: Be more thorough.
|
||||
}
|
||||
|
||||
void FlxSocketsI::DPrintTrace()
|
||||
void FlxSocketsI::LogTrace()
|
||||
{
|
||||
char* data;
|
||||
int ndata = BIO_get_mem_data(TraceBIO, &data);
|
||||
if (ndata == 0) return;
|
||||
DPrint(data, ndata);
|
||||
FString text(ndata, (const UTF8CHAR *)data);
|
||||
UE_LOG(LogLuprexIntegration, Verbose, TEXT("SSL Trace: %s"), *text);
|
||||
BIO_reset(TraceBIO);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,14 +22,14 @@ bool UlxLuaValues::Initialize(std::string_view data)
|
||||
SimpleDynamicTag Tag = Decoder.read_simple_dynamic_tag();
|
||||
|
||||
int64 Pos = Decoder.total_reads();
|
||||
ELxLuaValueType Type;
|
||||
ElxLuaValueType Type;
|
||||
switch (Tag)
|
||||
{
|
||||
case SimpleDynamicTag::BOOLEAN: Type=ELxLuaValueType::Boolean; Decoder.read_bool(); break;
|
||||
case SimpleDynamicTag::NUMBER: Type=ELxLuaValueType::Float; Decoder.read_double(); break;
|
||||
case SimpleDynamicTag::STRING: Type=ELxLuaValueType::String; Decoder.read_string_view(); break;
|
||||
case SimpleDynamicTag::TOKEN: Type=ELxLuaValueType::Name; Decoder.read_string_view(); break;
|
||||
case SimpleDynamicTag::VECTOR: Type=ELxLuaValueType::Vector; Decoder.read_fvector(); break;
|
||||
case SimpleDynamicTag::BOOLEAN: Type=ElxLuaValueType::Boolean; Decoder.read_bool(); break;
|
||||
case SimpleDynamicTag::NUMBER: Type=ElxLuaValueType::Float; Decoder.read_double(); break;
|
||||
case SimpleDynamicTag::STRING: Type=ElxLuaValueType::String; Decoder.read_string_view(); break;
|
||||
case SimpleDynamicTag::TOKEN: Type=ElxLuaValueType::Name; Decoder.read_string_view(); break;
|
||||
case SimpleDynamicTag::VECTOR: Type=ElxLuaValueType::Vector; Decoder.read_fvector(); break;
|
||||
default: {
|
||||
Empty();
|
||||
return false;
|
||||
@@ -42,22 +42,57 @@ bool UlxLuaValues::Initialize(std::string_view data)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UlxLuaValues::CheckType(ELxLuaValueType Type, ELxLuaValueType Desired)
|
||||
FString UlxLuaValues::DebugString() const
|
||||
{
|
||||
TStringBuilder<2048> Output;
|
||||
Output << TEXT("{ ");
|
||||
for (int i = 0; i < Types.Num(); i++)
|
||||
{
|
||||
if (i > 0) Output << TEXT(", ");
|
||||
|
||||
ElxLuaValueType Type = Types[i];
|
||||
FlxStreamBuffer Decoder(Data[i]);
|
||||
switch (Type)
|
||||
{
|
||||
case ElxLuaValueType::Boolean:
|
||||
Output << Decoder.read_bool();
|
||||
break;
|
||||
case ElxLuaValueType::Float:
|
||||
Output << FString::Printf(TEXT("%lf"), Decoder.read_double());
|
||||
break;
|
||||
case ElxLuaValueType::String:
|
||||
Output << TEXT("\"") << Decoder.read_fstring() << TEXT("\"");
|
||||
break;
|
||||
case ElxLuaValueType::Name:
|
||||
Output << Decoder.read_fname();
|
||||
break;
|
||||
case ElxLuaValueType::Vector: {
|
||||
FVector Vec = Decoder.read_fvector();
|
||||
Output << FString::Printf(TEXT("(%lf, %lf, %lf)"), Vec.X, Vec.Y, Vec.Z);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Output << TEXT(" }");
|
||||
return Output.ToString();
|
||||
}
|
||||
|
||||
bool UlxLuaValues::CheckType(ElxLuaValueType Type, ElxLuaValueType Desired)
|
||||
{
|
||||
if (Type != Desired)
|
||||
{
|
||||
FString TypeName = StaticEnum<ELxLuaValueType>()->GetDisplayNameTextByValue(int64(Type)).ToString();
|
||||
FString DesiredName = StaticEnum<ELxLuaValueType>()->GetDisplayNameTextByValue(int64(Desired)).ToString();
|
||||
FString TypeName = StaticEnum<ElxLuaValueType>()->GetDisplayNameTextByValue(int64(Type)).ToString();
|
||||
FString DesiredName = StaticEnum<ElxLuaValueType>()->GetDisplayNameTextByValue(int64(Desired)).ToString();
|
||||
UE_LOG(LogBlueprint, Error, TEXT("Expected a value of type %s, but found %s instead."), *DesiredName, *TypeName);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ELxLuaValueType UlxLuaValues::GetType(int n) const
|
||||
ElxLuaValueType UlxLuaValues::GetType(int n) const
|
||||
{
|
||||
if (n < 0) return ELxLuaValueType::None;
|
||||
if (n >= Types.Num()) return ELxLuaValueType::None;
|
||||
if (n < 0) return ElxLuaValueType::None;
|
||||
if (n >= Types.Num()) return ElxLuaValueType::None;
|
||||
return Types[Cursor];
|
||||
}
|
||||
|
||||
@@ -69,42 +104,42 @@ ELxLuaValueType UlxLuaValues::GetType(int n) const
|
||||
|
||||
FString UlxLuaValues::GetString(int n) const
|
||||
{
|
||||
if (!CheckType(GetType(n), ELxLuaValueType::String)) return FString();
|
||||
if (!CheckType(GetType(n), ElxLuaValueType::String)) return FString();
|
||||
FlxStreamBuffer Decoder(Data[n]);
|
||||
return Decoder.read_fstring();
|
||||
}
|
||||
|
||||
FName UlxLuaValues::GetName(int n) const
|
||||
{
|
||||
if (!CheckType(GetType(n), ELxLuaValueType::Name)) return FName();
|
||||
if (!CheckType(GetType(n), ElxLuaValueType::Name)) return FName();
|
||||
FlxStreamBuffer Decoder(Data[n]);
|
||||
return Decoder.read_fname();
|
||||
}
|
||||
|
||||
double UlxLuaValues::GetFloat(int n) const
|
||||
{
|
||||
if (!CheckType(GetType(n), ELxLuaValueType::Float)) return 0.0;
|
||||
if (!CheckType(GetType(n), ElxLuaValueType::Float)) return 0.0;
|
||||
FlxStreamBuffer Decoder(Data[n]);
|
||||
return Decoder.read_double();
|
||||
}
|
||||
|
||||
int UlxLuaValues::GetInt(int n) const
|
||||
{
|
||||
if (!CheckType(GetType(n), ELxLuaValueType::Float)) return 0;
|
||||
if (!CheckType(GetType(n), ElxLuaValueType::Float)) return 0;
|
||||
FlxStreamBuffer Decoder(Data[n]);
|
||||
return int(Decoder.read_double());
|
||||
}
|
||||
|
||||
FVector UlxLuaValues::GetVector(int n) const
|
||||
{
|
||||
if (!CheckType(GetType(n), ELxLuaValueType::Vector)) return FVector();
|
||||
if (!CheckType(GetType(n), ElxLuaValueType::Vector)) return FVector();
|
||||
FlxStreamBuffer Decoder(Data[n]);
|
||||
return Decoder.read_fvector();
|
||||
}
|
||||
|
||||
FVector2D UlxLuaValues::GetVector2D(int n) const
|
||||
{
|
||||
if (!CheckType(GetType(n), ELxLuaValueType::Vector)) return FVector2D();
|
||||
if (!CheckType(GetType(n), ElxLuaValueType::Vector)) return FVector2D();
|
||||
FlxStreamBuffer Decoder(Data[n]);
|
||||
FVector v = Decoder.read_fvector();
|
||||
return FVector2D(v.X, v.Y);
|
||||
@@ -112,7 +147,7 @@ FVector2D UlxLuaValues::GetVector2D(int n) const
|
||||
|
||||
bool UlxLuaValues::GetBoolean(int n) const
|
||||
{
|
||||
if (!CheckType(GetType(n), ELxLuaValueType::Boolean)) return false;
|
||||
if (!CheckType(GetType(n), ElxLuaValueType::Boolean)) return false;
|
||||
FlxStreamBuffer Decoder(Data[n]);
|
||||
return Decoder.read_bool();
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class ELxLuaValueType : uint8 {
|
||||
enum class ElxLuaValueType : uint8 {
|
||||
None,
|
||||
String,
|
||||
Name,
|
||||
@@ -105,7 +105,7 @@ private:
|
||||
|
||||
// For each chunk, the type of the chunk.
|
||||
//
|
||||
TArray<ELxLuaValueType> Types;
|
||||
TArray<ElxLuaValueType> Types;
|
||||
|
||||
// For each chunk, a pointer to the serialized data.
|
||||
//
|
||||
@@ -120,16 +120,21 @@ private:
|
||||
//
|
||||
void Empty();
|
||||
|
||||
// Compare two types. If they aren't equal, log an error and return false.
|
||||
//
|
||||
static bool CheckType(ElxLuaValueType Type, ElxLuaValueType Desired);
|
||||
|
||||
public:
|
||||
UlxLuaValues() { Cursor = 0; }
|
||||
|
||||
// Copies the data, and then preprocesses it to make sure
|
||||
// it's all valid. If it's not valid, returns false.
|
||||
//
|
||||
bool Initialize(std::string_view data);
|
||||
|
||||
// Compare two types. If they aren't equal, log an error and return false.
|
||||
//
|
||||
static bool CheckType(ELxLuaValueType Type, ELxLuaValueType Desired);
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
FString DebugString() const;
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
int Length() const { return Types.Num(); }
|
||||
|
||||
@@ -139,16 +144,17 @@ public:
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
||||
void SetCursor(int n) { Cursor = n; }
|
||||
|
||||
|
||||
private:
|
||||
//
|
||||
// Functions that get values from the array, random access.
|
||||
//
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
ELxLuaValueType GetType(int n) const;
|
||||
ElxLuaValueType GetType(int n) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
bool IsType(int n, ELxLuaValueType Type) const { return GetType(n) == Type; }
|
||||
bool IsType(int n, ElxLuaValueType Type) const { return GetType(n) == Type; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
FString GetString(int n) const;
|
||||
@@ -177,10 +183,10 @@ private:
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
ELxLuaValueType NextType() const { return GetType(Cursor); }
|
||||
ElxLuaValueType NextType() const { return GetType(Cursor); }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
bool IsNextType(ELxLuaValueType Type) const { return IsType(Cursor, Type); }
|
||||
bool IsNextType(ElxLuaValueType Type) const { return IsType(Cursor, Type); }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
||||
FString ReadString() { return GetString(Cursor++); }
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "TangibleManager.h"
|
||||
#include "LuprexGameModeBase.h"
|
||||
|
||||
#define DEFAULT_BLUEPRINT (TEXT("TangibleStaticMesh"))
|
||||
#define DEFAULT_BLUEPRINT (TEXT("StaticMesh"))
|
||||
|
||||
UlxTangible::UlxTangible()
|
||||
{
|
||||
@@ -24,17 +24,18 @@ void UlxTangible::Init(UlxTangibleManager* tm, int64 id)
|
||||
}
|
||||
|
||||
#pragma optimize("", off)
|
||||
void UlxTangible::SetActorBlueprint(const FString &name) {
|
||||
void UlxTangible::SetActorBlueprint(const FString &XName) {
|
||||
FString Name = XName.ToLower();
|
||||
|
||||
// If we're already of the right class, do nothing.
|
||||
if (ActorBlueprintName == name) {
|
||||
if (ActorBlueprintName == Name) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the blueprint.
|
||||
// If the blueprint doesn't exist, or doesn't implement
|
||||
// TangibleInterface, then use the fallback blueprint.
|
||||
UClass *blueprint = Manager->GetTangibleClass(name);
|
||||
if ((!name.IsEmpty()) && (blueprint == nullptr)) {
|
||||
UClass *blueprint = Manager->GetTangibleClass(Name);
|
||||
if (blueprint == nullptr)
|
||||
{
|
||||
blueprint = Manager->GetTangibleClass(DEFAULT_BLUEPRINT);
|
||||
check(blueprint != nullptr);
|
||||
}
|
||||
@@ -62,13 +63,16 @@ void UlxTangible::SetActorBlueprint(const FString &name) {
|
||||
}
|
||||
|
||||
// Update the blueprint name
|
||||
ActorBlueprintName = name;
|
||||
ActorBlueprintName = Name;
|
||||
|
||||
// Now create a new actor, unless the BP is nullptr.
|
||||
if (blueprint != nullptr) {
|
||||
UWorld* w = Manager->GetWorld();
|
||||
FActorSpawnParameters params;
|
||||
|
||||
// Give the new actor a reasonable name.
|
||||
params.Name = FName(*FString::Printf(TEXT("%s_%ld"), *Name, TangibleId));
|
||||
|
||||
// Currently, the actor is spawned at (0,0,0), which is not good.
|
||||
// We should spawn at the actor's current location. I'll get to it
|
||||
// eventually.
|
||||
@@ -86,6 +90,9 @@ void UlxTangible::SetActorBlueprint(const FString &name) {
|
||||
AActor* a = w->SpawnActor(blueprint, &transform, params);
|
||||
check(a != nullptr);
|
||||
|
||||
// Make sure the label and the name are the same.
|
||||
a->SetActorLabel(params.Name.ToString());
|
||||
|
||||
// Insert a TangibleComponent into the actor.
|
||||
// Link the actor to its tangible, and the tangible to its actor.
|
||||
UActorComponent* ac = a->AddComponentByClass(UlxTangibleComponent::StaticClass(), false, FTransform::Identity, false);
|
||||
|
||||
@@ -124,6 +124,7 @@ public:
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Set the actor's blueprint, and recreate the actor if necessary.
|
||||
//
|
||||
// If the blueprint is the empty string, deletes the actor.
|
||||
|
||||
@@ -3,11 +3,8 @@
|
||||
|
||||
#include "TangibleManager.h"
|
||||
#include "Tangible.h"
|
||||
#include "DebugPrint.h"
|
||||
#include "LuprexGameModeBase.h"
|
||||
|
||||
using namespace DebugPrint;
|
||||
|
||||
UFunction *UlxTangibleManager::GetAnimationQueueChanged(UClass *uclass) {
|
||||
UFunction *result = uclass->FindFunctionByName(FName(TEXT("Animation Queue Changed")));
|
||||
if (result == nullptr) return nullptr;
|
||||
@@ -16,6 +13,8 @@ UFunction *UlxTangibleManager::GetAnimationQueueChanged(UClass *uclass) {
|
||||
}
|
||||
|
||||
UClass *UlxTangibleManager::GetTangibleClass(const FString &name) {
|
||||
UPackage *Pack = LoadObject<UPackage>(nullptr, TEXT("/Game/Tangibles"));
|
||||
UE_LOG(LogBlueprint, Verbose, TEXT("Pack=%ld"), int64(Pack));
|
||||
if (name.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -24,8 +23,10 @@ UClass *UlxTangibleManager::GetTangibleClass(const FString &name) {
|
||||
}
|
||||
|
||||
FString path(TEXT("/Game/Tangibles/"));
|
||||
path += TEXT("Tan");
|
||||
path += name;
|
||||
path += TCHAR('.');
|
||||
path += TEXT("Tan");
|
||||
path += name;
|
||||
path += TCHAR('_');
|
||||
path += TCHAR('C');
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
#include "TriggeredTask.h"
|
||||
#include "DebugPrint.h"
|
||||
|
||||
using namespace DebugPrint;
|
||||
|
||||
FTriggeredTask::FTriggeredTask() {
|
||||
Client = nullptr;
|
||||
@@ -16,7 +13,6 @@ uint32 FTriggeredTask::Run() {
|
||||
{
|
||||
CallEvent->Wait();
|
||||
if (ThreadStopRequested) {
|
||||
DPrint("Thread stopping as requested");
|
||||
break;
|
||||
}
|
||||
// The payload.
|
||||
|
||||
Reference in New Issue
Block a user