diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7da0ce1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Objects. +.scons-cache/ +*.os + +# SConstruct +.sconf_temp +.sconsign.dblite +*.pyc + +# MacOS +.DS_Store + +# Editors +.vscode/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..0538c5d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,150 @@ +project(godot-cpp-test) +cmake_minimum_required(VERSION 3.6) + +set(GODOT_GDEXTENSION_DIR ../gdextension/ CACHE STRING "Path to GDExtension interface header directory") +set(CPP_BINDINGS_PATH ../ CACHE STRING "Path to C++ bindings") + +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(TARGET_PATH x11) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(TARGET_PATH win64) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + set(TARGET_PATH macos) +else() + message(FATAL_ERROR "Not implemented support for ${CMAKE_SYSTEM_NAME}") +endif() + +# Change the output directory to the bin directory +set(BUILD_PATH ${CMAKE_SOURCE_DIR}/bin/${TARGET_PATH}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${BUILD_PATH}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${BUILD_PATH}") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${BUILD_PATH}") +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}") +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}") +SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}") +SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}") +SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}") +SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}") + +# Set the c++ standard to c++17 +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(GODOT_COMPILE_FLAGS ) +set(GODOT_LINKER_FLAGS ) + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + # using Visual Studio C++ + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /EHsc /WX") # /GF /MP + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /DTYPED_METHOD_BIND") + + if(CMAKE_BUILD_TYPE MATCHES Debug) + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi + else() + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MD /O2") # /Oy /GL /Gy + STRING(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) + endif(CMAKE_BUILD_TYPE MATCHES Debug) + + # Disable conversion warning, truncation, unreferenced var, signed mismatch + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /wd4244 /wd4305 /wd4101 /wd4018 /wd4267") + + add_definitions(-DNOMINMAX) + + # Unkomment for warning level 4 + #if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") + # string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + #endif() + +else() + +#elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + # using Clang +#elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + # using GCC and maybe MinGW? + + set(GODOT_LINKER_FLAGS "-static-libgcc -static-libstdc++ -Wl,-R,'$$ORIGIN'") + + # Hmm.. maybe to strikt? + set(GODOT_COMPILE_FLAGS "-fPIC -g -Wwrite-strings") + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wchar-subscripts -Wcomment -Wdisabled-optimization") + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wformat -Wformat=2 -Wformat-security -Wformat-y2k") + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wimport -Winit-self -Winline -Winvalid-pch -Werror") + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wmissing-braces -Wmissing-format-attribute") + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wmissing-include-dirs -Wmissing-noreturn -Wpacked -Wpointer-arith") + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wredundant-decls -Wreturn-type -Wsequence-point") + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wswitch -Wswitch-enum -Wtrigraphs") + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wuninitialized -Wunknown-pragmas -Wunreachable-code -Wunused-label") + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wunused-value -Wvariadic-macros -Wvolatile-register-var -Wno-error=attributes") + + # -Wshadow -Wextra -Wall -Weffc++ -Wfloat-equal -Wstack-protector -Wunused-parameter -Wsign-compare -Wunused-variable -Wcast-align + # -Wunused-function -Wstrict-aliasing -Wstrict-aliasing=2 -Wmissing-field-initializers + + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android") + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wno-ignored-attributes") + endif() + + if(CMAKE_BUILD_TYPE MATCHES Debug) + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0") + else() + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3") + endif(CMAKE_BUILD_TYPE MATCHES Debug) +endif() + +# Get Sources +file(GLOB_RECURSE SOURCES src/*.c**) +file(GLOB_RECURSE HEADERS include/*.h**) + +# Define our godot-cpp library +add_library(${PROJECT_NAME} SHARED ${SOURCES} ${HEADERS}) + +target_include_directories(${PROJECT_NAME} SYSTEM + PRIVATE + ${CPP_BINDINGS_PATH}/include + ${CPP_BINDINGS_PATH}/gen/include + ${GODOT_GDEXTENSION_DIR} +) + +# Create the correct name (godot.os.build_type.system_bits) +# Synchronized with godot-cpp's CMakeLists.txt + +set(BITS 32) +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(BITS 64) +endif(CMAKE_SIZEOF_VOID_P EQUAL 8) + +if(CMAKE_BUILD_TYPE MATCHES Debug) + set(GODOT_CPP_BUILD_TYPE Debug) +else() + set(GODOT_CPP_BUILD_TYPE Release) +endif() + +string(TOLOWER ${CMAKE_SYSTEM_NAME} SYSTEM_NAME) +string(TOLOWER ${GODOT_CPP_BUILD_TYPE} BUILD_TYPE) + +if(ANDROID) + # Added the android abi after system name + set(SYSTEM_NAME ${SYSTEM_NAME}.${ANDROID_ABI}) +endif() + +if(CMAKE_VERSION VERSION_GREATER "3.13") + target_link_directories(${PROJECT_NAME} + PRIVATE + ${CPP_BINDINGS_PATH}/bin/ + ) + + target_link_libraries(${PROJECT_NAME} + godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}$<$>:.${BITS}> + ) +else() + target_link_libraries(${PROJECT_NAME} + ${CPP_BINDINGS_PATH}/bin/libgodot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}$<$>:.${BITS}>.a + ) +endif() + +# Add the compile flags +set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS}) +set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS ${GODOT_LINKER_FLAGS}) + +set_property(TARGET ${PROJECT_NAME} PROPERTY OUTPUT_NAME "gdexample") diff --git a/README.md b/README.md new file mode 100644 index 0000000..3c2c038 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# discord-rpc-godot +dont forget to run the following command if you clone this project or the godot-cpp folder will be empty +```sh +git submodule update --init +``` \ No newline at end of file diff --git a/SConstruct b/SConstruct new file mode 100644 index 0000000..a99466f --- /dev/null +++ b/SConstruct @@ -0,0 +1,32 @@ +#!/usr/bin/env python +import os +import sys + +env = SConscript("./godot-cpp/SConstruct") + +# For the reference: +# - CCFLAGS are compilation flags shared between C and C++ +# - CFLAGS are for C-specific compilation flags +# - CXXFLAGS are for C++-specific compilation flags +# - CPPFLAGS are for pre-processor flags +# - CPPDEFINES are for pre-processor defines +# - LINKFLAGS are for linking flags + +# tweak this if you want to use different folders, or more folders, to store your source code in. +env.Append(CPPPATH=["src/"]) +sources = Glob("src/*.cpp") + +if env["platform"] == "macos": + library = env.SharedLibrary( + "demo/bin/libgdexample.{}.{}.framework/libgdexample.{}.{}".format( + env["platform"], env["target"], env["platform"], env["target"] + ), + source=sources, + ) +else: + library = env.SharedLibrary( + "demo/bin/libgdexample{}{}".format(env["suffix"], env["SHLIBSUFFIX"]), + source=sources, + ) + +Default(library) diff --git a/demo/.gitignore b/demo/.gitignore new file mode 100644 index 0000000..71dbfb4 --- /dev/null +++ b/demo/.gitignore @@ -0,0 +1,4 @@ +# Godot +.godot/ +#Visual Studio +.vs/ diff --git a/demo/bin/.gitignore b/demo/bin/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/demo/bin/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/demo/default_env.tres b/demo/default_env.tres new file mode 100644 index 0000000..0645b88 --- /dev/null +++ b/demo/default_env.tres @@ -0,0 +1,7 @@ +[gd_resource type="Environment" load_steps=2 format=3 uid="uid://dtd3q2x2ulcsi"] + +[sub_resource type="Sky" id="1"] + +[resource] +background_mode = 2 +sky = SubResource("1") diff --git a/demo/example.gdextension b/demo/example.gdextension new file mode 100644 index 0000000..6d53405 --- /dev/null +++ b/demo/example.gdextension @@ -0,0 +1,22 @@ +[configuration] + +entry_symbol = "example_library_init" + +[libraries] + +macos.debug = "res://bin/libgdexample.macos.template_debug.framework" +macos.release = "res://bin/libgdexample.macos.template_release.framework" +windows.debug.x86_32 = "res://bin/libgdexample.windows.template_debug.x86_32.dll" +windows.release.x86_32 = "res://bin/libgdexample.windows.template_release.x86_32.dll" +windows.debug.x86_64 = "res://bin/libgdexample.windows.template_debug.x86_64.dll" +windows.release.x86_64 = "res://bin/libgdexample.windows.template_release.x86_64.dll" +linux.debug.x86_64 = "res://bin/libgdexample.linux.template_debug.x86_64.so" +linux.release.x86_64 = "res://bin/libgdexample.linux.template_release.x86_64.so" +linux.debug.arm64 = "res://bin/libgdexample.linux.template_debug.arm64.so" +linux.release.arm64 = "res://bin/libgdexample.linux.template_release.arm64.so" +linux.debug.rv64 = "res://bin/libgdexample.linux.template_debug.rv64.so" +linux.release.rv64 = "res://bin/libgdexample.linux.template_release.rv64.so" +android.debug.x86_64 = "res://bin/libgdexample.android.template_debug.x86_64.so" +android.release.x86_64 = "res://bin/libgdexample.android.template_release.x86_64.so" +android.debug.arm64 = "res://bin/libgdexample.android.template_debug.arm64.so" +android.release.arm64 = "res://bin/libgdexample.android.template_release.arm64.so" diff --git a/demo/icon.png b/demo/icon.png new file mode 100644 index 0000000..c98fbb6 Binary files /dev/null and b/demo/icon.png differ diff --git a/demo/icon.png.import b/demo/icon.png.import new file mode 100644 index 0000000..8a7c8b0 --- /dev/null +++ b/demo/icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cswr8vy4lt7dt" +path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.png" +dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/demo/main.gd b/demo/main.gd new file mode 100644 index 0000000..3858cc7 --- /dev/null +++ b/demo/main.gd @@ -0,0 +1,80 @@ +extends Node + +func _ready(): + # Bind signals + prints("Signal bind") + $Button.button_up.connect($Example.emit_custom_signal.bind("Button", 42)) + + prints("") + + # To string. + prints("To string") + prints(" Example --> ", $Example.to_string()) + prints(" ExampleMin --> ", $Example/ExampleMin.to_string()) + + # Call static methods. + prints("Static method calls") + prints(" static (109)", Example.test_static(9, 100)); + Example.test_static2(); + + # Property list. + prints("Property list") + $Example.property_from_list = Vector3(100, 200, 300) + prints(" property value ", $Example.property_from_list) + + # Call methods. + prints("Instance method calls") + $Example.simple_func() + ($Example as Example).simple_const_func() # Force use of ptrcall + prints(" returned", $Example.return_something("some string")) + prints(" returned const", $Example.return_something_const()) + var null_ref = $Example.return_empty_ref() + prints(" returned empty ref", null_ref) + var ret_ref = $Example.return_extended_ref() + prints(" returned ref", ret_ref.get_instance_id(), ", id:", ret_ref.get_id()) + prints(" returned ", $Example.get_v4()) + prints(" test node argument", $Example.test_node_argument($Example)) + + prints("VarArg method calls") + var ref = ExampleRef.new() + prints(" sending ref: ", ref.get_instance_id(), "returned ref: ", $Example.extended_ref_checks(ref).get_instance_id()) + prints(" vararg args", $Example.varargs_func("some", "arguments", "to", "test")) + prints(" vararg_nv ret", $Example.varargs_func_nv("some", "arguments", "to", "test")) + $Example.varargs_func_void("some", "arguments", "to", "test") + + prints("Method calls with default values") + prints(" defval (300)", $Example.def_args()) + prints(" defval (250)", $Example.def_args(50)) + prints(" defval (150)", $Example.def_args(50, 100)) + + prints("Array and Dictionary") + prints(" test array", $Example.test_array()) + prints(" test tarray", $Example.test_tarray()) + prints(" test dictionary", $Example.test_dictionary()) + var array: Array[int] = [1, 2, 3] + $Example.test_tarray_arg(array) + + prints("String += operator") + prints(" test string +=", $Example.test_string_ops()) + + prints("PackedArray iterators") + prints(" test packed array iterators", $Example.test_vector_ops()) + + prints("Properties") + prints(" custom position is", $Example.group_subgroup_custom_position) + $Example.group_subgroup_custom_position = Vector2(50, 50) + prints(" custom position now is", $Example.group_subgroup_custom_position) + + prints("Constants") + prints(" FIRST", $Example.FIRST) + prints(" ANSWER_TO_EVERYTHING", $Example.ANSWER_TO_EVERYTHING) + prints(" CONSTANT_WITHOUT_ENUM", $Example.CONSTANT_WITHOUT_ENUM) + + prints("BitFields") + prints(" FLAG_ONE", Example.FLAG_ONE) + prints(" FLAG_TWO", Example.FLAG_TWO) + prints(" returned BitField", $Example.test_bitfield(0)) + prints(" returned BitField", $Example.test_bitfield(Example.FLAG_ONE | Example.FLAG_TWO)) + +func _on_Example_custom_signal(signal_name, value): + prints("Example emitted:", signal_name, value) diff --git a/demo/main.tscn b/demo/main.tscn new file mode 100644 index 0000000..ab1b91e --- /dev/null +++ b/demo/main.tscn @@ -0,0 +1,25 @@ +[gd_scene load_steps=2 format=3 uid="uid://dmx2xuigcpvt4"] + +[ext_resource type="Script" path="res://main.gd" id="1_c326s"] + +[node name="Node" type="Node"] +script = ExtResource("1_c326s") + +[node name="Example" type="Example" parent="."] + +[node name="ExampleMin" type="ExampleMin" parent="Example"] +layout_mode = 0 + +[node name="Label" type="Label" parent="Example"] +layout_mode = 0 +offset_left = 194.0 +offset_top = -2.0 +offset_right = 234.0 +offset_bottom = 21.0 + +[node name="Button" type="Button" parent="."] +offset_right = 79.0 +offset_bottom = 29.0 +text = "Click me!" + +[connection signal="custom_signal" from="Example" to="." method="_on_Example_custom_signal"] diff --git a/demo/project.godot b/demo/project.godot new file mode 100644 index 0000000..615cee8 --- /dev/null +++ b/demo/project.godot @@ -0,0 +1,28 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="GDExtension Test Project" +run/main_scene="res://main.tscn" +config/features=PackedStringArray("4.0") +config/icon="res://icon.png" + +[dotnet] + +project/assembly_name="GDExtension Test Project" + +[native_extensions] + +paths=["res://example.gdextension"] + +[rendering] + +environment/defaults/default_environment="res://default_env.tres" diff --git a/src/example.cpp b/src/example.cpp new file mode 100644 index 0000000..a94175d --- /dev/null +++ b/src/example.cpp @@ -0,0 +1,337 @@ +/* godot-cpp integration testing project. + * + * This is free and unencumbered software released into the public domain. + */ + +#include "example.h" + +#include + +#include +#include +#include + +using namespace godot; + +int ExampleRef::instance_count = 0; +int ExampleRef::last_id = 0; + +int ExampleRef::get_id() const { + return id; +} + +void ExampleRef::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_id"), &ExampleRef::get_id); +} + +ExampleRef::ExampleRef() { + id = ++last_id; + instance_count++; + + UtilityFunctions::print("ExampleRef ", itos(id), " created, current instance count: ", itos(instance_count)); +} + +ExampleRef::~ExampleRef() { + instance_count--; + UtilityFunctions::print("ExampleRef ", itos(id), " destroyed, current instance count: ", itos(instance_count)); +} + +int Example::test_static(int p_a, int p_b) { + return p_a + p_b; +} + +void Example::test_static2() { + UtilityFunctions::print(" void static"); +} + +int Example::def_args(int p_a, int p_b) { + return p_a + p_b; +} + +void Example::_notification(int p_what) { + UtilityFunctions::print("Notification: ", String::num(p_what)); +} + +bool Example::_set(const StringName &p_name, const Variant &p_value) { + String name = p_name; + if (name.begins_with("dproperty")) { + int64_t index = name.get_slicec('_', 1).to_int(); + dprop[index] = p_value; + return true; + } + if (name == "property_from_list") { + property_from_list = p_value; + return true; + } + return false; +} + +bool Example::_get(const StringName &p_name, Variant &r_ret) const { + String name = p_name; + if (name.begins_with("dproperty")) { + int64_t index = name.get_slicec('_', 1).to_int(); + r_ret = dprop[index]; + return true; + } + if (name == "property_from_list") { + r_ret = property_from_list; + return true; + } + return false; +} + +String Example::_to_string() const { + return "[ GDExtension::Example <--> Instance ID:" + uitos(get_instance_id()) + " ]"; +} + +void Example::_get_property_list(List *p_list) const { + p_list->push_back(PropertyInfo(Variant::VECTOR3, "property_from_list")); + for (int i = 0; i < 3; i++) { + p_list->push_back(PropertyInfo(Variant::VECTOR2, "dproperty_" + itos(i))); + } +} + +bool Example::_property_can_revert(const StringName &p_name) const { + if (p_name == StringName("property_from_list") && property_from_list != Vector3(42, 42, 42)) { + return true; + } else { + return false; + } +}; + +bool Example::_property_get_revert(const StringName &p_name, Variant &r_property) const { + if (p_name == StringName("property_from_list")) { + r_property = Vector3(42, 42, 42); + return true; + } else { + return false; + } +}; + +void Example::_bind_methods() { + // Methods. + ClassDB::bind_method(D_METHOD("simple_func"), &Example::simple_func); + ClassDB::bind_method(D_METHOD("simple_const_func"), &Example::simple_const_func); + ClassDB::bind_method(D_METHOD("return_something"), &Example::return_something); + ClassDB::bind_method(D_METHOD("return_something_const"), &Example::return_something_const); + ClassDB::bind_method(D_METHOD("return_empty_ref"), &Example::return_empty_ref); + ClassDB::bind_method(D_METHOD("return_extended_ref"), &Example::return_extended_ref); + ClassDB::bind_method(D_METHOD("extended_ref_checks", "ref"), &Example::extended_ref_checks); + + ClassDB::bind_method(D_METHOD("test_array"), &Example::test_array); + ClassDB::bind_method(D_METHOD("test_tarray_arg", "array"), &Example::test_tarray_arg); + ClassDB::bind_method(D_METHOD("test_tarray"), &Example::test_tarray); + ClassDB::bind_method(D_METHOD("test_dictionary"), &Example::test_dictionary); + ClassDB::bind_method(D_METHOD("test_node_argument"), &Example::test_node_argument); + ClassDB::bind_method(D_METHOD("test_string_ops"), &Example::test_string_ops); + ClassDB::bind_method(D_METHOD("test_vector_ops"), &Example::test_vector_ops); + + ClassDB::bind_method(D_METHOD("test_bitfield", "flags"), &Example::test_bitfield); + + ClassDB::bind_method(D_METHOD("def_args", "a", "b"), &Example::def_args, DEFVAL(100), DEFVAL(200)); + + ClassDB::bind_static_method("Example", D_METHOD("test_static", "a", "b"), &Example::test_static); + ClassDB::bind_static_method("Example", D_METHOD("test_static2"), &Example::test_static2); + + { + MethodInfo mi; + mi.arguments.push_back(PropertyInfo(Variant::STRING, "some_argument")); + mi.name = "varargs_func"; + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "varargs_func", &Example::varargs_func, mi); + } + + { + MethodInfo mi; + mi.arguments.push_back(PropertyInfo(Variant::STRING, "some_argument")); + mi.name = "varargs_func_nv"; + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "varargs_func_nv", &Example::varargs_func_nv, mi); + } + + { + MethodInfo mi; + mi.arguments.push_back(PropertyInfo(Variant::STRING, "some_argument")); + mi.name = "varargs_func_void"; + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "varargs_func_void", &Example::varargs_func_void, mi); + } + + // Properties. + ADD_GROUP("Test group", "group_"); + ADD_SUBGROUP("Test subgroup", "group_subgroup_"); + + ClassDB::bind_method(D_METHOD("get_custom_position"), &Example::get_custom_position); + ClassDB::bind_method(D_METHOD("get_v4"), &Example::get_v4); + ClassDB::bind_method(D_METHOD("set_custom_position", "position"), &Example::set_custom_position); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "group_subgroup_custom_position"), "set_custom_position", "get_custom_position"); + + // Signals. + ADD_SIGNAL(MethodInfo("custom_signal", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::INT, "value"))); + ClassDB::bind_method(D_METHOD("emit_custom_signal", "name", "value"), &Example::emit_custom_signal); + + // Constants. + BIND_ENUM_CONSTANT(FIRST); + BIND_ENUM_CONSTANT(ANSWER_TO_EVERYTHING); + + BIND_BITFIELD_FLAG(FLAG_ONE); + BIND_BITFIELD_FLAG(FLAG_TWO); + + BIND_CONSTANT(CONSTANT_WITHOUT_ENUM); + BIND_ENUM_CONSTANT(OUTSIDE_OF_CLASS); +} + +Example::Example() { + UtilityFunctions::print("Constructor."); +} + +Example::~Example() { + UtilityFunctions::print("Destructor."); +} + +// Methods. +void Example::simple_func() { + UtilityFunctions::print(" Simple func called."); +} + +void Example::simple_const_func() const { + UtilityFunctions::print(" Simple const func called."); +} + +String Example::return_something(const String &base) { + UtilityFunctions::print(" Return something called."); + return base; +} + +Viewport *Example::return_something_const() const { + UtilityFunctions::print(" Return something const called."); + if (is_inside_tree()) { + Viewport *result = get_viewport(); + return result; + } + return nullptr; +} + +Ref Example::return_empty_ref() const { + Ref ref; + return ref; +} + +ExampleRef *Example::return_extended_ref() const { + // You can instance and return a refcounted object like this, but keep in mind that refcounting starts with the returned object + // and it will be destroyed when all references are destroyed. If you store this pointer you run the risk of having a pointer + // to a destroyed object. + return memnew(ExampleRef()); +} + +Example *Example::test_node_argument(Example *p_node) const { + UtilityFunctions::print(" Test node argument called with ", p_node ? String::num(p_node->get_instance_id()) : "null"); + return p_node; +} + +Ref Example::extended_ref_checks(Ref p_ref) const { + // This is therefor the prefered way of instancing and returning a refcounted object: + Ref ref; + ref.instantiate(); + + UtilityFunctions::print(" Example ref checks called with value: ", p_ref->get_instance_id(), ", returning value: ", ref->get_instance_id()); + return ref; +} + +Variant Example::varargs_func(const Variant **args, GDExtensionInt arg_count, GDExtensionCallError &error) { + UtilityFunctions::print(" Varargs (Variant return) called with ", String::num((double)arg_count), " arguments"); + return arg_count; +} + +int Example::varargs_func_nv(const Variant **args, GDExtensionInt arg_count, GDExtensionCallError &error) { + UtilityFunctions::print(" Varargs (int return) called with ", String::num((double)arg_count), " arguments"); + return 42; +} + +void Example::varargs_func_void(const Variant **args, GDExtensionInt arg_count, GDExtensionCallError &error) { + UtilityFunctions::print(" Varargs (no return) called with ", String::num((double)arg_count), " arguments"); +} + +void Example::emit_custom_signal(const String &name, int value) { + emit_signal("custom_signal", name, value); +} + +Array Example::test_array() const { + Array arr; + + arr.resize(2); + arr[0] = Variant(1); + arr[1] = Variant(2); + + return arr; +} + +String Example::test_string_ops() const { + String s = String("A"); + s += "B"; + s += "C"; + s += char32_t(0x010E); + s = s + "E"; + return s; +} + +int Example::test_vector_ops() const { + PackedInt32Array arr; + arr.push_back(10); + arr.push_back(20); + arr.push_back(30); + arr.push_back(45); + int ret = 0; + for (const int32_t &E : arr) { + ret += E; + } + return ret; +} + +void Example::test_tarray_arg(const TypedArray &p_array) { + for (int i = 0; i < p_array.size(); i++) { + UtilityFunctions::print(p_array[i]); + } +} + +TypedArray Example::test_tarray() const { + TypedArray arr; + + arr.resize(2); + arr[0] = Vector2(1, 2); + arr[1] = Vector2(2, 3); + + return arr; +} + +Dictionary Example::test_dictionary() const { + Dictionary dict; + + dict["hello"] = "world"; + dict["foo"] = "bar"; + + return dict; +} + +BitField Example::test_bitfield(BitField flags) { + UtilityFunctions::print(" Got BitField: ", String::num_int64(flags)); + return flags; +} + +// Properties. +void Example::set_custom_position(const Vector2 &pos) { + custom_position = pos; +} + +Vector2 Example::get_custom_position() const { + return custom_position; +} + +Vector4 Example::get_v4() const { + return Vector4(1.2, 3.4, 5.6, 7.8); +} + +// Virtual function override. +bool Example::_has_point(const Vector2 &point) const { + Label *label = get_node