gdnative.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. // Copyright © 2019 - 2020 Oscar Campos <oscar.campos@thepimpam.com>
  2. // Copyright © 2017 - William Edwards
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License
  15. // Package gdnative provides a wrapper around the Godot GDNative API.
  16. package gdnative
  17. /*
  18. #cgo CFLAGS: -I../godot_headers -std=c11
  19. #cgo linux LDFLAGS: -Wl,-unresolved-symbols=ignore-all
  20. #cgo darwin LDFLAGS: -Wl,-undefined,dynamic_lookup
  21. #include <gdnative/gdnative.h>
  22. #include <gdnative_api_struct.gen.h>
  23. #include "gdnative.gen.h"
  24. #include "util.h"
  25. */
  26. import "C"
  27. import (
  28. "fmt"
  29. "log"
  30. "unsafe"
  31. wchar "github.com/vitaminwater/cgo.wchar"
  32. )
  33. // debug determines whether or not we should log messages
  34. var debug = false
  35. // EnableDebug will enable logging of GDNative debug messages.
  36. func EnableDebug() {
  37. debug = true
  38. }
  39. // GDNative is our API main entry point, it is first set here to null.
  40. // This will be set when 'godot_gdnative_init' is called by Godot when the library is loaded.
  41. var GDNative = new(gdNative)
  42. // gdNative is a structure that wraps the GDNativeAPI.
  43. type gdNative struct {
  44. api *C.godot_gdnative_core_api_struct
  45. initialized bool
  46. }
  47. // IsInitialized will return true if `godot_gdnative_init` was called by Godot.
  48. func (g *gdNative) IsInitialized() bool {
  49. return g.initialized
  50. }
  51. // CheckInit will check to see if GDNative has initialized. If it is not, it will
  52. // throw a panic.
  53. func (g *gdNative) checkInit() {
  54. if !g.IsInitialized() {
  55. panic("GDNative has not initialized! You cannot call this in init()!")
  56. }
  57. }
  58. // godot_gdnative_init is the library entry point. When the library is loaded
  59. // this method will be called by Godot.
  60. //export godot_gdnative_init
  61. func godot_gdnative_init(options *C.godot_gdnative_init_options) {
  62. // Get the API struct from the init options passed by Godot when this
  63. // library is loaded. This API struct will have all of the functions
  64. // to call.
  65. GDNative.api = (*options).api_struct
  66. GDNative.initialized = true
  67. // Configure logging.
  68. log.SetFlags(log.LstdFlags | log.Lshortfile)
  69. log.SetOutput(Log)
  70. if debug {
  71. log.Println("Initializing gdnative-go library.")
  72. }
  73. // Find GDNative extensions that we support.
  74. for i := 0; i < int(GDNative.api.num_extensions); i++ {
  75. extension := C.cgo_get_ext(GDNative.api.extensions, C.int(i))
  76. switch extension._type {
  77. case C.GDNATIVE_EXT_NATIVESCRIPT:
  78. if debug {
  79. log.Println("Found nativescript extension!")
  80. }
  81. NativeScript.api = (*C.godot_gdnative_ext_nativescript_api_struct)(unsafe.Pointer(extension))
  82. }
  83. }
  84. }
  85. /** Library de-initialization **/
  86. // godot_gdnative_terminate is the library's de-initialization method. When
  87. // Godot unloads the library, this method will be called.
  88. //export godot_gdnative_terminate
  89. func godot_gdnative_terminate(options *C.godot_gdnative_terminate_options) {
  90. if debug {
  91. log.Println("De-initializing Go library.")
  92. }
  93. GDNative.api = nil
  94. NativeScript.api = nil
  95. }
  96. // NewEmptyVoid returns back a new C empty or void pointer
  97. func NewEmptyVoid() Pointer {
  98. var empty C.void
  99. return Pointer{base: unsafe.Pointer(&empty)}
  100. }
  101. // GetSingleton will return an instance of the given singleton.
  102. func GetSingleton(name String) Object {
  103. if debug {
  104. log.Println("Getting singleton:", name)
  105. }
  106. GDNative.checkInit()
  107. // Create a C string from the name argument.
  108. cName := C.CString(string(name))
  109. // Call the C method
  110. obj := C.go_godot_global_get_singleton(GDNative.api, cName)
  111. return Object{base: (*C.godot_object)(obj)}
  112. }
  113. // NewMethodBind will return a method binding using the given class name and method
  114. // name.
  115. func NewMethodBind(class, method string) MethodBind {
  116. if debug {
  117. log.Println("Creating method bind for:", class+"."+method)
  118. }
  119. GDNative.checkInit()
  120. methodBind := C.go_godot_method_bind_get_method(
  121. GDNative.api,
  122. C.CString(class),
  123. C.CString(method),
  124. )
  125. return MethodBind{base: methodBind}
  126. }
  127. // MethodBindPtrCall will call the given method on the given Godot Object. Its return
  128. // value is given as a pointer, which can be used to convert it to a variant.
  129. func MethodBindPtrCall(methodBind MethodBind, instance Object, args []Pointer, returns Pointer) Pointer {
  130. GDNative.checkInit()
  131. if instance.getBase() == nil {
  132. panic("Godot object pointer was nil when calling MethodBindPtrCall")
  133. }
  134. // Build out our C arguments array
  135. cArgs := C.go_void_build_array(C.int(len(args)))
  136. for i, arg := range args {
  137. C.go_void_add_element(cArgs, arg.getBase(), C.int(i))
  138. }
  139. if debug {
  140. // If debug is enabled print all the arguments we are passing
  141. for i, arg := range args {
  142. log.Println("arg", i, ": ", arg.getBase())
  143. }
  144. log.Println("args: ", cArgs)
  145. log.Println("returns: ", returns.getBase())
  146. log.Println("object: ", unsafe.Pointer(instance.getBase()))
  147. log.Println("methodbind: ", unsafe.Pointer(methodBind.getBase()))
  148. }
  149. // Call the C method
  150. C.go_godot_method_bind_ptrcall(
  151. GDNative.api,
  152. methodBind.getBase(),
  153. unsafe.Pointer(instance.getBase()),
  154. cArgs,
  155. returns.getBase(),
  156. )
  157. if debug {
  158. log.Println("Finished calling method.")
  159. }
  160. return returns
  161. }
  162. // Pointer is a pointer to arbitrary underlying data. This is primarily used
  163. // in conjunction with MethodBindPtrCall.
  164. type Pointer struct {
  165. base unsafe.Pointer
  166. }
  167. func (p *Pointer) getBase() unsafe.Pointer {
  168. return p.base
  169. }
  170. // Char is a Godot C char wrapper
  171. type Char string
  172. func (c Char) getBase() *C.char {
  173. // this might lead to memory leaks as this C memory
  174. // is not gonna be garbage collected by Go runtime
  175. return C.CString(string(c))
  176. }
  177. // Double is a Godot C double wrapper
  178. type Double float64
  179. func (d Double) getBase() C.double {
  180. return C.double(d)
  181. }
  182. // NewPointerFromFloat will return an unsafe pointer to the given
  183. // object. This is primarily used in conjunction with MethodBindPtrCall.
  184. func NewPointerFromFloat(obj Float) Pointer {
  185. base := obj.getBase()
  186. return Pointer{base: unsafe.Pointer(&base)}
  187. }
  188. // NewFloatFromPointer will return a Float from the
  189. // given unsafe pointer. This is primarily used in conjunction with MethodBindPtrCall.
  190. func NewFloatFromPointer(ptr Pointer) Float {
  191. base := ptr.getBase()
  192. return Float(*(*C.float)(base))
  193. }
  194. // NewEmptyFloat will return a pointer to an empty
  195. // initialized Float. This is primarily used in
  196. // conjunction with MethodBindPtrCall.
  197. func NewEmptyFloat() Pointer {
  198. var obj C.float
  199. return Pointer{base: unsafe.Pointer(&obj)}
  200. }
  201. // Float is a Godot C float wrapper
  202. type Float float64
  203. func (f Float) getBase() C.float {
  204. return C.float(f)
  205. }
  206. // Int64T is a Godot C int64_t wrapper
  207. type Int64T int64
  208. func (i Int64T) getBase() C.int64_t {
  209. return C.int64_t(i)
  210. }
  211. // SignedChar is a Godot C schar wrapper
  212. type SignedChar int8
  213. func (s SignedChar) getBase() *C.schar { //nolint:unused
  214. intVal := int8(s)
  215. return (*C.schar)(unsafe.Pointer(&intVal))
  216. }
  217. // Uint is a Godot C uint wrapper
  218. type Uint uint
  219. func (u Uint) getBase() C.uint { //nolint:unused
  220. return C.uint(u)
  221. }
  222. // Uint8T is a Godot C uint8_t wrapper
  223. type Uint8T uint8
  224. func (u Uint8T) getBase() C.uint8_t {
  225. return C.uint8_t(u)
  226. }
  227. // Uint32T is a Godot C uint32_t wrapper
  228. type Uint32T uint32
  229. func (u Uint32T) getBase() C.uint32_t { //nolint:unused
  230. return C.uint32_t(u)
  231. }
  232. // Uint64T is a Godot C uint64_t wrapper
  233. type Uint64T uint64
  234. func (u Uint64T) getBase() C.uint64_t {
  235. return C.uint64_t(u)
  236. }
  237. // newWcharT will convert the given C.wchar_t into a Go string
  238. func newWcharT(str *C.wchar_t) WcharT {
  239. goStr, err := wchar.WcharStringPtrToGoString(unsafe.Pointer(str))
  240. if err != nil {
  241. log.Println("Error converting wchar_t to Go string:", err)
  242. }
  243. return WcharT(goStr)
  244. }
  245. // WcharT is a Godot C wchar_t wrapper
  246. type WcharT string
  247. func (w WcharT) getBase() *C.wchar_t {
  248. wcharString, err := wchar.FromGoString(string(w))
  249. if err != nil {
  250. log.Println("Error decoding WcharT:", err)
  251. }
  252. return (*C.wchar_t)(wcharString.Pointer())
  253. }
  254. // AsString converts a WCharT into a string
  255. func (w WcharT) AsString() String {
  256. return NewStringWithWideString(string(w))
  257. }
  258. // ID will return the Godot object memory address as a string, which can
  259. // be used in an instance registry for registering classes.
  260. func (gdt Object) ID() string {
  261. return fmt.Sprintf("%p", gdt.base)
  262. }