include ../unreal/prelude
import ../codegen/[modelconstructor, ueemit, uebind, models, uemeta, umacros]
import std/[json, strformat, jsonutils, sequtils, options, sugar, enumerate, strutils, tables]
import ../vm/[runtimefield, uecall]
import ../unreal/nimforue/nimforuebindings
#Primero coger el parametro.
#Luego devolverlo en el out
uprops(EditAnywhere, BlueprintReadWrite):
uClass UObjectPOC of UObject:
(BlueprintType, Reinstance)
UE_Log "Hola from UObjectPOC instanceFunc"
proc instanceFuncWithOneArgAndReturnTest(arg : int) : FVector = FVector(x:arg.float32, y:arg.float32, z:arg.float32)
proc callWithOutArg(res: var int) : int =
UE_Log &"Inside callWithOutArg {res}"
proc callWithOutHitArg(res: var FHitResult) =
proc callFuncWithNoArg() =
UE_Log "Hola from UObjectPOC"
proc callFuncWithOneIntArg(arg : int) =
UE_Log "Hola from UObjectPOC with arg: " & $arg
proc callFuncWithOneStrArg(arg : FString) =
UE_Log "Hola from UObjectPOC with arg: " & $arg
proc callFuncWithTwoIntArg(arg1 : int, arg2 : int) =
UE_Log "Hola from UObjectPOC with arg1: " & $arg1 & " and arg2: " & $arg2
proc callFuncWithTwoStrArg(arg1 : FString, arg2 : FString) =
UE_Log "Hola from UObjectPOC with arg1: " & $arg1 & " and arg2: " & $arg2
proc callFuncWithInt32Int64Arg(arg1 : int32, arg2 : int64) =
UE_Log "Hola from UObjectPOC with arg1: " & $arg1 & " and arg2: " & $arg2
proc saluteWitthTwoDifferentIntSizes2(arg1 : int64, arg2 : int32) =
UE_Log "Hola from UObjectPOC with arg1: " & $arg1 & " and arg2: " & $arg2
proc callFuncWithOneObjPtrArg(obj:UObjectPtr) =
UE_Log "Object name: " & $obj.getName()
proc callFuncWithObjPtrStrArg(obj:UObjectPtr, salute : FString) =
UE_Log "Object name: " & $obj.getName() & " Salute: " & $salute
proc callFuncWithObjPtrArgReturnInt(obj:UObjectPtr) : int =
UE_Log "Object name: " & $obj.getName()
UE_Log "Object addr: " & $cast[int](obj)
proc callFuncWithObjPtrArgReturnObjPtr(obj:UObjectPtr) : UObjectPtr =
UE_Log "Object name: " & $obj.getName()
proc callFuncWithObjPtrArgReturnStr(obj:UObjectPtr) : FString =
let str = "Object name: " & $obj.getName()
proc callFuncWithOneFVectorArg(vec : FVector) =
proc callFuncWithOneArrayIntArg(ints : TArray[int]) =
UE_Log "Int array length: " & $ints.len
proc callFuncWithOneArrayVectorArg(vecs : TArray[FVector]) =
UE_Log "Vector array length: " & $vecs.len
proc callThatReturnsArrayInt() : TArray[int] = makeTArray(1, 2, 3, 4, 5)
proc receiveFloat32(arg : float32) = #: float32 =
UE_Log "Float32: " & $arg
proc receiveFloat64(arg : float) =
UE_Log "Float64: " & $arg
proc receiveVectorAndFloat32(dir:FVector, scale:float32) =
UE_Error "receiveVectorAndFloat32 " & $dir & " scale:" & $scale
proc callFuncWithOneFVectorArgReturnFVector(vec : FVector) : FVector =
proc callFuncWithOneFVectorArgReturnFRotator(vec : FVector) : FRotator =
FRotator(pitch:vec.x, yaw:vec.y, roll:vec.z)
1. [x] Create a function that makes a call by fn name
2. [x] Create a function that makes a call by fn name and pass a value argument
2.1 [x] Create a function that makes a call by fn name and pass a two values of the same types as argument
2.2 [x] Create a function that makes a call by fn name and pass a two values of different types as argument
2.3 [x] Pass a int32 and a int64
3. [x] Create a function that makes a call by fn name and pass a pointer argument
4. [x] Create a function that makes a call by fn name and pass a value and pointer argument
5. [x] Create a function that makes a call by fn name and pass a value and pointer argument and return a value
6. [x] Create a function that makes a call by fn name and pass a value and pointer argument and return a pointer
6.1 [x] Create a function that makes a call by fn name and pass a value and pointer argument and returns a string
7. [ ] Repeat 1-6 where value arguments are complex types
8. [ ] Add support for missing basic types
# proc registerVmTests*() =
# unregisterAllNimTests()
# ueTest "should create a ":
# ueTest "another create a test2":
#maybe the way to go is by raising. Let's do a test to see if we can catch the errors in the actual actor
#Later on this can be an uobject that pulls and the actor will just run them. But this is fine as started point
uClass ANimTestBase of AActor:
self.printSucceed = false
#Traverse all the tests and run them. A test is a function that starts with "test" or "should
it.getName().tolower.startsWith("test") or
it.getName().tolower.startsWith("should"))
UE_Log "Running test: " & $fn.getName()
self.processEvent(fn, nil)
self.printSucceed = false
except CatchableError as e:
UE_Error "Error in test: " & $fn.getName() & " " & $e.msg
self.printSucceed = false
uClass AActorPOCVMTest of ANimTestBase:
proc testCallFuncWithNoArg() =
let callData = UECall(kind: uecFunc, fn: makeUEFunc("callFuncWithNoArg", "UObjectPOC"))
proc testCallWithOutArg() =
fn: makeUEFunc("callWithOutArg", "UObjectPOC"),
value: (res: 1).toRuntimeField()
let res = uCall(callData)
proc testCallWithOutHitArg() =
fn: makeUEFunc("callWithOutHitArg", "UObjectPOC"),
value: (res: hit).toRuntimeField()
let res = uCall(callData)
# discard callWithOutArg(1, test, 2)
# UE_Log "the value afterwards is " & $test
proc testCallFuncWithOneIntArg() =
fn: makeUEFunc("callFuncWithOneIntArg", "UObjectPOC"),
value: (arg: 10).toRuntimeField()
proc testCallFuncWithOneStrArg() =
fn: makeUEFunc("callFuncWithOneStrArg", "UObjectPOC"),
value: (arg: "10 cadena").toRuntimeField()
proc testCallFuncWithTwoStrArg() =
fn: makeUEFunc("callFuncWithTwoStrArg", "UObjectPOC"),
value: (arg1: "10 cadena", arg2: "Hola").toRuntimeField()
proc testCallFuncWithTwoIntArg() =
fn: makeUEFunc("callFuncWithTwoIntArg", "UObjectPOC"),
value: (arg1: 10, arg2: 10).toRuntimeField()
proc testCallFuncWithInt32Int64Arg() =
fn: makeUEFunc("callFuncWithInt32Int64Arg", "UObjectPOC"),
value: (arg1: 15, arg2: 10).toRuntimeField()
proc testCallFuncWithOneObjPtrArg() =
fn: makeUEFunc("callFuncWithOneObjPtrArg", "UObjectPOC"),
value: (obj: cast[int](self)).toRuntimeField()
proc testCallFuncWithObjPtrStrArg() =
fn: makeUEFunc("callFuncWithObjPtrStrArg", "UObjectPOC"),
value: (obj: cast[int](self), salute: "Hola").toRuntimeField()
proc testCallFuncWithObjPtrArgReturnInt() =
fn: makeUEFunc("callFuncWithObjPtrArgReturnInt", "UObjectPOC"),
value: (obj: cast[int](self)).toRuntimeField()
proc testCallFuncWithObjPtrArgReturnObjPtr() =
fn: makeUEFunc("callFuncWithObjPtrArgReturnObjPtr", "UObjectPOC"),
value: (obj: cast[int](self)).toRuntimeField()
let objAddr = uCall(callData).get(RuntimeField(kind:Int)).getInt()
UE_Log &"Returned object addr is {objAddr}"
let obj = cast[UObjectPtr](objAddr)
proc testCallFuncWithObjPtrArgReturnStr() =
fn: makeUEFunc("callFuncWithObjPtrArgReturnStr", "UObjectPOC"),
value: (obj: cast[int](self)).toRuntimeField()
let str = uCall(callData).get(RuntimeField(kind:String)).getStr()
UE_Log "Returned string is " & str
proc testCallFuncWithOneFVectorArg() =
fn: makeUEFunc("callFuncWithOneFVectorArg", "UObjectPOC"),
value: (vec:FVector(x:12, y:10)).toRuntimeField()
proc testCallFuncWithOneArrayIntArg() =
fn: makeUEFunc("callFuncWithOneArrayIntArg", "UObjectPOC"),
value: (ints:[2, 10]).toRuntimeField()
proc testCallFuncWithOneArrayVectorArg() =
fn: makeUEFunc("callFuncWithOneArrayVectorArg", "UObjectPOC"),
value: (vecs:[FVector(x:12, y:10), FVector(x:12, z:1)]).toRuntimeField()
proc testCallFuncWithOneFVectorArgReturnFVector() =
fn: makeUEFunc("callFuncWithOneFVectorArgReturnFVector", "UObjectPOC"),
value: (vec:FVector(x:12, y:10)).toRuntimeField()
UE_Log $uCall(callData).get.runtimeFieldTo(FVector)
proc testCallFuncWithOneFVectorArgReturnFRotator() =
fn: makeUEFunc("callFuncWithOneFVectorArgReturnFRotator", "UObjectPOC"),
value: (vec:FVector(x:12, y:10)).toRuntimeField()
proc testGetRightVector() =
fn: makeUEFunc("GetRightVector", "UKismetMathLibrary"),
value: (vec:FVector(x:12, y:10)).toRuntimeField()
proc testCallThatReturnsArrayInt() =
fn: makeUEFunc("callThatReturnsArrayInt", "UObjectPOC"),
# value: ().toRuntimeField()
proc testRuntimeFieldCanRetrieveAStructMemberByName() =
let vector = FVector(x:10, y:10)
let rtStruct = vector.toRuntimeField()
let rtField = rtStruct["x"]
let x = rtField.getFloat()
proc shouldReceiveFloat32() =
fn: makeUEFunc("receiveFloat32", "UObjectPOC"),
value: (arg: 10.0).toRuntimeField()
let val = uCall(callData)#.jsonTo(float)
proc shouldReceiveFloat64() =
fn: makeUEFunc("receiveFloat64", "UObjectPOC"),
value: (arg: 10.0).toRuntimeField()
macro ownerName(someSym: typed): string = newLit someSym.owner.strVal()
macro astRepr(exp: typed): string = newLit repr exp
# macro deconstructExp(exp: typed): string =
#TODO do a nice macro that splits the call and tells you what part is wrong
template check(exp: typed) =
let astRepr {.inject.} = astRepr(exp)
let res {.inject.} = $exp
let fnName {.inject.} = ownerName(a)
let msg = &"{[fnName]}Check failed {astRepr} is {res}"
when compiles(self.printSucceed):
UE_Log &"{[fnName]} Check passed"
UE_Log &"{[fnName]} Check passed"
# proc makeFromLoaded*(entry: FNameEntryId): FName {.importcpp:"FNameHelper::MakeFromLoaded(FNameEntrySerialized(#))".}
uClass AUECallPropReadTest of ANimTestBase:
proc shouldBeAbleToReadAnInt32Prop() =
clsName: self.getClass.getCppName(),
value: (intProp: default(int32)).toRuntimeField()
let reply = uCall(callData)
let val = reply.get(RuntimeField(kind:Int)).getInt()
check(val == self.intProp)
proc shouldBeAbleToReadAFStringProp() =
clsName: self.getClass.getCppName(),
value: (stringProp: default(FString)).toRuntimeField()
let reply = uCall(callData)
let val = reply.get(RuntimeField(kind:String)).getStr()
check val == self.stringProp
proc shouldBeAbleToReadABoolProp() =
clsName: self.getClass.getCppName(),
value: (boolProp: default(bool)).toRuntimeField()
let reply = uCall(callData)
let val = reply.get(RuntimeField(kind:Bool)).getBool()
check val == self.boolProp
proc shouldBeAbleToReadAnArrayProp() =
self.arrayProp = @[1, 2, 3, 4, 5].toTArray()
clsName: self.getClass.getCppName(),
value: (arrayProp: default(TArray[int])).toRuntimeField()
let reply = uCall(callData)
let val = reply.get(RuntimeField(kind:Array)).runtimeFieldTo(seq[int]).toTArray()
check val == self.arrayProp
proc shouldBeAbleToReadAStructProp() =
self.structProp = FVector(x:10, y:10, z:10)
clsName: self.getClass.getCppName(),
value: (structProp: default(FVector)).toRuntimeField()
let reply = uCall(callData)
let val = reply.get(RuntimeField(kind:Struct)).runtimeFieldTo(FVector)
check val.x == self.structProp.x
proc shouldBeAbleToReadAnEnumProp() =
self.enumProp = EEnumVMTest.ValueC
clsName: self.getClass.getCppName(),
value: (enumProp: default(EEnumVMTest)).toRuntimeField()
let reply = uCall(callData)
let val = reply.get(RuntimeField(kind:Int)).runtimeFieldTo(EEnumVMTest)
check val == self.enumProp
proc shouldBeAbleToReadANameProp() =
clsName: self.getClass.getCppName(),
value: (nameProp: default(FName)).toRuntimeField()
let reply = uCall(callData)
let val = reply.get(RuntimeField(kind:Int)).getInt()
let name = nameFromInt(val)
check name == self.nameProp
proc shouldBeAbleToWriteAVectorProp() =
self.vectorProp = FVector(x:10, y:10, z:10)
clsName: self.getClass.getCppName(),
value: (vectorProp: default(FVector)).toRuntimeField()
let reply = uCall(callData)
let val = reply.get(RuntimeField(kind:Struct)).runtimeFieldTo(FVector)
check val.x == self.vectorProp.x
proc shouldBeAbleToReadAHitProp() =
self.hitProp = FHitResult()
self.hitProp.bBlockingHit = true
self.hitProp.distance = 100
clsName: self.getClass.getCppName(),
value: (hitProp: default(FHitResult)).toRuntimeField()
let reply = uCall(callData)
let val = reply.get.runtimeFieldTo(FHitResult)
check val == self.hitProp
proc shouldBeAbleToReadATextProp() =
self.textProp = "hola".toText()
clsName: self.getClass.getCppName(),
value: (textProp: default(FText)).toRuntimeField()
let reply = uCall(callData)
let val = reply.get.runtimeFieldTo(FText)
check val == self.textProp
proc shouldBeAbleToReadASetProp() =
self.setProp = makeTSet(2, 1, 5)
clsName: self.getClass.getCppName(),
value: (setProp: default(TSet[int])).toRuntimeField()
let reply = uCall(callData)
# let val = reply.get.runtimeFieldTo(TSet[int])
# check val == self.setProp
(kind: Struct, structVal: @[("faceIndex", (kind: Int, intVal: 0)), ("time", (kind: Float, floatVal: 5.26354424712089e-315)), ("distance", (kind: Float, floatVal: 5.535528570914047e-315)), ("location", (kind: Struct, structVal: @[])), ("impactPoint", (kind: Struct, structVal: @[])), ("normal", (kind: Struct, structVal: @[])), ("impactNormal", (kind: Struct, structVal: @[])), ("traceStart", (kind: Struct, structVal: @[])), ("traceEnd", (kind: Struct, structVal: @[])), ("penetrationDepth", (kind: Float, floatVal: 0.0)), ("myItem", (kind: Int
, intVal: 4294967295)), ("item", (kind: Int, intVal: 0)), ("elementIndex", (kind: Int, intVal: 0)), ("bBlockingHit", (kind: Bool, boolVal: true)), ("bStartPenetrating", (kind: Bool, boolVal: true)), ("physMaterial", (kind: Int, intVal: 0)), ("hitObjectHandle", (kind: Struct, structVal: @[("actor", (kind: Int, intVal: 0))])), ("component", (kind: Int, intVal: 0)), ("boneName", (kind: Int, intVal: 0)), ("myBoneName", (kind: Int, intVal: 0))])
(kind: Struct, structVal: @[("faceIndex", (kind: Int, intVal: 0)), ("time", (kind: Float, floatVal: 1.0)), ("distance", (kind: Float, floatVal: 100.0)), ("normal", (kind: Struct, structVal: @[("x", (kind: Float, floatVal: 0.0)), ("y", (kind: Float, floatVal: 0.0)), ("z", (kind: Float, floatVal: 0.0))])), ("impactNormal", (kind: Struct, structVal: @[("x", (kind: Float, floatVal: 0.0)), ("y", (kind: Float, floatVal: 0.0)), ("z", (kind: Float, floatVal: 0.0))])), ("penetrationDepth", (kind: Float, floatVal: 0.0)), ("myItem", (kind: Int,
intVal: -1)), ("item", (kind: Int, intVal: 0)), ("elementIndex", (kind: Int, intVal: 0)), ("bBlockingHit", (kind: Bool, boolVal: true)), ("bStartPenetrating", (kind: Bool, boolVal: false)), ("boneName", (kind: Int, intVal: 0)), ("myBoneName", (kind: Int, intVal: 0))])
(faceIndex: 0, time: 1.0, distance: 100.0, normal: (x: 0.0, y: 0.0, z: 0.0), impactNormal: (x: 0.0, y: 0.0, z: 0.0), penetrationDepth: 0.0, myItem: -1, item: 0, elementIndex: 0, bBlockingHit: true, bStartPenetrating: false, boneName: None, myBoneName: None)
uClass AUECallPropWriteTest of ANimTestBase:
mapProp: TMap[int, FString]
proc shouldBeAbleToWritteAnInt32Prop() =
clsName: self.getClass.getCppName(),
value: (intProp: expectedValue).toRuntimeField()
check expectedValue == self.intProp
proc shouldBeAbleToWriteAnArrayProp() =
let expected = @[1, 2, 4].toTArray()
self.arrayProp = @[0].toTArray()
clsName: self.getClass.getCppName(),
value: (arrayProp: expected).toRuntimeField()
check expected == self.arrayProp
proc shouldBeAbleToWriteAnEnumProp() =
let expected = EEnumVMTest.ValueC
self.enumProp = EEnumVMTest.ValueA
clsName: self.getClass.getCppName(),
value: (enumProp: expected).toRuntimeField()
check expected == self.enumProp
proc shoulsBeAbleToWriteAStructProp() =
let expected = FVector(x:10, y:10, z:10)
self.structProp = FVector(x:0, y:0, z:0)
clsName: self.getClass.getCppName(),
value: (structProp: expected).toRuntimeField()
check expected.x == self.structProp.x
proc shouldBeAbleToWriteANameProp() =
clsName: "A" & self.getClass.getName(),
value: (nameProp: expected).toRuntimeField()
check expected == self.nameProp
proc shouldBeAbleToWriteAHitProp() =
let expected = FHitResult(bBlockingHit: true, distance: 100)
self.hitProp = FHitResult()
clsName: "A" & self.getClass.getName(),
value: (hitProp: expected).toRuntimeField()
UE_Error &"Distance is {self.hitprop.distance} and expected {expected.distance}"
check expected.distance == self.hitProp.distance
check expected.bBlockingHit == self.hitProp.bBlockingHit
proc shouldBeAbleToWriteATextProp() =
let expected = "hola".toText()
self.textProp = "empty".toText()
clsName: "A" & self.getClass.getName(),
value: (textProp: expected).toRuntimeField()
check expected == self.textProp
proc shouldBeAbleToWriteASetProp() =
let expected = makeTSet(2, 1, 5)
self.setProp = makeTSet[int]()
clsName: "A" & self.getClass.getName(),
value: (setProp: expected).toRuntimeField()
check expected == self.setProp
uClass AUECallMapTest of ANimTestBase:
mapIntIntProp: TMap[int, int]
mapIntFStringProp: TMap[int, FString]
mapIntBoolProp: TMap[int, bool]
mapIntStructProp: TMap[int, FStructVMTest]
mapStringIntProp: TMap[FString, int]
proc shouldBeAbleToWriteAMapIntIntProp() =
let expected = { 1: 10, 2: 20}.toTable().toTMap()
self.mapIntIntProp = makeTMap[int, int]()
clsName: "A" & self.getClass.getName(),
value: (mapIntIntProp: expected.toTable()).toRuntimeField()
check expected == self.mapIntIntProp
proc shouldBeAbleToWriteAMapIntFringProp() =
let expected = { 1: f"Hola", 2: f"Mundo"}.toTable().toTMap()
self.mapIntFStringProp = makeTMap[int, FString]()
clsName: "A" & self.getClass.getName(),
value: (mapIntFStringProp: expected.toTable()).toRuntimeField()
check expected == self.mapIntFStringProp
proc shouldBeAbleToWriteAMapIntBoolProp() =
let expected = { 1: true, 2: false}.toTable()
self.mapIntBoolProp = makeTMap[int, bool]()
clsName: "A" & self.getClass.getName(),
value: (mapIntBoolProp: expected).toRuntimeField()
check expected.toTMap() == self.mapIntBoolProp
proc shouldBeAbleToWriteAMapStructProp() =
let expected = { 1: FStructVMTest(x:10, y:10, z:10), 2: FStructVMTest(x:20, y:20, z:20)}.toTable()
self.mapIntStructProp = makeTMap[int, FStructVMTest]()
clsName: "A" & self.getClass.getName(),
value: (mapIntStructProp: expected).toRuntimeField()
check expected.toTMap() == self.mapIntStructProp
proc shouldBeAbleToWriteAMapStringIntProp() =
let expected = { f"Hola": 10, f"Mundo": 20}.toTable().toTMap()
self.mapStringIntProp = makeTMap[FString, int]()
clsName: "A" & self.getClass.getName(),
value: (mapStringIntProp: expected.toTable()).toRuntimeField()
check expected == self.mapStringIntProp