瀏覽代碼

Add support for engine singletons

Use, e.g. Engine::get_singleton() to get the singleton object();
George Marques 4 年之前
父節點
當前提交
3a9ff8de7a
共有 1 個文件被更改,包括 26 次插入1 次删除
  1. 26 1
      binding_generator.py

+ 26 - 1
binding_generator.py

@@ -1,6 +1,7 @@
 #!/usr/bin/env python
 
 import json
+from os import set_blocking
 import re
 import shutil
 from pathlib import Path
@@ -66,6 +67,8 @@ builtin_classes = []
 # Key is class name, value is boolean where True means the class is refcounted.
 engine_classes = {}
 
+singletons = []
+
 
 def generate_builtin_bindings(api, output_dir, build_config):
     global builtin_classes
@@ -644,6 +647,7 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
 
 def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
     global engine_classes
+    global singletons
 
     include_gen_folder = Path(output_dir) / "include" / "godot_cpp" / "classes"
     source_gen_folder = Path(output_dir) / "src" / "classes"
@@ -651,7 +655,7 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
     include_gen_folder.mkdir(parents=True, exist_ok=True)
     source_gen_folder.mkdir(parents=True, exist_ok=True)
 
-    # First create map of classes.
+    # First create map of classes and singletons.
     for class_api in api["classes"]:
         # TODO: Properly setup this singleton since it conflicts with ClassDB in the bindings.
         if class_api["name"] == "ClassDB":
@@ -659,6 +663,8 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
         engine_classes[class_api["name"]] = class_api["is_refcounted"]
     for native_struct in api["native_structures"]:
         engine_classes[native_struct["name"]] = False
+    for singleton in api["singletons"]:
+        singletons.append(singleton["name"])
 
     for class_api in api["classes"]:
         # TODO: Properly setup this singleton since it conflicts with ClassDB in the bindings.
@@ -768,10 +774,12 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
 
 
 def generate_engine_class_header(class_api, used_classes, fully_used_classes, use_template_get_node):
+    global singletons
     result = []
 
     class_name = class_api["name"]
     snake_class_name = camel_to_snake(class_name).upper()
+    is_singleton = class_name in singletons
 
     add_header(f"{snake_class_name.lower()}.hpp", result)
 
@@ -819,6 +827,10 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
             result.append("\t};")
             result.append("")
 
+    if is_singleton:
+        result.append(f"\tstatic {class_name} *get_singleton();")
+        result.append("")
+
     if "methods" in class_api:
         for method in class_api["methods"]:
             if method["is_virtual"]:
@@ -897,11 +909,13 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
 
 
 def generate_engine_class_source(class_api, used_classes, fully_used_classes, use_template_get_node):
+    global singletons
     result = []
 
     class_name = class_api["name"]
     snake_class_name = camel_to_snake(class_name)
     inherits = class_api["inherits"] if "inherits" in class_api else "Wrapped"
+    is_singleton = class_name in singletons
 
     add_header(f"{snake_class_name}.cpp", result)
 
@@ -920,6 +934,17 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us
     result.append("namespace godot {")
     result.append("")
 
+    if is_singleton:
+        result.append(f"{class_name} *{class_name}::get_singleton() {{")
+        result.append(f'\tstatic GDNativeObjectPtr singleton_obj = internal::interface->global_get_singleton("{class_name}");')
+        result.append("#ifdef DEBUG_ENABLED")
+        result.append('\tERR_FAIL_COND_V(singleton_obj == nullptr, nullptr);')
+        result.append("#endif // DEBUG_ENABLED")
+        result.append(f'\tstatic {class_name} *singleton = reinterpret_cast<{class_name} *>(internal::interface->object_get_instance_binding(singleton_obj, internal::token, &{class_name}::___binding_callbacks));')
+        result.append("\treturn singleton;")
+        result.append("}")
+        result.append("")
+
     if "methods" in class_api:
         for method in class_api["methods"]:
             if method["is_virtual"]: