gdext/bridge

Vars

Initialization_Default {.compileTime.} = Initialization_Scene

Macros

macro gdexport(iden: typed; appearance = default(Appearance); description = ""): untyped

Exposes a member variable to the engine as a property.

type MyResource* {.gdsync.} = ptr object of Resource
  data: PackedVector2Array
gdexport MyResource.data

macro gdexport(name: static string; iden: typed;
               appearance = default(Appearance); description = ""): untyped

Exposes a member variable to the engine as a property.

type MyResource* {.gdsync.} = ptr object of Resource
  data: PackedVector2Array
gdexport "positions", MyResource.data

macro gdsync(body): untyped

The role of the {.gdsync.} pragma, as can be inferred from its name, is to communicate and synchronize the data to which the pragma is attached to the engine. Attaching this pragma makes it visible to scripts or be called as a callback, and so on.

The {.gdsync.} pragma can be attached to the following places:

Class definition

Expose the class to the engine so it can be treated like a built-in class like Node or Resource.

type MyNode {.gdsync.} = ptr object of Node

Procedure definition / Method overriding

see Your Node Class

proc myProc (self: MyNode) {.gdsync.} = print "Hello, GDExtension! from myProc"
method ready (self: MyNode) {.gdsync.} = print "Hello, GDExtension! from ready"

Signal definition

see Signals

proc mySignal (self: MyNode): Error {.gdsync, signal.}

Virtual method definition

see Virtual methods

proc myMethod (self: MyNode) {.gdsync, base.} = printerr "Override please!"

Templates

template `bind`[E: enum](Enum: typedesc[E])
Same as ExtensionMain.bind Enum. ExtensionMain is a special sigleton class that names by config.nims
template `bind`[E: enum](Flags: typedesc[set[E]])
Same as ExtensionMain.bind Flags. ExtensionMain is a special sigleton class that names by config.nims
template `bind`[T: SomeUserClass; E: enum](Class: typedesc[T]; Enum: typedesc[E])

Binds Enum to Class and tells the engine about it. This causes the engine to treat the Enum as belonging to the Class.

type TestEnum* = enum # Values in Editor:
  TestEnumA      # TestNode.TestEnumA = 0
  TestEnumB = 2  # TestNode.TestEnumB = 2
  TestEnumC      # TestNode.TestEnumC = 3
MyClass.bind TestEnum

template `bind`[T: SomeUserClass; E: enum](Class: typedesc[T];
    Flags: typedesc[set[E]])

Binds set[Enum] to Class and tells the engine about it. This causes the engine to treat the Enum is bitfields and it as belonging to the Class.

type TestFlags* = enum # Values in Editor:
  TestFlagA      # TestNode.TestFlagA = 1 (1 << 0)
  TestFlagB = 2  # TestNode.TestFlagB = 4 (1 << 2)
  TestFlagC      # TestNode.TestFlagC = 8 (1 << 3)
MyClass.bind TestFlags
If you want to use the Enum as a sets, at properties, arguments and return-value, bind it as set[Enum].

assert cast[int]({TestFlagA, TestFlagB, TestFlagC}) == (1 or 4 or 8)

template description(desc: string) {.pragma.}

By attaching it to a class, property, or function, you can add a description to the appropriate section of the editor help.

type MyClass {.gdsync, description: "Temporary class to describe bridge functionalities".} = ptr object of Node
  myProperty* {.gdexport, description: "A property description".}: String

proc myFunc*(self: MyClass) {.gdsync, description: "A function description".}: String =
  "hello, world!"

proc myFunc2*{.self: MyClass) {.gdsync.}: String =
  ## Only for functions, this style of description is also available.
  "hello, world!"

template gdexport() {.pragma.}

Exposes a member variable to the engine as a property.

type MyResource* {.gdsync.} = ptr object of Resource
  data* {.gdexport.}: PackedVector2Array

template gdexport(appearance: Appearance) {.pragma.}

Exposes a member variable to the engine as a property. It receives Appearance.

type Weapon* {.gdsync.} = ptr object of Node3D
  description* {.gdexport: Appearance.multiline.}: string

template gdexport(name: string; typ: typedesc[SomeUserClass];
                  proptyp: typedesc[SomeProperty]; getter, setter: StringName;
                  appearance = default(Appearance); description = ""): untyped

Register virtual properties using your own defined getters and setters.

proc get_power(self: Actor): Int {.gdsync.} = self.weapon.atk + self.atk
proc set_power(self: Actor; value: Int) {.gdsync.} = self.atk = max(0, (value - self.weapon.atk))
gdexport "power", Actor, Int, "get_power", "set_power"

template gdexport[T: SomeUserClass; P: SomeProperty](name: static string;
    getter: proc (self: T): P; setter: proc (self: T; value: P);
    appearance = default(Appearance); description = ""): untyped

Register virtual properties using your own defined getters and setters.

proc set_power(self: Actor; value: Int) {.gdsync.} = self.atk = max(0, (value - self.weapon.atk))
gdexport "power",
  proc(self: Actor): Int = self.weapon.atk + self.atk,
  set_power

template gdexport[T: SomeUserClass](name: string;
                                    appearance = default(Appearance)): untyped

Registers non-entity properties such as groups and categories.

gdexport[Actor] "Base Params", Appearance.category

template icon(icon_path: string) {.pragma.}

Specify the class icon on the editor by path.

type MyIconClass {.gdsync, icon: "res://icon.png".} = ptr object of Node

template initLevel(level: InitializationLevel) {.pragma.}

With gdsync, changes the order in which class information is registered.

type MyServer {.gdsync, initLevel: Initialization_servers.} = ptr object of Object

template name(newname: static string) {.pragma.}

Attaching it to a function along with gdsync allows to alias to the registered function.

proc myCallback(self: MyClass; value: Int) {.gdsync, name: "_my_callback".} =
  print "hi! the value is: ", value, "!"

template signal() {.pragma.}

With gdsync, register a function as a signal. Thereafter, calling the function will emit the associated signal.

proc mySignal(self: MyClass; value: Int): Error {.gdsync, signal.}
assert self.signal("mySignal").connect("_my_callback") == 0
assert self.mySignal(10) == ok
# stdout: hi! the value is 10!

template tool() {.pragma.}

Register the class as a tool class so that processing will be executed even while the editor is running.

type MyTool {.gdsync, tool.} = ptr object of Node
method ready(self: MyTool) {.gdsync.} =
  if Engine.isEditorHint:
    print "You are in the editor."
  else:
    print "You are executing the app."