diff --git a/Source/LuaMachine/Private/LuaState.cpp b/Source/LuaMachine/Private/LuaState.cpp index b0294322..2caaa6c5 100644 --- a/Source/LuaMachine/Private/LuaState.cpp +++ b/Source/LuaMachine/Private/LuaState.cpp @@ -296,6 +296,451 @@ FLuaValue ULuaState::GetLuaBlueprintPackageTable(const FString& PackageName) return LuaBlueprintPackages[PackageName]->SelfTable; } +FLuaValue ULuaState::LuaCreateTable() +{ + return CreateLuaTable(); +} + +FLuaValue ULuaState::LuaCreateThread(FLuaValue Value /* Function */) +{ + return CreateLuaThread(Value); +} + +FLuaValue ULuaState::LuaCreateObjectInState(UObject* InObject) +{ + FLuaValue LuaValue; + if (!InObject) + return LuaValue; + + LuaValue = FLuaValue(InObject); + LuaValue.LuaState = this; + return LuaValue; +} + +FLuaValue ULuaState::LuaGetGlobal(const FString& Name) +{ + uint32 ItemsToPop = GetFieldFromTree(Name); + FLuaValue ReturnValue = ToLuaValue(-1); + Pop(ItemsToPop); + return ReturnValue; +} + +void ULuaState::LuaSetGlobal(const FString& Name, FLuaValue Value) +{ + SetFieldFromTree(Name, Value, true); +} + +void ULuaState::LuaSetUserDataMetaTable(FLuaValue MetaTable) +{ + SetUserDataMetaTable(MetaTable); +} + +FLuaValue ULuaState::AssignLuaValueToLuaState(FLuaValue Value) +{ + Value.LuaState = this; + return Value; +} + +FLuaValue ULuaState::GetLuaComponentByStateAsLuaValue(AActor* Actor) +{ + if (!Actor) + return FLuaValue(); +#if ENGINE_MINOR_VERSION < 24 + TArray Components = Actor->GetComponentsByClass(ULuaComponent::StaticClass()); +#else + TArray Components; + Actor->GetComponents(Components); +#endif + for (UActorComponent* Component : Components) + { + ULuaComponent* LuaComponent = Cast(Component); + if (LuaComponent) + { + if (LuaComponent->LuaState == this->GetClass()) + { + return FLuaValue(LuaComponent); + } + } + } + + return FLuaValue(); +} + +FLuaValue ULuaState::GetLuaComponentByStateAndNameAsLuaValue(AActor* Actor, const FString& Name) +{ + if (!Actor) + return FLuaValue(); + +#if ENGINE_MINOR_VERSION < 24 + TArray Components = Actor->GetComponentsByClass(ULuaComponent::StaticClass()); +#else + TArray Components; + Actor->GetComponents(Components); +#endif + for (UActorComponent* Component : Components) + { + ULuaComponent* LuaComponent = Cast(Component); + if (LuaComponent) + { + if (LuaComponent->LuaState == this->GetClass() && LuaComponent->GetName() == Name) + { + return FLuaValue(LuaComponent); + } + } + } + + return FLuaValue(); +} + +FLuaValue ULuaState::LuaGlobalCall(const FString& Name, TArray Args) +{ + FLuaValue ReturnValue; + int32 ItemsToPop = GetFieldFromTree(Name); + + int NArgs = 0; + for (FLuaValue& Arg : Args) + { + FromLuaValue(Arg); + NArgs++; + } + + PCall(NArgs, ReturnValue); + + // we have the return value and the function has been removed, so we do not need to change ItemsToPop + Pop(ItemsToPop); + + return ReturnValue; +} + +TArray ULuaState::LuaGlobalCallMulti(const FString& Name, TArray Args) +{ + TArray ReturnValue; + + int32 ItemsToPop = GetFieldFromTree(Name); + + int32 StackTop = GetTop(); + + int NArgs = 0; + for (FLuaValue& Arg : Args) + { + FromLuaValue(Arg); + NArgs++; + } + + FLuaValue LastReturnValue; + if (PCall(NArgs, LastReturnValue, LUA_MULTRET)) + { + + int32 NumOfReturnValues = (GetTop() - StackTop) + 1; + if (NumOfReturnValues > 0) + { + for (int32 i = -1; i >= -(NumOfReturnValues); i--) + { + ReturnValue.Insert(ToLuaValue(i), 0); + } + Pop(NumOfReturnValues - 1); + } + + } + + // we have the return value and the function has been removed, so we do not need to change ItemsToPop + Pop(ItemsToPop); + + return ReturnValue; +} + +FLuaValue ULuaState::LuaGlobalCallValue(FLuaValue Value, TArray Args) +{ + FLuaValue ReturnValue; + + FromLuaValue(Value); + + int NArgs = 0; + for (FLuaValue& Arg : Args) + { + FromLuaValue(Arg); + NArgs++; + } + + PCall(NArgs, ReturnValue); + + Pop(); + + return ReturnValue; +} + +TArray ULuaState::LuaGlobalCallValueMulti(FLuaValue Value, TArray Args) +{ + TArray ReturnValue; + + FromLuaValue(Value); + + int32 StackTop = GetTop(); + + int NArgs = 0; + for (FLuaValue& Arg : Args) + { + FromLuaValue(Arg); + NArgs++; + } + + FLuaValue LastReturnValue; + if (PCall(NArgs, LastReturnValue, LUA_MULTRET)) + { + + int32 NumOfReturnValues = (GetTop() - StackTop) + 1; + if (NumOfReturnValues > 0) + { + for (int32 i = -1; i >= -(NumOfReturnValues); i--) + { + ReturnValue.Insert(ToLuaValue(i), 0); + } + Pop(NumOfReturnValues - 1); + } + + } + + Pop(); + + return ReturnValue; +} + +FLuaValue ULuaState::LuaTablePack(TArray Values) +{ + FLuaValue ReturnValue; + + ReturnValue = CreateLuaTable(); + + int32 Index = 1; + + for (FLuaValue& Value : Values) + { + ReturnValue.SetFieldByIndex(Index++, Value); + } + + return ReturnValue; +} + +FLuaValue ULuaState::LuaTableMergePack(TArray Values1, TArray Values2) +{ + FLuaValue ReturnValue; + + ReturnValue = CreateLuaTable(); + + int32 Index = 1; + + for (FLuaValue& Value : Values1) + { + ReturnValue.SetFieldByIndex(Index++, Value); + } + + for (FLuaValue& Value : Values2) + { + ReturnValue.SetFieldByIndex(Index++, Value); + } + + return ReturnValue; +} + +FLuaValue ULuaState::LuaTableFromMap(TMap Map) +{ + FLuaValue ReturnValue; + + ReturnValue = CreateLuaTable(); + + for (TPair& Pair : Map) + { + ReturnValue.SetField(Pair.Key, Pair.Value); + } + + return ReturnValue; +} + +bool ULuaState::LuaValueFromJson(const FString& Json, FLuaValue& Value) +{ + // default to nil + Value = FLuaValue(); + + TSharedPtr JsonValue; + TSharedRef< TJsonReader > JsonReader = TJsonReaderFactory::Create(Json); + if (!FJsonSerializer::Deserialize(JsonReader, JsonValue)) + { + return false; + } + + Value = FLuaValue::FromJsonValue(this, *JsonValue); + return true; +} + +int64 ULuaState::LuaValueToPointer(FLuaValue Value) +{ + FromLuaValue(Value); + const void* Ptr = ToPointer(-1); + Pop(); + + return (int64)Ptr; +} + +FString ULuaState::LuaValueToHexPointer(FLuaValue Value) +{ + int64 Ptr = LuaValueToPointer(Value); + if (FGenericPlatformProperties::IsLittleEndian()) + { + uint8 BEPtr[8] = + { + (uint8)((Ptr >> 56) & 0xff), + (uint8)((Ptr >> 48) & 0xff), + (uint8)((Ptr >> 40) & 0xff), + (uint8)((Ptr >> 32) & 0xff), + (uint8)((Ptr >> 24) & 0xff), + (uint8)((Ptr >> 16) & 0xff), + (uint8)((Ptr >> 8) & 0xff), + (uint8)((Ptr) & 0xff), + }; + return BytesToHex((const uint8*)BEPtr, sizeof(int64)); + } + return BytesToHex((const uint8*)&Ptr, sizeof(int64)); +} + +int32 ULuaState::LuaGetTop() +{ + return GetTop(); +} + +FLuaValue ULuaState::LuaRunFile(const FString& Filename, const bool bIgnoreNonExistent) +{ + FLuaValue ReturnValue; + + if (!RunFile(Filename, bIgnoreNonExistent, 1)) + { + if (bLogError) + LogError(LastError); + ReceiveLuaError(LastError); + } + else + { + ReturnValue = ToLuaValue(-1); + } + + Pop(); + return ReturnValue; +} + +FLuaValue ULuaState::LuaRunNonContentFile(const FString& Filename, const bool bIgnoreNonExistent) +{ + FLuaValue ReturnValue; + + if (!RunFile(Filename, bIgnoreNonExistent, 1, true)) + { + if (bLogError) + LogError(LastError); + ReceiveLuaError(LastError); + } + else + { + ReturnValue = ToLuaValue(-1); + } + + Pop(); + return ReturnValue; +} + +FLuaValue ULuaState::LuaRunCodeAsset(ULuaCode* CodeAsset) +{ + FLuaValue ReturnValue; + + if (!CodeAsset) + return ReturnValue; + + if (!RunCodeAsset(CodeAsset, 1)) + { + if (bLogError) + LogError(LastError); + ReceiveLuaError(LastError); + } + else { + ReturnValue = ToLuaValue(-1); + } + Pop(); + return ReturnValue; +} + +FLuaValue ULuaState::LuaRunByteCode(const TArray& ByteCode, const FString& CodePath) +{ + FLuaValue ReturnValue; + + if (!RunCode(ByteCode, CodePath, 1)) + { + if (bLogError) + LogError(LastError); + ReceiveLuaError(LastError); + } + else + { + ReturnValue = ToLuaValue(-1); + } + Pop(); + return ReturnValue; +} + +FLuaValue ULuaState::LuaRunString(const FString& CodeString, FString CodePath /*= ""*/) +{ + FLuaValue ReturnValue; + + if (CodePath.IsEmpty()) + { + CodePath = CodeString; + } + + if (!RunCode(CodeString, CodePath, 1)) + { + if (bLogError) + LogError(LastError); + ReceiveLuaError(LastError); + } + else + { + ReturnValue = ToLuaValue(-1); + } + Pop(); + return ReturnValue; +} + +FLuaValue ULuaState::LuaNewLuaUserDataObject(TSubclassOf UserDataObjectClass, bool bTrackObject /*= true*/) +{ + return NewLuaUserDataObject(UserDataObjectClass, bTrackObject); +} + +int32 ULuaState::LuaGetUsedMemory() +{ + return GC(LUA_GCCOUNT); +} + +void ULuaState::LuaGCCollect() +{ + GC(LUA_GCCOLLECT); +} + +void ULuaState::LuaGCStop() +{ + GC(LUA_GCSTOP); +} + +void ULuaState::LuaGCRestart() +{ + GC(LUA_GCRESTART); +} + +FLuaValue ULuaState::LuaTableAssetToLuaTable(ULuaTableAsset* TableAsset) +{ + return TableAsset->ToLuaTable(this); +} + +FLuaValue ULuaState::LuaCreateLazyTable() +{ + return CreateLuaLazyTable(); +} + bool ULuaState::RunCodeAsset(ULuaCode* CodeAsset, int NRet) { diff --git a/Source/LuaMachine/Private/LuaStateComponent.cpp b/Source/LuaMachine/Private/LuaStateComponent.cpp new file mode 100644 index 00000000..5d1c0bbd --- /dev/null +++ b/Source/LuaMachine/Private/LuaStateComponent.cpp @@ -0,0 +1,39 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "LuaStateComponent.h" + + +ULuaStateComponent::ULuaStateComponent() +{ + PrimaryComponentTick.bCanEverTick = true; +} + +ULuaState* ULuaStateComponent::GetLuaState() +{ + if (LuaState) + { + return LuaState; + } + + if (!LuaStateClass) + { + return nullptr; + } + + LuaState = NewObject(this, LuaStateClass); + LuaState->GetLuaState(GetWorld()); + LuaState->ReceiveLuaLevelAddedToWorld(GetOwner()->GetLevel(), GetWorld()); + return LuaState; +} + +void ULuaStateComponent::DestroyLuaState() +{ + if (LuaState) + { + LuaState->ReceiveLuaLevelRemovedFromWorld(GetOwner()->GetLevel(), GetWorld()); + LuaState->MarkPendingKill(); + LuaState = nullptr; + } +} + diff --git a/Source/LuaMachine/Public/LuaState.h b/Source/LuaMachine/Public/LuaState.h index e2d6de82..bb1a8f22 100644 --- a/Source/LuaMachine/Public/LuaState.h +++ b/Source/LuaMachine/Public/LuaState.h @@ -218,6 +218,102 @@ class LUAMACHINE_API ULuaState : public UObject UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Lua") FLuaValue GetLuaBlueprintPackageTable(const FString& PackageName); + UFUNCTION(BlueprintCallable, Category = "Lua") + FLuaValue LuaCreateTable(); + + UFUNCTION(BlueprintCallable, Category = "Lua") + FLuaValue LuaCreateThread(FLuaValue Value /* Function */); + + UFUNCTION(BlueprintCallable, Category = "Lua") + FLuaValue LuaCreateObjectInState(UObject* InObject); + + UFUNCTION(BlueprintCallable, Category = "Lua") + FLuaValue LuaGetGlobal(const FString& Name); + + UFUNCTION(BlueprintCallable, Category = "Lua") + void LuaSetGlobal(const FString& Name, FLuaValue Value); + + UFUNCTION(BlueprintCallable, Category = "Lua") + void LuaSetUserDataMetaTable(FLuaValue MetaTable); + + UFUNCTION(BlueprintCallable, Category = "Lua") + FLuaValue AssignLuaValueToLuaState(FLuaValue Value); + + UFUNCTION(BlueprintPure, Category = "Lua") + FLuaValue GetLuaComponentByStateAsLuaValue(AActor* Actor); + + UFUNCTION(BlueprintPure, Category = "Lua") + FLuaValue GetLuaComponentByStateAndNameAsLuaValue(AActor* Actor, const FString& Name); + + UFUNCTION(BlueprintCallable, meta = (AutoCreateRefTerm = "Args"), Category = "Lua") + FLuaValue LuaGlobalCall(const FString& Name, TArray Args); + + UFUNCTION(BlueprintCallable, meta = (AutoCreateRefTerm = "Args"), Category = "Lua") + TArray LuaGlobalCallMulti(const FString& Name, TArray Args); + + UFUNCTION(BlueprintCallable, meta = (AutoCreateRefTerm = "Args"), Category = "Lua") + FLuaValue LuaGlobalCallValue(FLuaValue Value, TArray Args); + + UFUNCTION(BlueprintCallable, meta = (AutoCreateRefTerm = "Args"), Category = "Lua") + TArray LuaGlobalCallValueMulti(FLuaValue Value, TArray Args); + + UFUNCTION(BlueprintCallable, Category = "Lua") + FLuaValue LuaTablePack(TArray Values); + + UFUNCTION(BlueprintCallable, Category = "Lua") + FLuaValue LuaTableMergePack(TArray Values1, TArray Values2); + + UFUNCTION(BlueprintCallable, Category = "Lua") + FLuaValue LuaTableFromMap(TMap Map); + + UFUNCTION(BlueprintCallable, Category = "Lua") + bool LuaValueFromJson(const FString& Json, FLuaValue& Value); + + UFUNCTION(BlueprintPure, Category = "Lua") + int64 LuaValueToPointer(FLuaValue Value); + + UFUNCTION(BlueprintPure, Category = "Lua") + FString LuaValueToHexPointer(FLuaValue Value); + + UFUNCTION(BlueprintPure, Category = "Lua") + int32 LuaGetTop(); + + UFUNCTION(BlueprintCallable, Category = "Lua") + FLuaValue LuaRunFile(const FString& Filename, const bool bIgnoreNonExistent); + + UFUNCTION(BlueprintCallable, Category = "Lua") + FLuaValue LuaRunNonContentFile(const FString& Filename, const bool bIgnoreNonExistent); + + UFUNCTION(BlueprintCallable, Category = "Lua") + FLuaValue LuaRunCodeAsset(ULuaCode* CodeAsset); + + UFUNCTION(BlueprintCallable, Category = "Lua") + FLuaValue LuaRunByteCode(const TArray& ByteCode, const FString& CodePath); + + UFUNCTION(BlueprintCallable, Category = "Lua") + FLuaValue LuaRunString(const FString& CodeString, FString CodePath = ""); + + UFUNCTION(BlueprintCallable, Category = "Lua") + FLuaValue LuaNewLuaUserDataObject(TSubclassOf UserDataObjectClass, bool bTrackObject = true); + + UFUNCTION(BlueprintPure, Category = "Lua") + int32 LuaGetUsedMemory(); + + UFUNCTION(BlueprintCallable, Category = "Lua") + void LuaGCCollect(); + + UFUNCTION(BlueprintCallable, Category = "Lua") + void LuaGCStop(); + + UFUNCTION(BlueprintCallable, Category = "Lua") + void LuaGCRestart(); + + UFUNCTION(BlueprintCallable, Category = "Lua") + FLuaValue LuaTableAssetToLuaTable(ULuaTableAsset* TableAsset); + + UFUNCTION(BlueprintCallable, Category = "Lua") + FLuaValue LuaCreateLazyTable(); + void FromLuaValue(FLuaValue& LuaValue, UObject* CallContext = nullptr, lua_State* State = nullptr); FLuaValue ToLuaValue(int Index, lua_State* State = nullptr); diff --git a/Source/LuaMachine/Public/LuaStateComponent.h b/Source/LuaMachine/Public/LuaStateComponent.h new file mode 100644 index 00000000..867d32d6 --- /dev/null +++ b/Source/LuaMachine/Public/LuaStateComponent.h @@ -0,0 +1,32 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Components/ActorComponent.h" +#include "LuaState.h" +#include "LuaStateComponent.generated.h" + + +UCLASS(BlueprintType, Blueprintable, ClassGroup=(Custom), meta=(BlueprintSpawnableComponent), DisplayName = "Lua State") +class LUAMACHINE_API ULuaStateComponent : public UActorComponent +{ + GENERATED_BODY() + +public: + ULuaStateComponent(); + + UFUNCTION(BlueprintPure, Category = "Reference") + ULuaState* GetLuaState(); + + UFUNCTION(BlueprintCallable, Category = "Reference") + void DestroyLuaState(); + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Config") + TSubclassOf LuaStateClass; + +private: + UPROPERTY() + ULuaState* LuaState; + +};