Documentation & Travis & Refactoring
This commit is contained in:
parent
ec707ea776
commit
988b9e1f11
27 changed files with 772 additions and 123 deletions
|
|
@ -32,6 +32,19 @@ type
|
|||
|
||||
ParseError = object of Exception
|
||||
|
||||
proc godotToNim[T](val: Variant): (T, ConversionResult) =
|
||||
mixin fromVariant
|
||||
result[1] = fromVariant(result[0], val)
|
||||
|
||||
proc nimToGodot[T](val: T): Variant =
|
||||
mixin toVariant
|
||||
when compiles(toVariant(val)):
|
||||
result = toVariant(val)
|
||||
else:
|
||||
printError("Failed to convert Nim value of type " & T.name &
|
||||
" into Variant")
|
||||
initNilVariant(result)
|
||||
|
||||
template parseError(node: NimNode, msg: string) =
|
||||
raise newException(ParseError, lineinfo(node) & ": " & msg)
|
||||
|
||||
|
|
@ -249,7 +262,7 @@ macro invokeVarArgs(procIdent, objIdent;
|
|||
|
||||
if hasReturnValue:
|
||||
let theCall = newNimNode(nnkBracketExpr).add(newNimNode(nnkDotExpr).add(
|
||||
newCall("toGodot", invocation), ident("godotVariant")))
|
||||
newCall("toVariant", invocation), ident("godotVariant")))
|
||||
branchBody.add(getAst(initGodotVariantCall(ident("result"), theCall)))
|
||||
else:
|
||||
branchBody.add(invocation)
|
||||
|
|
@ -291,11 +304,18 @@ proc nimDestroyRefFunc(obj: ptr GodotObject, methData: pointer,
|
|||
# so nothing to do here.
|
||||
discard
|
||||
|
||||
proc refcountIncremented*(obj: NimGodotObject) =
|
||||
GC_ref(obj)
|
||||
proc refcountIncremented(obj: ptr GodotObject, methodData: pointer,
|
||||
userData: pointer, numArgs: cint,
|
||||
args: var array[MAX_ARG_COUNT, ptr GodotVariant]):
|
||||
GodotVariant {.noconv.} =
|
||||
GC_ref(cast[NimGodotObject](userData))
|
||||
|
||||
proc refcountDecremented*(obj: NimGodotObject): bool =
|
||||
GC_unref(obj)
|
||||
proc refcountDecremented(obj: ptr GodotObject, methodData: pointer,
|
||||
userData: pointer, numArgs: cint,
|
||||
args: var array[MAX_ARG_COUNT, ptr GodotVariant]):
|
||||
GodotVariant {.noconv.} =
|
||||
GC_unref(cast[NimGodotObject](userData))
|
||||
initGodotVariant(result, false) # destroy when Nim decides
|
||||
|
||||
template registerGodotClass(classNameIdent, classNameLit, isRef,
|
||||
baseNameLit, createFuncIdent; isTool: bool) =
|
||||
|
|
@ -306,6 +326,8 @@ template registerGodotClass(classNameIdent, classNameLit, isRef,
|
|||
nimObj.setGodotObject(obj)
|
||||
GC_ref(nimObj)
|
||||
result = cast[pointer](nimObj)
|
||||
when compiles(nimObj.init()):
|
||||
nimObj.init()
|
||||
|
||||
let createFuncObj = GodotInstanceCreateFunc(
|
||||
createFunc: createFuncIdent
|
||||
|
|
@ -356,19 +378,23 @@ template registerGodotField(classNameLit, classNameIdent, propNameLit,
|
|||
getFunc: getFuncIdent
|
||||
)
|
||||
{.push warning[ProveInit]: off.} # false warning, Nim bug
|
||||
var attr = GodotPropertyAttributes(
|
||||
typ: ord(godotVariantType(propTypeIdent)),
|
||||
hintString: hintTipLit.toGodotString(),
|
||||
var hintStr = hintTipLit.toGodotString()
|
||||
let attr = GodotPropertyAttributes(
|
||||
typ: ord(variantType(propTypeIdent)),
|
||||
hintString: hintStr,
|
||||
hint: GodotPropertyHint.hintIdent,
|
||||
usage: GodotPropertyUsageFlags.usageIdent
|
||||
)
|
||||
{.push warning[ProveInit]: on.}
|
||||
when hasDefaultValue:
|
||||
attr.defaultValue = (defaultValueNode).toGodot()
|
||||
attr.defaultValue = (defaultValueNode).toVariant().godotVariant[]
|
||||
godotScriptRegisterProperty(getNativeLibHandle(), classNameLit, propNameLit,
|
||||
attr, setFunc, getFunc)
|
||||
unsafeAddr attr, setFunc, getFunc)
|
||||
hintStr.deinit()
|
||||
|
||||
static:
|
||||
import strutils, sets
|
||||
import strutils, sets, sequtils
|
||||
|
||||
proc toGodotStyle(s: string): string {.compileTime.} =
|
||||
result = newStringOfCap(s.len + 10)
|
||||
for c in s:
|
||||
|
|
@ -469,7 +495,6 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
|
|||
GodotVariant {.noconv.} =
|
||||
let self = cast[classNameIdent](userData)
|
||||
const isStaticCall = methodNameLit == cstring"_ready" or
|
||||
methodNameLit == cstring"_init" or
|
||||
methodNameLit == cstring"_enter_tree" or
|
||||
methodNameLit == cstring"_exit_tree" or
|
||||
methodNameLit == cstring"_enter_world" or
|
||||
|
|
@ -520,25 +545,70 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
|
|||
|
||||
if isRef:
|
||||
# add ref/unref for types inherited from Reference
|
||||
let noArgs = newSeq[NimNode]()
|
||||
result.add(getAst(
|
||||
registerGodotMethod(classNameLit, classNameIdent, ident("refcountIncremented"),
|
||||
cstring"_refcount_incremented", 0, 0,
|
||||
noArgs, genSym(nskProc, "refcount_incremented"),
|
||||
ident("false"))))
|
||||
result.add(getAst(
|
||||
registerGodotMethod(classNameLit, classNameIdent, ident("refcountDecremented"),
|
||||
cstring"_refcount_decremented", 0, 0,
|
||||
noArgs, genSym(nskProc, "refcount_decremented"),
|
||||
ident("true"))))
|
||||
template registerRefIncDec(classNameLit) =
|
||||
let refInc = GodotInstanceMethod(
|
||||
meth: refcountIncremented
|
||||
)
|
||||
let refDec = GodotInstanceMethod(
|
||||
meth: refcountDecremented
|
||||
)
|
||||
godotScriptRegisterMethod(getNativeLibHandle(), classNameLit,
|
||||
cstring"_refcount_incremented",
|
||||
GodotMethodAttributes(), refInc)
|
||||
godotScriptRegisterMethod(getNativeLibHandle(), classNameLit,
|
||||
cstring"_refcount_decremented",
|
||||
GodotMethodAttributes(), refDec)
|
||||
result.add(getAst(registerRefIncDec(classNameLit)))
|
||||
|
||||
{.push warning[Deprecated]: off.}
|
||||
# immediate macros are deprecated, but `untyped` doesnt make it immediate,
|
||||
# immediate macros are deprecated, but `untyped` doesn't make it immediate,
|
||||
# as the warning and the documentation claim.
|
||||
|
||||
macro gdobj*(definition: untyped, body: typed): typed {.immediate.} =
|
||||
## Generates Godot type. Self-documenting example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## import godot, node
|
||||
##
|
||||
## gdobj MyObj of Node:
|
||||
## var myField: int
|
||||
## ## Not exported to Godot (i.e. editor will not see this field).
|
||||
##
|
||||
## var myString* {.gdExport, hint: Length, tip: "20".}: string
|
||||
## ## Exported to Godot as ``my_string``.
|
||||
## ## Editor will limit this string to length 20.
|
||||
## ## ``hint` is a value of ``GodotPropertyHint`` enum.
|
||||
## ## ``tip`` depends on the value of ``hint``, its format is described
|
||||
## ## in ``GodotPropertyHint`` documentation.
|
||||
##
|
||||
## method ready*() =
|
||||
## ## Exported methods are exported to Godot by default,
|
||||
## ## and their Godot names are prefixed with ``_``
|
||||
## ## (in this case ``_ready``)
|
||||
## print("I am ready! myString is: " & myString)
|
||||
##
|
||||
## proc myProc*() {.gdExport.} =
|
||||
## ## Exported to Godot as ``my_proc``
|
||||
## print("myProc is called! Incrementing myField.")
|
||||
## inc myField
|
||||
##
|
||||
## If parent type is omitted, the type is inherited from ``Object``.
|
||||
##
|
||||
## ``tool`` specifier can be added to mark the type as an
|
||||
## `editor plugin <https://godot.readthedocs.io/en/stable/development/plugins/making_plugins.html>`_:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## import godot, editor_plugin
|
||||
##
|
||||
## gdobj(MyTool of EditorPlugin, tool):
|
||||
## method enterTree*() =
|
||||
## print("MyTool initialized!")
|
||||
##
|
||||
## Objects can be instantiated by invoking
|
||||
## `gdnew <godotnim.html#gdnew>`_ or by using
|
||||
## `load <godotapi/resource_loader.html#load,string,string,bool>`_ or any other way
|
||||
## that you can find in `Godot API <index.html#modules-godot-api>`_.
|
||||
let typeDef = parseType(definition, callsite())
|
||||
result = genType(typeDef)
|
||||
|
||||
{.push warning[Deprecated]: on.}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,15 +10,28 @@ import core.vector2, core.rect2,
|
|||
core.arrays, core.poolarrays, core.variants
|
||||
import godotinternal
|
||||
|
||||
## Definition of NimGodotObject and converters for built-in types.
|
||||
## This module defines ``NimGodotObject`` and ``toVariant``/``fromVariant``
|
||||
## converters for Nim types. The converters are used by
|
||||
## `gdobj <godotmacros.html#gdobj.m,untyped,typed>`_ macro to import/export
|
||||
## values from/to Godot (editor, GDScript).
|
||||
##
|
||||
## You can also allow conversion of any custom type ``MyType`` by implementing:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## proc variantType*(T: typedesc[MyType]): VariantType
|
||||
## proc toVariant*(self: MyType): Variant
|
||||
## proc fromVariant*(self: var MyType, val: Variant): ConversionResult
|
||||
|
||||
type
|
||||
NimGodotObject* = ref object of RootObj
|
||||
## The base type all Godot types inherit from.
|
||||
## Manages lifecycle of the wrapped GodotObject.
|
||||
godotObject: ptr GodotObject
|
||||
isExternalRef: bool
|
||||
isOwn: bool
|
||||
|
||||
ConversionResult* {.pure.} = enum
|
||||
## Conversion result to return from ``fromVariant`` procedure.
|
||||
OK,
|
||||
TypeError,
|
||||
## Type mismatch
|
||||
|
|
@ -41,7 +54,11 @@ type
|
|||
SomeGodotOrNum = SomeGodot or SomeSignedInt or SomeUnsignedInt or SomeFloat
|
||||
|
||||
CallError* = object of Exception
|
||||
## Raised by wrappers in case of an incorrect dynamic invocation.
|
||||
## For example, if incorrect number of arguments were passed or they had
|
||||
## unexpected types.
|
||||
err*: VariantCallError
|
||||
## The error as returned by Godot
|
||||
|
||||
ObjectInfo = object
|
||||
constructor: proc(): NimGodotObject {.gcsafe, nimcall.}
|
||||
|
|
@ -49,20 +66,24 @@ type
|
|||
isNative: bool
|
||||
isRef: bool
|
||||
|
||||
template printWarning*(warn: typed) =
|
||||
template printWarning*(warning: typed) =
|
||||
## Prints ``warning`` to Godot log, adding filename and line information.
|
||||
let (filename, line) = instantiationInfo()
|
||||
godotPrintWarning(cstring($warn), nil, cstring(filename), line.cint)
|
||||
godotPrintWarning(cstring($warning), nil, cstring(filename), line.cint)
|
||||
|
||||
template printError*(err: typed) =
|
||||
template printError*(error: typed) =
|
||||
## Prints ``error`` to Godot log, adding filename and line information.
|
||||
let (filename, line) = instantiationInfo()
|
||||
godotPrintError(cstring($err), nil, cstring(filename), line.cint)
|
||||
godotPrintError(cstring($error), nil, cstring(filename), line.cint)
|
||||
|
||||
proc print*(message: string) {.inline.} =
|
||||
## Prints ``message`` to Godot log.
|
||||
var s = message.toGodotString()
|
||||
godotPrint(s)
|
||||
s.deinit()
|
||||
|
||||
proc print*(message: cstring) {.inline.} =
|
||||
## Prints ``message`` to Godot log.
|
||||
var s = message.toGodotString()
|
||||
godotPrint(s)
|
||||
s.deinit()
|
||||
|
|
@ -141,7 +162,9 @@ macro isReference(T: typedesc): bool =
|
|||
else: ident("false")
|
||||
|
||||
template registerClass*(T: typedesc; godotClassName: cstring,
|
||||
isNativeParam: bool) =
|
||||
native: bool) =
|
||||
## Registers the specified Godot type.
|
||||
## Used by ``gdobj`` macro and `godotapigen <godotapigen.html>`_.
|
||||
if classRegistry.isNil:
|
||||
classRegistry = newTable[cstring, ObjectInfo]()
|
||||
let constructor = proc(): NimGodotObject =
|
||||
|
|
@ -154,21 +177,21 @@ template registerClass*(T: typedesc; godotClassName: cstring,
|
|||
let objInfo = ObjectInfo(
|
||||
constructor: constructor,
|
||||
baseNativeClass: base,
|
||||
isNative: isNativeParam,
|
||||
isNative: native,
|
||||
isRef: isRef
|
||||
)
|
||||
classRegistry[godotClassName] = objInfo
|
||||
static:
|
||||
let objInfoStatic = ObjectInfo(
|
||||
baseNativeClass: base,
|
||||
isNative: isNativeParam,
|
||||
isRef: isRef
|
||||
isNative: native,
|
||||
isRef: isRef,
|
||||
)
|
||||
classRegistryStatic[godotClassName] = objInfoStatic
|
||||
when isRef:
|
||||
static:
|
||||
refClasses.add(T.name)
|
||||
when isNativeParam:
|
||||
when native:
|
||||
static:
|
||||
nativeClasses.add(T.name)
|
||||
|
||||
|
|
@ -187,6 +210,9 @@ proc newNimGodotObject[T: NimGodotObject](
|
|||
result.godotObject.reference()
|
||||
|
||||
proc asNimGodotObject*[T: NimGodotObject](godotObject: ptr GodotObject): T =
|
||||
## Wraps ``godotObject`` into Nim type ``T``.
|
||||
## This is used by `godotapigen <godotapigen.html>`_ and should rarely be
|
||||
## used by anything else.
|
||||
if godotObject.isNil: return nil
|
||||
let userDataPtr = godotObject.getUserData()
|
||||
if not userDataPtr.isNil:
|
||||
|
|
@ -202,15 +228,24 @@ proc newVariant*(obj: NimGodotObject): Variant {.inline.} =
|
|||
newVariant(obj.godotObject)
|
||||
|
||||
proc asObject*[T: NimGodotObject](v: Variant): T {.inline.} =
|
||||
## Converts ``v`` to object of type ``T``.
|
||||
## Returns ``nil`` if the conversion cannot be performed
|
||||
## (``v``'s type is not an Object or it's an object of an incompatible type)
|
||||
asNimGodotObject[T](v.asGodotObject())
|
||||
|
||||
proc asObject*(v: Variant, T: typedesc[NimGodotObject]): T {.inline.} =
|
||||
## Converts ``v`` to object of type ``T``.
|
||||
## Returns ``nil`` if the conversion cannot be performed
|
||||
## (``v``'s type is not an Object or it's an object of an incompatible type)
|
||||
asNimGodotObject[T](v.asGodotObject())
|
||||
|
||||
proc `as`*[T: NimGodotObject](obj: NimGodotObject, t: typedesc[T]): T =
|
||||
## Converts the ``obj`` into the specified type.
|
||||
## Returns ``nil`` if the conversion cannot be performed
|
||||
## (the ``obj`` is not of the type ``T``)
|
||||
##
|
||||
## This can be used either in dot notation (``node.as(Button)``) or
|
||||
## infix notation (``node as Button``).
|
||||
if obj.isNil or not (obj of T):
|
||||
when not defined(release):
|
||||
if not obj.isNil:
|
||||
|
|
@ -220,9 +255,6 @@ proc `as`*[T: NimGodotObject](obj: NimGodotObject, t: typedesc[T]): T =
|
|||
else:
|
||||
result = T(obj)
|
||||
|
||||
proc getSingletonGodot*(name: cstring): ptr GodotObject {.
|
||||
importc: "godot_global_get_singleton".}
|
||||
|
||||
proc newRStrLit(s: string): NimNode {.compileTime.} =
|
||||
result = newNimNode(nnkRStrLit)
|
||||
result.strVal = s
|
||||
|
|
@ -241,8 +273,11 @@ macro toGodotName(T: typedesc): cstring =
|
|||
ident("cstring"), newRStrLit(godotName))
|
||||
|
||||
proc getSingleton*[T: NimGodotObject](): T =
|
||||
## Returns singleton of type ``T``. Normally, this should not be used,
|
||||
## because `godotapigen <godotapigen.html>`_ wraps singleton methods so that
|
||||
## singleton objects don't have to be provided as parameters.
|
||||
const godotName = toGodotName(T)
|
||||
let singleton = getSingletonGodot(godotName)
|
||||
let singleton = getGodotSingleton(godotName)
|
||||
if singleton.isNil:
|
||||
printError("Tried to get non-existing singleton of type " & $godotName)
|
||||
else:
|
||||
|
|
@ -285,6 +320,7 @@ proc newOwnObj[T: NimGodotObject](name: cstring): T =
|
|||
ret.deinit()
|
||||
|
||||
proc gdnew*[T: NimGodotObject](): T =
|
||||
## Instantiates new object of type ``T``.
|
||||
const godotName = toGodotName(T)
|
||||
const objInfo = classRegistryStatic[godotName]
|
||||
result = when objInfo.isNative:
|
||||
|
|
@ -292,6 +328,7 @@ proc gdnew*[T: NimGodotObject](): T =
|
|||
else: newOwnObj[T](godotName)
|
||||
|
||||
proc newCallError*(err: VariantCallError): ref CallError =
|
||||
## Instantiates ``CallError`` from Godot ``err``.
|
||||
let msg = case err.error:
|
||||
of VariantCallErrorType.OK,
|
||||
VariantCallErrorType.InvalidMethod,
|
||||
|
|
@ -307,6 +344,8 @@ proc newCallError*(err: VariantCallError): ref CallError =
|
|||
result.err = err
|
||||
|
||||
proc newConversionError*(err: ConversionResult): ref ValueError =
|
||||
## Instantiates error raised by `godotapigen <godotapigen.html>`_
|
||||
## generated code in case of a conversion error.
|
||||
let msg = case err:
|
||||
of ConversionResult.TypeError:
|
||||
"Failed to convert the return value into Nim type"
|
||||
|
|
@ -317,28 +356,32 @@ proc newConversionError*(err: ConversionResult): ref ValueError =
|
|||
|
||||
result = newException(ValueError, msg)
|
||||
|
||||
proc removeGodotObject*(nimObj: NimGodotObject) {.inline.} =
|
||||
## Used from destructor
|
||||
nimObj.godotObject = nil
|
||||
|
||||
proc setGodotObject*(nimObj: NimGodotObject, obj: ptr GodotObject) {.inline.} =
|
||||
## Used from Godot constructor. Don't call this.
|
||||
assert(not obj.isNil)
|
||||
assert(nimObj.godotObject.isNil) # reassignment is not allowed
|
||||
nimObj.godotObject = obj
|
||||
|
||||
proc setOwn*(nimObj: NimGodotObject) {.inline.} =
|
||||
## Used from Godot constructor. Don't call this.
|
||||
nimObj.isOwn = true
|
||||
|
||||
proc removeGodotObject*(nimObj: NimGodotObject) {.inline.} =
|
||||
## Used from Godot destructor. Don't call this.
|
||||
nimObj.godotObject = nil
|
||||
|
||||
proc godotObject*(nimObj: NimGodotObject): ptr GodotObject {.inline.} =
|
||||
## Returns internal poitner to ``GodotObject``. Use only if you know what
|
||||
## you are doing.
|
||||
nimObj.godotObject
|
||||
|
||||
proc godotVariantType*(T: typedesc[NimGodotObject]): VariantType {.inline.} =
|
||||
proc variantType*(T: typedesc[NimGodotObject]): VariantType {.inline.} =
|
||||
VariantType.Object
|
||||
|
||||
proc toGodot*(self: NimGodotObject): Variant {.inline.} =
|
||||
proc toVariant*(self: NimGodotObject): Variant {.inline.} =
|
||||
newVariant(self.godotObject)
|
||||
|
||||
proc fromGodot*[T: NimGodotObject](self: var T,
|
||||
proc fromVariant*[T: NimGodotObject](self: var T,
|
||||
val: Variant): ConversionResult =
|
||||
if val.getType() == VariantType.Object:
|
||||
let objPtr = val.asGodotObject()
|
||||
|
|
@ -350,27 +393,27 @@ proc fromGodot*[T: NimGodotObject](self: var T,
|
|||
else:
|
||||
result = ConversionResult.TypeError
|
||||
|
||||
proc godotVariantType*(T: typedesc[enum]): VariantType {.inline.} =
|
||||
proc variantType*(T: typedesc[enum]): VariantType {.inline.} =
|
||||
VariantType.Int
|
||||
|
||||
proc toGodot*[T: enum](self: T): Variant {.inline.} =
|
||||
proc toVariant*[T: enum](self: T): Variant {.inline.} =
|
||||
newVariant(int64(ord(self)))
|
||||
|
||||
proc fromGodot*[T: enum](self: var T,
|
||||
proc fromVariant*[T: enum](self: var T,
|
||||
val: Variant): ConversionResult {.inline.} =
|
||||
if val.getType() == VariantType.Int:
|
||||
self = T(val.asInt())
|
||||
else:
|
||||
result = ConversionResult.TypeError
|
||||
|
||||
proc toGodot*(self: Variant): Variant {.inline.} =
|
||||
proc toVariant*(self: Variant): Variant {.inline.} =
|
||||
self
|
||||
|
||||
proc fromGodot*(self: var Variant,
|
||||
proc fromVariant*(self: var Variant,
|
||||
val: Variant): ConversionResult {.inline.} =
|
||||
self = newVariant(val)
|
||||
|
||||
proc godotVariantType*(T: typedesc[SomeGodotOrNum]): VariantType {.inline.} =
|
||||
proc variantType*(T: typedesc[SomeGodotOrNum]): VariantType {.inline.} =
|
||||
when T is SomeSignedInt or T is SomeUnsignedInt:
|
||||
VariantType.Int
|
||||
elif T is bool:
|
||||
|
|
@ -426,10 +469,10 @@ proc godotVariantType*(T: typedesc[SomeGodotOrNum]): VariantType {.inline.} =
|
|||
else:
|
||||
VariantType.Nil
|
||||
|
||||
proc toGodot*[T: SomeGodotOrNum](val: T): Variant {.inline.} =
|
||||
proc toVariant*[T: SomeGodotOrNum](val: T): Variant {.inline.} =
|
||||
newVariant(val)
|
||||
|
||||
proc fromGodot*[T: SomeSignedInt or SomeUnsignedInt](
|
||||
proc fromVariant*[T: SomeSignedInt or SomeUnsignedInt](
|
||||
self: var T, val: Variant): ConversionResult =
|
||||
if val.getType() != VariantType.Int:
|
||||
result = ConversionResult.TypeError
|
||||
|
|
@ -443,7 +486,7 @@ proc fromGodot*[T: SomeSignedInt or SomeUnsignedInt](
|
|||
else:
|
||||
self = T(intVal)
|
||||
|
||||
proc fromGodot*[T: SomeFloat](self: var T, val: Variant): ConversionResult =
|
||||
proc fromVariant*[T: SomeFloat](self: var T, val: Variant): ConversionResult =
|
||||
if val.getType() == VariantType.Real:
|
||||
self = T(val.asReal())
|
||||
elif val.getType() == VariantType.Int:
|
||||
|
|
@ -451,8 +494,8 @@ proc fromGodot*[T: SomeFloat](self: var T, val: Variant): ConversionResult =
|
|||
else:
|
||||
result = ConversionResult.TypeError
|
||||
|
||||
proc fromGodot*[T: SomeGodot](self: var T, val: Variant): ConversionResult =
|
||||
if godotVariantType(T) != val.getType():
|
||||
proc fromVariant*[T: SomeGodot](self: var T, val: Variant): ConversionResult =
|
||||
if variantType(T) != val.getType():
|
||||
return ConversionResult.TypeError
|
||||
when self is bool:
|
||||
self = val.asBool()
|
||||
|
|
@ -506,13 +549,13 @@ proc fromGodot*[T: SomeGodot](self: var T, val: Variant): ConversionResult =
|
|||
# mustn't reach this
|
||||
result = ConversionError.TypeError
|
||||
|
||||
proc godotVariantType*(T: typedesc[string]): VariantType {.inline.} =
|
||||
proc variantType*(T: typedesc[string]): VariantType {.inline.} =
|
||||
VariantType.String
|
||||
|
||||
proc toGodot*(s: string): Variant {.inline.} =
|
||||
proc toVariant*(s: string): Variant {.inline.} =
|
||||
newVariant(s)
|
||||
|
||||
proc fromGodot*(s: var string, val: Variant): ConversionResult =
|
||||
proc fromVariant*(s: var string, val: Variant): ConversionResult =
|
||||
if val.getType() == VariantType.String:
|
||||
s = val.asString()
|
||||
elif val.getType() == VariantType.Nil:
|
||||
|
|
@ -520,20 +563,20 @@ proc fromGodot*(s: var string, val: Variant): ConversionResult =
|
|||
else:
|
||||
result = ConversionResult.TypeError
|
||||
|
||||
proc godotVariantType*(T: typedesc[seq]): VariantType =
|
||||
proc variantType*(T: typedesc[seq]): VariantType =
|
||||
VariantType.Array
|
||||
|
||||
proc godotVariantType*(T: typedesc[array]): VariantType =
|
||||
proc variantType*(T: typedesc[array]): VariantType =
|
||||
VariantType.Array
|
||||
|
||||
proc toGodot*[T](s: openarray[T]): Variant =
|
||||
proc toVariant*[T](s: openarray[T]): Variant =
|
||||
var arr = newArray()
|
||||
mixin toGodot
|
||||
for item in s:
|
||||
arr.add(toGodot(item))
|
||||
arr.add(toVariant(item))
|
||||
result = newVariant(arr)
|
||||
|
||||
proc fromGodot*[T](s: var seq[T], val: Variant): ConversionResult =
|
||||
proc fromVariant*[T](s: var seq[T], val: Variant): ConversionResult =
|
||||
if val.getType() != VariantType.Array:
|
||||
result = ConversionResult.TypeError
|
||||
else:
|
||||
|
|
@ -541,12 +584,12 @@ proc fromGodot*[T](s: var seq[T], val: Variant): ConversionResult =
|
|||
s = newSeq[T](arr.len)
|
||||
for idx, item in arr:
|
||||
mixin fromGodot
|
||||
let convResult = fromGodot(s[idx], item)
|
||||
let convResult = fromVariant(s[idx], item)
|
||||
if convResult != ConversionResult.OK:
|
||||
s = nil
|
||||
return convResult
|
||||
|
||||
proc fromGodot*[T: array](s: var T, val: Variant): ConversionResult =
|
||||
proc fromVariant*[T: array](s: var T, val: Variant): ConversionResult =
|
||||
if val.getType() != VariantType.Array:
|
||||
result = ConversionResult.TypeError
|
||||
else:
|
||||
|
|
@ -555,21 +598,21 @@ proc fromGodot*[T: array](s: var T, val: Variant): ConversionResult =
|
|||
return ConversionResult.TypeError
|
||||
for idx, item in arr:
|
||||
mixin fromGodot
|
||||
let convResult = fromGodot(s[idx], item)
|
||||
let convResult = fromVariant(s[idx], item)
|
||||
if convResult != ConversionResult.OK:
|
||||
return convResult
|
||||
|
||||
proc godotVariantType*(T: typedesc[Table|TableRef]): VariantType {.inline.} =
|
||||
proc variantType*(T: typedesc[Table|TableRef]): VariantType {.inline.} =
|
||||
VariantType.Dictionary
|
||||
|
||||
proc toGodot*[T: Table or TableRef](t: T): Variant =
|
||||
proc toVariant*[T: Table or TableRef](t: T): Variant =
|
||||
var dict = newDictionary()
|
||||
mixin toGodot
|
||||
for k, v in t.pairs():
|
||||
dict[toGodot(k)] = toGodot(v)
|
||||
dict[toVariant(k)] = toVariant(v)
|
||||
result = newVariant(dict)
|
||||
|
||||
proc fromGodot*[T: Table or TableRef](t: var T, val: Variant): ConversionResult =
|
||||
proc fromVariant*[T: Table or TableRef](t: var T, val: Variant): ConversionResult =
|
||||
if val.getType() != VariantType.Dictionary:
|
||||
result = ConversionResult.TypeError
|
||||
else:
|
||||
|
|
@ -582,31 +625,18 @@ proc fromGodot*[T: Table or TableRef](t: var T, val: Variant): ConversionResult
|
|||
for k, v in dict:
|
||||
var nimKey: type(t.keys())
|
||||
var nimVal: type(t.values())
|
||||
let keyResult = fromGodot(nimKey, k)
|
||||
let keyResult = fromVariant(nimKey, k)
|
||||
if keyResult != ConversionResult.OK:
|
||||
when t is ref:
|
||||
t = nil
|
||||
return keyResult
|
||||
let valResult = fromGodot(nimVal, v)
|
||||
let valResult = fromVariant(nimVal, v)
|
||||
if valResult != ConversionResult.OK:
|
||||
when t is ref:
|
||||
t = nil
|
||||
return valResult
|
||||
t[nimKey] = nimVal
|
||||
|
||||
proc godotToNim*[T](val: Variant): (T, ConversionResult) =
|
||||
mixin fromGodot
|
||||
result[1] = fromGodot(result[0], val)
|
||||
|
||||
proc nimToGodot*[T](val: T): Variant =
|
||||
mixin toGodot
|
||||
when compiles(toGodot(val)):
|
||||
result = toGodot(val)
|
||||
else:
|
||||
printError("Failed to convert Nim value of type " & T.name &
|
||||
" into Variant")
|
||||
initNilVariant(result)
|
||||
|
||||
{.emit: """/*TYPESECTION*/
|
||||
void NimMain(void);
|
||||
N_NOINLINE(void, setStackBottom)(void* thestackbottom);
|
||||
|
|
@ -614,6 +644,8 @@ N_NOINLINE(void, setStackBottom)(void* thestackbottom);
|
|||
|
||||
var nativeLibHandle: pointer
|
||||
proc getNativeLibHandle*(): pointer =
|
||||
## Returns NativeScript library handle used to register type information
|
||||
## in Godot. Use only if you know what you are doing.
|
||||
return nativeLibHandle
|
||||
|
||||
proc godot_nativescript_init(handle: pointer) {.
|
||||
|
|
|
|||
1
godot/nim/nim.cfg
Normal file
1
godot/nim/nim.cfg
Normal file
|
|
@ -0,0 +1 @@
|
|||
--path:"$projectdir/../"
|
||||
Loading…
Add table
Add a link
Reference in a new issue