Lots of work on look-at widgets
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/Luprex/lxGameMode.uasset
LFS
BIN
Content/Luprex/lxGameMode.uasset
LFS
Binary file not shown.
Binary file not shown.
BIN
Content/Widgets/WB_Console.uasset
LFS
Normal file
BIN
Content/Widgets/WB_Console.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/Widgets/WB_Crosshair.uasset
LFS
Normal file
BIN
Content/Widgets/WB_Crosshair.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/Widgets/WB_Hotkeys.uasset
LFS
Normal file
BIN
Content/Widgets/WB_Hotkeys.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/Widgets/lxCrosshairImage.uasset
LFS
Normal file
BIN
Content/Widgets/lxCrosshairImage.uasset
LFS
Normal file
Binary file not shown.
@@ -4,6 +4,9 @@
|
||||
#include "AssetRegistry/AssetData.h"
|
||||
#include "AssetRegistry/AssetRegistryState.h"
|
||||
#include "LuprexGameModeBase.h"
|
||||
#include "Components/Widget.h"
|
||||
#include "WidgetBlueprint.h"
|
||||
#include "Blueprint/UserWidget.h"
|
||||
|
||||
void UlxAssetLookup::RebuildIndex()
|
||||
{
|
||||
@@ -12,6 +15,7 @@ void UlxAssetLookup::RebuildIndex()
|
||||
IAssetRegistry::GetChecked().WaitForCompletion();
|
||||
ScanTangibles();
|
||||
ScanStaticMeshes();
|
||||
ScanWidgets();
|
||||
}
|
||||
|
||||
void UlxAssetLookup::ScanTangibles()
|
||||
@@ -27,7 +31,7 @@ void UlxAssetLookup::ScanTangibles()
|
||||
UE_LOG(LogLuprexIntegration, Display, TEXT("Found %d assets in /Game/Tangibles"), FoundData.Num());
|
||||
for (const FAssetData &Data : FoundData)
|
||||
{
|
||||
FString Path = Data.GetObjectPathString();
|
||||
FString Path = Data.GetObjectPathString() + TEXT("_C");
|
||||
CachedTangibles.Add(Data.AssetName, Path);
|
||||
}
|
||||
}
|
||||
@@ -42,7 +46,7 @@ void UlxAssetLookup::ScanStaticMeshes()
|
||||
AssetFilter.bRecursivePaths = true;
|
||||
IAssetRegistry::GetChecked().GetAssets(AssetFilter, FoundData);
|
||||
|
||||
UE_LOG(LogLuprexIntegration, Display, TEXT("Found %d static mesh assets"), FoundData.Num());
|
||||
UE_LOG(LogLuprexIntegration, Display, TEXT("Found %d assets in /Game/StaticMeshes"), FoundData.Num());
|
||||
for (const FAssetData &Data : FoundData)
|
||||
{
|
||||
FString Path = Data.GetObjectPathString();
|
||||
@@ -50,10 +54,26 @@ void UlxAssetLookup::ScanStaticMeshes()
|
||||
}
|
||||
}
|
||||
|
||||
void UlxAssetLookup::ScanWidgets()
|
||||
{
|
||||
TArray<FAssetData> FoundData;
|
||||
FARFilter AssetFilter;
|
||||
AssetFilter.PackagePaths.Add(FName(TEXT("/Game/Widgets")));
|
||||
AssetFilter.ClassPaths.Add(UWidgetBlueprint::StaticClass()->GetClassPathName());
|
||||
AssetFilter.bIncludeOnlyOnDiskAssets = true;
|
||||
AssetFilter.bRecursivePaths = true;
|
||||
IAssetRegistry::GetChecked().GetAssets(AssetFilter, FoundData);
|
||||
|
||||
UE_LOG(LogLuprexIntegration, Display, TEXT("Found %d assets in /Game/Widgets"), FoundData.Num());
|
||||
for (const FAssetData &Data : FoundData)
|
||||
{
|
||||
FString Path = Data.GetObjectPathString() + TEXT("_C");
|
||||
CachedWidgets.Add(Data.AssetName, Path);
|
||||
}
|
||||
}
|
||||
|
||||
FString UlxAssetLookup::TangibleLoadPath(const FName &AssetName) const
|
||||
{
|
||||
FScopeLock lock(&Mutex);
|
||||
|
||||
const FString *Result = CachedTangibles.Find(AssetName);
|
||||
if (Result == nullptr) return TEXT("");
|
||||
return *Result;
|
||||
@@ -61,13 +81,18 @@ FString UlxAssetLookup::TangibleLoadPath(const FName &AssetName) const
|
||||
|
||||
FString UlxAssetLookup::StaticMeshLoadPath(const FName &AssetName) const
|
||||
{
|
||||
FScopeLock lock(&Mutex);
|
||||
|
||||
const FString *Result = CachedStaticMeshes.Find(AssetName);
|
||||
if (Result == nullptr) return TEXT("");
|
||||
return *Result;
|
||||
}
|
||||
|
||||
FString UlxAssetLookup::WidgetLoadPath(const FName &AssetName) const
|
||||
{
|
||||
const FString *Result = CachedWidgets.Find(AssetName);
|
||||
if (Result == nullptr) return TEXT("");
|
||||
return *Result;
|
||||
}
|
||||
|
||||
UStaticMesh *UlxAssetLookup::GetStaticMeshByName(const UObject *Context, const FString &Name)
|
||||
{
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context);
|
||||
@@ -77,18 +102,16 @@ UStaticMesh *UlxAssetLookup::GetStaticMeshByName(const UObject *Context, const F
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Static mesh not on search path: %s"), *Name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FString FullPath = Path;
|
||||
UStaticMesh *Result = LoadObject<UStaticMesh>(nullptr, *FullPath);
|
||||
UStaticMesh *Result = LoadObject<UStaticMesh>(nullptr, *Path);
|
||||
if (Result == nullptr) {
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Cannot load static mesh: %s"), *FullPath);
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Cannot load static mesh: %s"), *Path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
UClass *UlxAssetLookup::GetTangibleClassByName(const UObject *Context, const FString &Name) {
|
||||
TSubclassOf<AActor> UlxAssetLookup::GetTangibleClassByName(const UObject *Context, const FString &Name) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context);
|
||||
FString Path = mode->GetAssetLookup()->TangibleLoadPath(FName(FString("TAN_") + Name));
|
||||
if (Path.IsEmpty())
|
||||
@@ -96,21 +119,61 @@ UClass *UlxAssetLookup::GetTangibleClassByName(const UObject *Context, const FSt
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Tangible not on search path: %s"), *Name);
|
||||
return nullptr;
|
||||
}
|
||||
FString FullPath = Path + TEXT("_C");
|
||||
UClass *Result = LoadObject<UClass>(nullptr, *FullPath);
|
||||
UClass *Result = LoadObject<UClass>(nullptr, *Path);
|
||||
if (Result == nullptr) {
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Cannot load tangible class: %s"), *FullPath);
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Cannot load tangible class: %s"), *Path);
|
||||
return nullptr;
|
||||
}
|
||||
if (!Result->IsChildOf(AActor::StaticClass())) {
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Tangible class is not an actor: %s"), *FullPath);
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Tangible class is not an actor: %s"), *Path);
|
||||
return nullptr;
|
||||
}
|
||||
UFunction *aqchanged = Result->FindFunctionByName(FName(TEXT("Animation Queue Changed")));
|
||||
if ((aqchanged == nullptr)||(aqchanged->ParmsSize != 0))
|
||||
{
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Tangible does not have 'Animation Queue Changed' function: %s"), *FullPath);
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Tangible does not have 'Animation Queue Changed' function: %s"), *Path);
|
||||
return nullptr;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
TSubclassOf<UUserWidget> UlxAssetLookup::GetWidgetByName(const UObject *Context, const FString &Name) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context);
|
||||
FString Path = mode->GetAssetLookup()->WidgetLoadPath(FName(FString("WB_") + Name));
|
||||
if (Path.IsEmpty())
|
||||
{
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Widget not on search path: %s"), *Name);
|
||||
return nullptr;
|
||||
}
|
||||
UClass *Result = LoadObject<UClass>(nullptr, *Path);
|
||||
if (Result == nullptr) {
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Cannot load widget blueprint: %s"), *Path);
|
||||
return nullptr;
|
||||
}
|
||||
if (!Result->IsChildOf(UUserWidget::StaticClass())) {
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Blueprint is not a Widget Blueprint: %s"), *Path);
|
||||
return nullptr;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
TSubclassOf<UlxLookAtWidget> UlxAssetLookup::GetLookAtWidgetByName(const UObject *Context, const FString &Name) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context);
|
||||
FString Path = mode->GetAssetLookup()->WidgetLoadPath(FName(FString("WB_") + Name));
|
||||
if (Path.IsEmpty())
|
||||
{
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Widget not on search path: %s"), *Name);
|
||||
return nullptr;
|
||||
}
|
||||
UClass *Result = LoadObject<UClass>(nullptr, *Path);
|
||||
if (Result == nullptr) {
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Cannot load widget blueprint: %s"), *Path);
|
||||
return nullptr;
|
||||
}
|
||||
if (!Result->IsChildOf(UlxLookAtWidget::StaticClass())) {
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Blueprint is not a Luprex Look-At Widget: %s"), *Path);
|
||||
return nullptr;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,14 +6,17 @@
|
||||
#include "CommonTypes.h"
|
||||
#include "AssetLookup.generated.h"
|
||||
|
||||
class AActor;
|
||||
class UUserWidget;
|
||||
class UlxLookAtWidget;
|
||||
class UStaticMesh;
|
||||
|
||||
UCLASS(MinimalAPI)
|
||||
class UlxAssetLookup : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
private:
|
||||
mutable FCriticalSection Mutex;
|
||||
|
||||
// Map from asset name to full loadable path.
|
||||
UPROPERTY()
|
||||
TMap<FName, FString> CachedTangibles;
|
||||
@@ -22,22 +25,40 @@ private:
|
||||
UPROPERTY()
|
||||
TMap<FName, FString> CachedStaticMeshes;
|
||||
|
||||
public:
|
||||
void RebuildIndex();
|
||||
// Map from asset name to full loadable path.
|
||||
UPROPERTY()
|
||||
TMap<FName, FString> CachedWidgets;
|
||||
|
||||
private:
|
||||
void ScanTangibles();
|
||||
void ScanStaticMeshes();
|
||||
void ScanWidgets();
|
||||
|
||||
// Get the full path name of a
|
||||
public:
|
||||
void RebuildIndex();
|
||||
|
||||
// Get the full LoadObject path of a Tangible.
|
||||
FString TangibleLoadPath(const FName &AssetName) const;
|
||||
|
||||
// Get a static mesh by its asset name.
|
||||
// Get the full LoadObject path of a Static Mesh.
|
||||
FString StaticMeshLoadPath(const FName &AssetName) const;
|
||||
|
||||
// Get the full LoadObject path of a Widget Blueprint.
|
||||
FString WidgetLoadPath(const FName &AssetName) const;
|
||||
|
||||
// Get a static mesh by name
|
||||
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous")
|
||||
static UStaticMesh *GetStaticMeshByName(const UObject *Context, const FString &Name);
|
||||
|
||||
// Get a static mesh by name
|
||||
// Get a tangible class by name
|
||||
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous")
|
||||
static UClass *GetTangibleClassByName(const UObject *Context, const FString &Name);
|
||||
static TSubclassOf<AActor> GetTangibleClassByName(const UObject *Context, const FString &Name);
|
||||
|
||||
// Get a widget blueprint by name
|
||||
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous")
|
||||
static TSubclassOf<UUserWidget> GetWidgetByName(const UObject *Context, const FString &Name);
|
||||
|
||||
// Get a look-at widget blueprint by name
|
||||
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous")
|
||||
static TSubclassOf<UlxLookAtWidget> GetLookAtWidgetByName(const UObject *Context, const FString &Name);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
#include "BlueprintErrors.h"
|
||||
#include "StringDecoder.h"
|
||||
#include "LuaCall.h"
|
||||
#include "Internationalization/TextFormatter.h"
|
||||
#include "Kismet/KismetSystemLibrary.h"
|
||||
#include "Kismet2/KismetDebugUtilities.h"
|
||||
|
||||
@@ -25,6 +25,7 @@ public class Integration : ModuleRules
|
||||
"KismetWidgets",
|
||||
"BlueprintGraph",
|
||||
"UMG",
|
||||
"UMGEditor",
|
||||
});
|
||||
|
||||
// Uncomment if you are using Slate UI
|
||||
|
||||
@@ -5,15 +5,14 @@
|
||||
|
||||
#include "EdGraphSchema_K2.h"
|
||||
|
||||
static void FatalBlueprintError(const TCHAR *message) {
|
||||
FBlueprintExceptionInfo ExceptionInfo(EBlueprintExceptionType::FatalError, FText::FromString(FString(message)));
|
||||
FBlueprintCoreDelegates::ThrowScriptException(FFrame::GetThreadLocalTopStackFrame()->Object, *FFrame::GetThreadLocalTopStackFrame(), ExceptionInfo);
|
||||
}
|
||||
|
||||
static void CheckNotEmpty(const FlxStreamBuffer &sb) {
|
||||
if (sb.empty()) {
|
||||
FatalBlueprintError(TEXT("Must use LuaCallBegin before other LuaCall steps"));
|
||||
static bool NotInitialized(const FlxStreamBuffer &sb) {
|
||||
if (sb.empty())
|
||||
{
|
||||
UE_LOG(LogBlueprint, Error, TEXT("Must use LuaCallBegin before other LuaCall steps"));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static constexpr uint64_t ParseNameAsToken(std::string_view str) {
|
||||
@@ -219,8 +218,8 @@ void UlxLuaCallLibrary::LuaCallInvoke(UObject *context, AActor *place)
|
||||
{
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetBuffer();
|
||||
CheckNotEmpty(sb);
|
||||
mode->LuaCallEnd(InvocationKind::LUA_INVOKE, place);
|
||||
if (NotInitialized(sb)) return;
|
||||
mode->LuaCallEnd(InvocationKind::LUA_INVOKE, place);
|
||||
}
|
||||
|
||||
|
||||
@@ -228,7 +227,7 @@ void UlxLuaCallLibrary::LuaCallProbe(UObject *context, AActor *place)
|
||||
{
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetBuffer();
|
||||
CheckNotEmpty(sb);
|
||||
if (NotInitialized(sb)) return;
|
||||
mode->LuaCallEnd(InvocationKind::LUA_PROBE, place);
|
||||
}
|
||||
|
||||
@@ -254,7 +253,7 @@ UlxLuaValues *UlxLuaCallLibrary::LuaCallGetRest(UObject *context)
|
||||
void UlxLuaCallLibrary::LuaCallArgument_string(UObject *context, const FString &pstring) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetBuffer();
|
||||
CheckNotEmpty(sb);
|
||||
if (NotInitialized(sb)) return;
|
||||
sb.write_simple_dynamic_tag(SimpleDynamicTag::STRING);
|
||||
sb.write_string(pstring);
|
||||
}
|
||||
@@ -263,12 +262,13 @@ void UlxLuaCallLibrary::LuaCallArgument_name(UObject *context, const FName &pnam
|
||||
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"));
|
||||
if ((tokvalue == 0) && !namestr.empty())
|
||||
{
|
||||
UE_LOG(LogBlueprint, Error, TEXT("Names passed to lua must be short, and must contain only lowercase and digits"));
|
||||
}
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetBuffer();
|
||||
CheckNotEmpty(sb);
|
||||
if (NotInitialized(sb)) return;
|
||||
sb.write_simple_dynamic_tag(SimpleDynamicTag::TOKEN);
|
||||
sb.write_string(namestr);
|
||||
}
|
||||
@@ -276,7 +276,7 @@ void UlxLuaCallLibrary::LuaCallArgument_name(UObject *context, const FName &pnam
|
||||
void UlxLuaCallLibrary::LuaCallArgument_float(UObject *context, double pfloat) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetBuffer();
|
||||
CheckNotEmpty(sb);
|
||||
if (NotInitialized(sb)) return;
|
||||
sb.write_simple_dynamic_tag(SimpleDynamicTag::NUMBER);
|
||||
sb.write_double(pfloat);
|
||||
}
|
||||
@@ -284,7 +284,7 @@ void UlxLuaCallLibrary::LuaCallArgument_float(UObject *context, double pfloat) {
|
||||
void UlxLuaCallLibrary::LuaCallArgument_int(UObject *context, int value) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetBuffer();
|
||||
CheckNotEmpty(sb);
|
||||
if (NotInitialized(sb)) return;
|
||||
sb.write_simple_dynamic_tag(SimpleDynamicTag::NUMBER);
|
||||
sb.write_double(value);
|
||||
}
|
||||
@@ -292,7 +292,7 @@ void UlxLuaCallLibrary::LuaCallArgument_int(UObject *context, int value) {
|
||||
void UlxLuaCallLibrary::LuaCallArgument_vector(UObject *context, const FVector &pvector) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetBuffer();
|
||||
CheckNotEmpty(sb);
|
||||
if (NotInitialized(sb)) return;
|
||||
sb.write_simple_dynamic_tag(SimpleDynamicTag::VECTOR);
|
||||
sb.write_fvector(pvector);
|
||||
}
|
||||
@@ -300,7 +300,7 @@ void UlxLuaCallLibrary::LuaCallArgument_vector(UObject *context, const FVector &
|
||||
void UlxLuaCallLibrary::LuaCallArgument_vector2d(UObject *context, const FVector2D &pvector) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetBuffer();
|
||||
CheckNotEmpty(sb);
|
||||
if (NotInitialized(sb)) return;
|
||||
sb.write_simple_dynamic_tag(SimpleDynamicTag::VECTOR);
|
||||
sb.write_double(pvector.X);
|
||||
sb.write_double(pvector.Y);
|
||||
@@ -310,7 +310,7 @@ void UlxLuaCallLibrary::LuaCallArgument_vector2d(UObject *context, const FVector
|
||||
void UlxLuaCallLibrary::LuaCallArgument_boolean(UObject *context, bool pbool) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetBuffer();
|
||||
CheckNotEmpty(sb);
|
||||
if (NotInitialized(sb)) return;
|
||||
sb.write_simple_dynamic_tag(SimpleDynamicTag::BOOLEAN);
|
||||
sb.write_bool(pbool);
|
||||
}
|
||||
@@ -327,7 +327,11 @@ FString UlxLuaCallLibrary::LuaCallReturnValue_string(UObject *context) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetResult();
|
||||
SimpleDynamicTag tag = sb.read_simple_dynamic_tag();
|
||||
if (tag != SimpleDynamicTag::STRING) FatalBlueprintError(TEXT("expected lua to return a string"));
|
||||
if (tag != SimpleDynamicTag::STRING)
|
||||
{
|
||||
UE_LOG(LogBlueprint, Error, TEXT("expected lua to return a string"));
|
||||
return TEXT("");
|
||||
}
|
||||
return sb.read_fstring();
|
||||
}
|
||||
|
||||
@@ -335,7 +339,11 @@ FName UlxLuaCallLibrary::LuaCallReturnValue_name(UObject *context) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetResult();
|
||||
SimpleDynamicTag tag = sb.read_simple_dynamic_tag();
|
||||
if (tag != SimpleDynamicTag::TOKEN) FatalBlueprintError(TEXT("expected lua to return a name"));
|
||||
if (tag != SimpleDynamicTag::TOKEN)
|
||||
{
|
||||
UE_LOG(LogBlueprint, Error, TEXT("expected lua to return a name"));
|
||||
return FName();
|
||||
}
|
||||
return sb.read_fname();
|
||||
}
|
||||
|
||||
@@ -343,7 +351,11 @@ double UlxLuaCallLibrary::LuaCallReturnValue_float(UObject *context) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetResult();
|
||||
SimpleDynamicTag tag = sb.read_simple_dynamic_tag();
|
||||
if (tag != SimpleDynamicTag::NUMBER) FatalBlueprintError(TEXT("expected lua to return a float"));
|
||||
if (tag != SimpleDynamicTag::NUMBER)
|
||||
{
|
||||
UE_LOG(LogBlueprint, Error, TEXT("expected lua to return a float"));
|
||||
return 0.0;
|
||||
}
|
||||
return sb.read_double();
|
||||
}
|
||||
|
||||
@@ -351,7 +363,11 @@ int UlxLuaCallLibrary::LuaCallReturnValue_int(UObject *context) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetResult();
|
||||
SimpleDynamicTag tag = sb.read_simple_dynamic_tag();
|
||||
if (tag != SimpleDynamicTag::NUMBER) FatalBlueprintError(TEXT("expected lua to return a number"));
|
||||
if (tag != SimpleDynamicTag::NUMBER)
|
||||
{
|
||||
UE_LOG(LogBlueprint, Error, TEXT("expected lua to return a number"));
|
||||
return 0;
|
||||
}
|
||||
return int(sb.read_double());
|
||||
}
|
||||
|
||||
@@ -359,7 +375,11 @@ FVector UlxLuaCallLibrary::LuaCallReturnValue_vector(UObject *context) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetResult();
|
||||
SimpleDynamicTag tag = sb.read_simple_dynamic_tag();
|
||||
if (tag != SimpleDynamicTag::VECTOR) FatalBlueprintError(TEXT("expected lua to return a vector"));
|
||||
if (tag != SimpleDynamicTag::VECTOR)
|
||||
{
|
||||
UE_LOG(LogBlueprint, Error, TEXT("expected lua to return a vector"));
|
||||
return FVector();
|
||||
}
|
||||
return sb.read_fvector();
|
||||
}
|
||||
|
||||
@@ -367,8 +387,12 @@ FVector2D UlxLuaCallLibrary::LuaCallReturnValue_vector2d(UObject *context) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetResult();
|
||||
SimpleDynamicTag tag = sb.read_simple_dynamic_tag();
|
||||
if (tag != SimpleDynamicTag::VECTOR) FatalBlueprintError(TEXT("expected lua to return a vector"));
|
||||
FVector v = sb.read_fvector();
|
||||
if (tag != SimpleDynamicTag::VECTOR)
|
||||
{
|
||||
UE_LOG(LogBlueprint, Error, TEXT("expected lua to return a vector"));
|
||||
return FVector2D();
|
||||
}
|
||||
FVector v = sb.read_fvector();
|
||||
return FVector2D(v.X, v.Y);
|
||||
}
|
||||
|
||||
@@ -376,7 +400,169 @@ bool UlxLuaCallLibrary::LuaCallReturnValue_boolean(UObject *context) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(context);
|
||||
FlxStreamBuffer &sb = mode->LuaCallGetResult();
|
||||
SimpleDynamicTag tag = sb.read_simple_dynamic_tag();
|
||||
if (tag != SimpleDynamicTag::BOOLEAN) FatalBlueprintError(TEXT("expected lua to return a boolean"));
|
||||
return sb.read_bool();
|
||||
if (tag != SimpleDynamicTag::BOOLEAN)
|
||||
{
|
||||
UE_LOG(LogBlueprint, Error, TEXT("expected lua to return a boolean"));
|
||||
return false;
|
||||
}
|
||||
return sb.read_bool();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Returning the rest of the lua return values as an array.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void UlxLuaValues::Empty()
|
||||
{
|
||||
Serialized.clear();
|
||||
Types.Empty();
|
||||
Data.Empty();
|
||||
Cursor = 0;
|
||||
}
|
||||
|
||||
bool UlxLuaValues::Initialize(std::string_view data)
|
||||
{
|
||||
Empty();
|
||||
Serialized = data;
|
||||
const char *SerializedChar = &Serialized[0];
|
||||
|
||||
FlxStreamBuffer Decoder(Serialized);
|
||||
|
||||
while (!Decoder.empty())
|
||||
{
|
||||
SimpleDynamicTag Tag = Decoder.read_simple_dynamic_tag();
|
||||
|
||||
int64 Pos = Decoder.total_reads();
|
||||
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;
|
||||
default: {
|
||||
Empty();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int64 Pos2 = Decoder.total_reads();
|
||||
Types.Add(Type);
|
||||
Data.Add(std::string_view(SerializedChar + Pos, Pos2 - Pos));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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();
|
||||
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
|
||||
{
|
||||
if (n < 0) return ElxLuaValueType::None;
|
||||
if (n >= Types.Num()) return ElxLuaValueType::None;
|
||||
return Types[Cursor];
|
||||
}
|
||||
|
||||
//
|
||||
// Get the Nth value in the array. Array bounds-checking
|
||||
// is handled by 'GetType', which returns 'None' for out-of-bounds
|
||||
// accesses.
|
||||
//
|
||||
|
||||
FString UlxLuaValues::GetString(int n) const
|
||||
{
|
||||
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();
|
||||
FlxStreamBuffer Decoder(Data[n]);
|
||||
return Decoder.read_fname();
|
||||
}
|
||||
|
||||
double UlxLuaValues::GetFloat(int n) const
|
||||
{
|
||||
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;
|
||||
FlxStreamBuffer Decoder(Data[n]);
|
||||
return int(Decoder.read_double());
|
||||
}
|
||||
|
||||
FVector UlxLuaValues::GetVector(int n) const
|
||||
{
|
||||
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();
|
||||
FlxStreamBuffer Decoder(Data[n]);
|
||||
FVector v = Decoder.read_fvector();
|
||||
return FVector2D(v.X, v.Y);
|
||||
}
|
||||
|
||||
bool UlxLuaValues::GetBoolean(int n) const
|
||||
{
|
||||
if (!CheckType(GetType(n), ElxLuaValueType::Boolean)) return false;
|
||||
FlxStreamBuffer Decoder(Data[n]);
|
||||
return Decoder.read_bool();
|
||||
}
|
||||
|
||||
|
||||
@@ -176,3 +176,145 @@ public:
|
||||
};
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// These are the types that can actually be packed into
|
||||
// a serialized buffer.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class ElxLuaValueType : uint8 {
|
||||
None,
|
||||
String,
|
||||
Name,
|
||||
Float,
|
||||
Boolean,
|
||||
Vector
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// This class stores an array of values that were returned by Lua.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class INTEGRATION_API UlxLuaValues : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
private:
|
||||
// The raw serialized data returned by Lua.
|
||||
//
|
||||
std::string Serialized;
|
||||
|
||||
// For each chunk, the type of the chunk.
|
||||
//
|
||||
TArray<ElxLuaValueType> Types;
|
||||
|
||||
// For each chunk, a pointer to the serialized data.
|
||||
//
|
||||
TArray<std::string_view> Data;
|
||||
|
||||
// The current cursor.
|
||||
//
|
||||
int Cursor;
|
||||
|
||||
private:
|
||||
// Clear everything.
|
||||
//
|
||||
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);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
FString DebugString() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
int Length() const { return Types.Num(); }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
int GetCursor() const { return Cursor; }
|
||||
|
||||
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;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
bool IsType(int n, ElxLuaValueType Type) const { return GetType(n) == Type; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
FString GetString(int n) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
FName GetName(int n) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
double GetFloat(int n) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
int GetInt(int n) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
FVector GetVector(int n) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
FVector2D GetVector2D(int n) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
bool GetBoolean(int n) const;
|
||||
|
||||
//
|
||||
// Functions that get values from the array using the cursor.
|
||||
//
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
ElxLuaValueType NextType() const { return GetType(Cursor); }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
bool IsNextType(ElxLuaValueType Type) const { return IsType(Cursor, Type); }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
||||
FString ReadString() { return GetString(Cursor++); }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
||||
FName ReadName() { return GetName(Cursor++); }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
||||
double ReadFloat() { return GetFloat(Cursor++); }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
||||
int ReadInt() { return GetInt(Cursor++); }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
||||
FVector ReadVector() { return GetVector(Cursor++); }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
||||
FVector2D ReadVector2D() { return GetVector2D(Cursor++); }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
||||
bool ReadBoolean() { return GetBoolean(Cursor++); }
|
||||
};
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Tangible.h"
|
||||
#include "TangibleManager.h"
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
|
||||
#include "CommonTypes.h"
|
||||
#include "AnimQueue.h"
|
||||
@@ -355,21 +356,46 @@ void ALuprexGameModeBase::ClearLookAtWidget(const UObject *Context)
|
||||
}
|
||||
}
|
||||
|
||||
void ALuprexGameModeBase::SetLookAtWidget(const UObject *Context, UUserWidget *Widget, int ZOrder)
|
||||
void ALuprexGameModeBase::SetLookAtWidget(const UObject *Context, UlxLookAtWidget *Widget)
|
||||
{
|
||||
ALuprexGameModeBase *Mode = FromContext(Context);
|
||||
if (Mode->LookAtWidget != Widget)
|
||||
{
|
||||
ClearLookAtWidget(Context);
|
||||
}
|
||||
if (Widget != nullptr)
|
||||
if (!Widget->IsInViewport())
|
||||
{
|
||||
Widget->RemoveFromParent();
|
||||
Widget->AddToViewport(ZOrder);
|
||||
Widget->AddToViewport(100);
|
||||
}
|
||||
Mode->LookAtWidget = Widget;
|
||||
}
|
||||
|
||||
void ALuprexGameModeBase::SetLookAt(const UObject *Context, const FHitResult &HitResult)
|
||||
{
|
||||
ALuprexGameModeBase *Mode = FromContext(Context);
|
||||
Mode->CurrentLookAt = HitResult;
|
||||
}
|
||||
|
||||
FVector2D ALuprexGameModeBase::GetLookAtPixel(const UObject *Context)
|
||||
{
|
||||
ALuprexGameModeBase *Mode = FromContext(Context);
|
||||
APlayerController *pc = Context->GetWorld()->GetFirstPlayerController();
|
||||
if (pc == nullptr) return FVector2D();
|
||||
FVector2D ScreenPosition;
|
||||
UGameplayStatics::ProjectWorldToScreen(pc, Mode->CurrentLookAt.Location, ScreenPosition, false);
|
||||
return ScreenPosition;
|
||||
}
|
||||
|
||||
FVector2D ALuprexGameModeBase::GetPreviousLookAtPixel(const UObject *Context)
|
||||
{
|
||||
ALuprexGameModeBase *Mode = FromContext(Context);
|
||||
APlayerController *pc = Context->GetWorld()->GetFirstPlayerController();
|
||||
if (pc == nullptr) return FVector2D();
|
||||
FVector2D ScreenPosition;
|
||||
UGameplayStatics::ProjectWorldToScreen(pc, Mode->PreviousLookAt.Location, ScreenPosition, false);
|
||||
return ScreenPosition;
|
||||
}
|
||||
|
||||
void ALuprexGameModeBase::UpdateLookAt() {
|
||||
// Rotate the variables.
|
||||
PreviousLookAt = CurrentLookAt;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "LuprexSockets.h"
|
||||
#include "TriggeredTask.h"
|
||||
#include "BlueprintErrors.h"
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "LuprexGameModeBase.generated.h"
|
||||
|
||||
// Messages that come from inside the Luprex Core.
|
||||
@@ -20,12 +21,23 @@ DECLARE_LOG_CATEGORY_EXTERN(LogLuprex, Display, All);
|
||||
// Messages that pertain to our Luprex integration with Unreal.
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogLuprexIntegration, Display, All);
|
||||
|
||||
class LookAtDetector;
|
||||
class UlxLuaValues;
|
||||
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class INTEGRATION_API UlxLookAtWidget : public UUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "Luprex|Look-At Detection")
|
||||
void ReadLuaConfiguration(AActor *Place, UlxLuaValues *Config);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
UCLASS(BlueprintType)
|
||||
class INTEGRATION_API ALuprexGameModeBase : public AGameModeBase, public FRunnable
|
||||
{
|
||||
GENERATED_BODY()
|
||||
@@ -56,7 +68,7 @@ public:
|
||||
int64 GetPlayerId();
|
||||
|
||||
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context"), Category = "Luprex|Look-At Detection")
|
||||
static void SetLookAt(const UObject *Context, const FHitResult &hit) { FromContext(Context)->CurrentLookAt = hit; }
|
||||
static void SetLookAt(const UObject *Context, const FHitResult &HitResult);
|
||||
|
||||
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"),Category = "Luprex|Look-At Detection")
|
||||
static const FHitResult &GetLookAt(const UObject *Context) { return FromContext(Context)->CurrentLookAt; }
|
||||
@@ -64,20 +76,26 @@ public:
|
||||
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"),Category = "Luprex|Look-At Detection")
|
||||
static const AActor *GetLookAtActor(const UObject *Context) { return FromContext(Context)->CurrentLookAt.GetActor(); }
|
||||
|
||||
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"),Category = "Luprex|Look-At Detection")
|
||||
static FVector2D GetLookAtPixel(const UObject *Context);
|
||||
|
||||
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"),Category = "Luprex|Look-At Detection")
|
||||
static const FHitResult &GetPreviousLookAt(const UObject *Context) { return FromContext(Context)->PreviousLookAt; }
|
||||
|
||||
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"),Category = "Luprex|Look-At Detection")
|
||||
static const AActor *GetPreviousLookAtActor(const UObject *Context) { return FromContext(Context)->PreviousLookAt.GetActor(); }
|
||||
|
||||
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"),Category = "Luprex|Look-At Detection")
|
||||
static FVector2D GetPreviousLookAtPixel(const UObject *Context);
|
||||
|
||||
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"),Category = "Luprex|Look-At Detection")
|
||||
static bool IsLookAtChanged(const UObject *Context);
|
||||
|
||||
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context"), Category = "Luprex|Look-At Detection")
|
||||
static void SetLookAtWidget(const UObject *Context, UUserWidget *Widget, int ZOrder = 100);
|
||||
static void SetLookAtWidget(const UObject *Context, UlxLookAtWidget *Widget);
|
||||
|
||||
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context"), Category = "Luprex|Look-At Detection")
|
||||
static UUserWidget *GetLookAtWidget(const UObject *Context) { return FromContext(Context)->LookAtWidget; }
|
||||
static UlxLookAtWidget *GetLookAtWidget(const UObject *Context) { return FromContext(Context)->LookAtWidget; }
|
||||
|
||||
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context"), Category = "Luprex|Look-At Detection")
|
||||
static void ClearLookAtWidget(const UObject *Context);
|
||||
@@ -160,7 +178,7 @@ public:
|
||||
FHitResult CurrentLookAt;
|
||||
|
||||
UPROPERTY()
|
||||
UUserWidget *LookAtWidget;
|
||||
UlxLookAtWidget *LookAtWidget;
|
||||
|
||||
// The sensitivity level at which a log message triggers a debugger breakpoint.
|
||||
UPROPERTY(EditAnywhere, Category="Debugging Tools")
|
||||
|
||||
@@ -1,154 +1,3 @@
|
||||
#include "StringDecoder.h"
|
||||
|
||||
|
||||
void UlxLuaValues::Empty()
|
||||
{
|
||||
Serialized.clear();
|
||||
Types.Empty();
|
||||
Data.Empty();
|
||||
Cursor = 0;
|
||||
}
|
||||
|
||||
bool UlxLuaValues::Initialize(std::string_view data)
|
||||
{
|
||||
Empty();
|
||||
Serialized = data;
|
||||
const char *SerializedChar = &Serialized[0];
|
||||
|
||||
FlxStreamBuffer Decoder(Serialized);
|
||||
|
||||
while (!Decoder.empty())
|
||||
{
|
||||
SimpleDynamicTag Tag = Decoder.read_simple_dynamic_tag();
|
||||
|
||||
int64 Pos = Decoder.total_reads();
|
||||
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;
|
||||
default: {
|
||||
Empty();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int64 Pos2 = Decoder.total_reads();
|
||||
Types.Add(Type);
|
||||
Data.Add(std::string_view(SerializedChar + Pos, Pos2 - Pos));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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();
|
||||
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
|
||||
{
|
||||
if (n < 0) return ElxLuaValueType::None;
|
||||
if (n >= Types.Num()) return ElxLuaValueType::None;
|
||||
return Types[Cursor];
|
||||
}
|
||||
|
||||
//
|
||||
// Get the Nth value in the array. Array bounds-checking
|
||||
// is handled by 'GetType', which returns 'None' for out-of-bounds
|
||||
// accesses.
|
||||
//
|
||||
|
||||
FString UlxLuaValues::GetString(int n) const
|
||||
{
|
||||
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();
|
||||
FlxStreamBuffer Decoder(Data[n]);
|
||||
return Decoder.read_fname();
|
||||
}
|
||||
|
||||
double UlxLuaValues::GetFloat(int n) const
|
||||
{
|
||||
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;
|
||||
FlxStreamBuffer Decoder(Data[n]);
|
||||
return int(Decoder.read_double());
|
||||
}
|
||||
|
||||
FVector UlxLuaValues::GetVector(int n) const
|
||||
{
|
||||
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();
|
||||
FlxStreamBuffer Decoder(Data[n]);
|
||||
FVector v = Decoder.read_fvector();
|
||||
return FVector2D(v.X, v.Y);
|
||||
}
|
||||
|
||||
bool UlxLuaValues::GetBoolean(int n) const
|
||||
{
|
||||
if (!CheckType(GetType(n), ElxLuaValueType::Boolean)) return false;
|
||||
FlxStreamBuffer Decoder(Data[n]);
|
||||
return Decoder.read_bool();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
#include "CoreMinimal.h"
|
||||
#include "lpx-basebuffer.hpp"
|
||||
|
||||
#include "StringDecoder.generated.h"
|
||||
|
||||
class FlxStreamBufferCore {
|
||||
private:
|
||||
bool err_eof_on_read_;
|
||||
@@ -68,144 +66,3 @@ public:
|
||||
return FName(s.size(), (const UTF8CHAR *)s.data(), FNAME_Add);
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// These are the types that can actually be packed into
|
||||
// a serialized buffer.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class ElxLuaValueType : uint8 {
|
||||
None,
|
||||
String,
|
||||
Name,
|
||||
Float,
|
||||
Boolean,
|
||||
Vector
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// This class stores an array of values that were returned by Lua.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
UCLASS(MinimalAPI)
|
||||
class UlxLuaValues : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
private:
|
||||
// The raw serialized data returned by Lua.
|
||||
//
|
||||
std::string Serialized;
|
||||
|
||||
// For each chunk, the type of the chunk.
|
||||
//
|
||||
TArray<ElxLuaValueType> Types;
|
||||
|
||||
// For each chunk, a pointer to the serialized data.
|
||||
//
|
||||
TArray<std::string_view> Data;
|
||||
|
||||
// The current cursor.
|
||||
//
|
||||
int Cursor;
|
||||
|
||||
private:
|
||||
// Clear everything.
|
||||
//
|
||||
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);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
FString DebugString() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
int Length() const { return Types.Num(); }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
int GetCursor() const { return Cursor; }
|
||||
|
||||
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;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
bool IsType(int n, ElxLuaValueType Type) const { return GetType(n) == Type; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
FString GetString(int n) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
FName GetName(int n) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
double GetFloat(int n) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
int GetInt(int n) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
FVector GetVector(int n) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
FVector2D GetVector2D(int n) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
bool GetBoolean(int n) const;
|
||||
|
||||
//
|
||||
// Functions that get values from the array using the cursor.
|
||||
//
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
ElxLuaValueType NextType() const { return GetType(Cursor); }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Luprex|Lua Value Array")
|
||||
bool IsNextType(ElxLuaValueType Type) const { return IsType(Cursor, Type); }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
||||
FString ReadString() { return GetString(Cursor++); }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
||||
FName ReadName() { return GetName(Cursor++); }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
||||
double ReadFloat() { return GetFloat(Cursor++); }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
||||
int ReadInt() { return GetInt(Cursor++); }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
||||
FVector ReadVector() { return GetVector(Cursor++); }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
||||
FVector2D ReadVector2D() { return GetVector2D(Cursor++); }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Lua Value Array")
|
||||
bool ReadBoolean() { return GetBoolean(Cursor++); }
|
||||
};
|
||||
@@ -77,6 +77,9 @@ public:
|
||||
// Be aware that (0.0, 0.0) is the upper-left corner of the upper-left pixel,
|
||||
// whereas (0.5, 0.5) is the center of the upper-left pixel.
|
||||
//
|
||||
// The resulting TraceStart and TraceEnd fields of the HitResult will not
|
||||
// contain world positions, instead, they will contain the PixelXY.
|
||||
//
|
||||
UFUNCTION(BlueprintCallable, Category="Collision", meta=(AutoCreateRefTerm="ActorsToIgnore", Keywords="raycast"))
|
||||
static bool LineTraceThroughPixel(const APlayerController* PlayerController,
|
||||
FVector2D PixelXY, double MaxDistanceFromCamera,
|
||||
|
||||
@@ -417,7 +417,7 @@ eng::string World::probe_lua_expr(int64_t actor_id, std::string_view lua) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void World::probe_lua_call(int64_t place_id, int64_t actor_id, std::string_view datapack, StreamBuffer *retvals) {
|
||||
void World::probe_lua_call(int64_t actor_id, int64_t place_id, std::string_view datapack, StreamBuffer *retvals) {
|
||||
assert(stack_is_clear());
|
||||
lua_State *L = state();
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@ public:
|
||||
// Print statements are discarded. The lua function may return a vector
|
||||
// of values. If so, the values are packed into a StreamBuffer.
|
||||
//
|
||||
void probe_lua_call(int64_t place_id, int64_t actor_id, std::string_view datapack, StreamBuffer *retvals);
|
||||
void probe_lua_call(int64_t actor_id, int64_t place_id, std::string_view datapack, StreamBuffer *retvals);
|
||||
|
||||
// Invoke an Invocation object.
|
||||
//
|
||||
|
||||
@@ -18,11 +18,17 @@ function engio.move(action, xyz, facing)
|
||||
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)
|
||||
function cube.getlookat()
|
||||
return { "Hotkeys", "X", "I Am a Cube" }
|
||||
end
|
||||
|
||||
function engio.retmany()
|
||||
return 7, vec(8,9,10), "Yo", "Banana", 13.2, vec(2,3,4), "Hi"
|
||||
function sphere.getlookat()
|
||||
return { "Hotkeys", "X", "I Am a Sphere" }
|
||||
end
|
||||
|
||||
function engio.getlookat()
|
||||
local place = tangible.place()
|
||||
local class = tangible.getclass(place)
|
||||
return class.getlookat()
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user