Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion example/project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,4 @@ paths=["res://addons/gode/binary/gode.gdextension"]
[rendering]

rendering_device/driver.windows="d3d12"
renderer/rendering_method="forward_plus"
textures/vram_compression/import_etc2_astc=true
13 changes: 13 additions & 0 deletions example/scripts/tests/runtime_integration_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ const PROPERTY_HINT_RESOURCE_TYPE = 17;
const PROPERTY_HINT_NODE_TYPE = 34;
const RUNTIME_ARRAY_RESOURCE_SCRIPT_PATH = "res://scripts/tests/runtime_array_resource.ts";

interface RuntimeExportInterfaceArrayElement {
label: string;
amount: number;
enabled: boolean;
tags: string[];
metadata: Record<string, number>;
}

function assert(condition: boolean, message: string): void {
if (!condition) {
throw new Error(message);
Expand Down Expand Up @@ -163,6 +171,9 @@ class RuntimeIntegrationTest extends RuntimeBaseModule.RuntimeIntegrationBase {
@Export()
editor_namespace_alias_resource_array: RuntimeExportTypes.RuntimeImportedResourceArray = [];

@Export()
editor_interface_array: RuntimeExportInterfaceArrayElement[] = [];

@Export()
editor_mixed_union: "automatic" | number = "automatic";

Expand Down Expand Up @@ -393,6 +404,7 @@ class RuntimeIntegrationTest extends RuntimeBaseModule.RuntimeIntegrationBase {
"editor_imported_generic_external_resource_array",
"editor_imported_generic_resource_dictionary",
"editor_namespace_alias_resource_array",
"editor_interface_array",
"editor_mixed_union",
"editor_mixed_object_union",
"editor_explicit_hint_enum",
Expand Down Expand Up @@ -443,6 +455,7 @@ class RuntimeIntegrationTest extends RuntimeBaseModule.RuntimeIntegrationBase {
assertArrayExportMetadata("editor_imported_generic_external_resource_array", `${VARIANT_TYPE_OBJECT}/${PROPERTY_HINT_RESOURCE_TYPE}:RuntimeExternalResource`);
assertDictionaryExportMetadata("editor_imported_generic_resource_dictionary", `${VARIANT_TYPE_STRING}:;${VARIANT_TYPE_OBJECT}/${PROPERTY_HINT_RESOURCE_TYPE}:RuntimeArrayResource`);
assertArrayExportMetadata("editor_namespace_alias_resource_array", `${VARIANT_TYPE_OBJECT}/${PROPERTY_HINT_RESOURCE_TYPE}:RuntimeArrayResource`);
assertArrayExportMetadata("editor_interface_array", `${VARIANT_TYPE_OBJECT}/${PROPERTY_HINT_RESOURCE_TYPE}:TypeScriptInterfaceResource`);
assertArrayExportMetadata("static_number_array", `${VARIANT_TYPE_FLOAT}:`);
assertArrayExportMetadata("static_custom_resource_array", `${VARIANT_TYPE_OBJECT}/${PROPERTY_HINT_RESOURCE_TYPE}:RuntimeArrayResource`);
assertDictionaryExportMetadata("static_record_dictionary", `${VARIANT_TYPE_STRING}:;${VARIANT_TYPE_FLOAT}:`);
Expand Down
22 changes: 22 additions & 0 deletions example/scripts/tests/tests_runner.gd
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,28 @@ func _run_next() -> void:
if current_test.get("editor_record_dictionary") != {"from_gdscript": 8}:
_fail("RuntimeIntegrationTest typed string-key Dictionary did not round-trip through ScriptInstance")
return
if not current_test.get("editor_interface_array").is_empty():
_fail("RuntimeIntegrationTest interface array default was not empty")
return
var interface_element: Object = ClassDB.instantiate("TypeScriptInterfaceResource")
current_test.set("editor_interface_array", [interface_element])
var interface_fields: Array[String] = []
for property in interface_element.get_property_list():
interface_fields.append(str(property.name))
if not interface_fields.has("label") or not interface_fields.has("amount") or not interface_fields.has("enabled") or not interface_fields.has("tags") or not interface_fields.has("metadata"):
_fail("RuntimeIntegrationTest interface array element did not expose interface fields")
return
if interface_element.get("label") != "" or interface_element.get("amount") != 0 or interface_element.get("enabled") != false:
_fail("RuntimeIntegrationTest interface array scalar fields did not use Godot defaults")
return
if not interface_element.get("tags").is_empty() or not interface_element.get("metadata").is_empty():
_fail("RuntimeIntegrationTest interface array container fields did not use Godot defaults")
return
interface_element.set("label", "configured")
interface_element.set("amount", 9)
if interface_element.get("label") != "configured" or interface_element.get("amount") != 9:
_fail("RuntimeIntegrationTest interface array element edits did not round-trip")
return
var int_key_dictionary := {}
int_key_dictionary[7] = "seven"
current_test.set("editor_int_key_map", int_key_dictionary)
Expand Down
50 changes: 50 additions & 0 deletions include/script/typescript_interface_resource.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#ifndef GODE_TYPESCRIPT_INTERFACE_RESOURCE_H
#define GODE_TYPESCRIPT_INTERFACE_RESOURCE_H

#include <godot_cpp/classes/resource.hpp>
#include <godot_cpp/templates/hash_map.hpp>
#include <godot_cpp/templates/vector.hpp>
#include <godot_cpp/variant/string_name.hpp>
#include <godot_cpp/variant/variant.hpp>

namespace gode {

class TypeScriptInterfaceResource : public godot::Resource {
GDCLASS(TypeScriptInterfaceResource, godot::Resource)

struct Schema {
godot::StringName interface_name;
godot::HashMap<godot::StringName, godot::Vector<godot::PropertyInfo>> interfaces;
};

static godot::HashMap<godot::StringName, Schema> schemas;

godot::StringName schema_id;
godot::Vector<godot::PropertyInfo> fields;
godot::HashMap<godot::StringName, godot::StringName> nested_interfaces;
godot::HashMap<godot::StringName, godot::StringName> nested_interface_arrays;
godot::HashMap<godot::StringName, godot::Variant> default_values;
godot::HashMap<godot::StringName, godot::Variant> values;

void apply_schema();
void configure_nested_value(const godot::StringName &p_name, const godot::Variant &p_value);

protected:
static void _bind_methods();
bool _set(const godot::StringName &p_name, const godot::Variant &p_value);
bool _get(const godot::StringName &p_name, godot::Variant &r_value) const;
void _get_property_list(godot::List<godot::PropertyInfo> *p_list) const;

public:
static void register_schema(
const godot::StringName &p_schema_id,
const godot::StringName &p_interface_name,
const godot::HashMap<godot::StringName, godot::Vector<godot::PropertyInfo>> &p_interfaces);
void configure(const godot::StringName &p_schema_id);
int64_t get_interface_field_count() const { return fields.size(); }
godot::StringName get_interface_field_name(int64_t p_index) const;
};

} // namespace gode

#endif // GODE_TYPESCRIPT_INTERFACE_RESOURCE_H
1 change: 1 addition & 0 deletions include/script/typescript_script.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class TypeScriptScript : public godot::ScriptExtension {
mutable godot::HashMap<godot::StringName, godot::MethodInfo> signals;
mutable godot::HashMap<godot::StringName, godot::PropertyInfo> properties;
mutable godot::Vector<godot::PropertyInfo> property_list;
mutable godot::HashMap<godot::StringName, godot::StringName> interface_array_schemas;
mutable godot::HashMap<godot::StringName, godot::Variant> property_defaults;
mutable godot::HashMap<godot::StringName, godot::Variant> constants;
mutable godot::HashMap<godot::StringName, int> member_lines;
Expand Down
2 changes: 2 additions & 0 deletions src/register_runtime_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "runtime/gode_runtime_bridge.h"
#include "runtime/node_runtime.h"
#include "script/typescript_language.h"
#include "script/typescript_interface_resource.h"
#include "script/typescript_loader.h"
#include "script/typescript_saver.h"
#include "script/typescript_script.h"
Expand All @@ -22,6 +23,7 @@ void initialize_gode_runtime_module(godot::ModuleInitializationLevel p_level) {
return;
}
GDREGISTER_CLASS(gode::TypeScriptScript);
GDREGISTER_CLASS(gode::TypeScriptInterfaceResource);
GDREGISTER_CLASS(gode::TypeScriptLanguage);
GDREGISTER_CLASS(gode::TypeScriptSaver);
GDREGISTER_CLASS(gode::TypeScriptLoader);
Expand Down
11 changes: 11 additions & 0 deletions src/script/script_instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "runtime/napi_error_utils.h"
#include "runtime/node_runtime.h"
#include "runtime/value_convert.h"
#include "script/typescript_interface_resource.h"
#include "script/typescript_script.h"
#include <v8-isolate.h>
#include <v8-locker.h>
Expand Down Expand Up @@ -332,6 +333,16 @@ void ScriptInstance::reload(bool p_keep_state) {
}

bool ScriptInstance::set(const StringName &p_name, const Variant &p_value) {
if (script.is_valid() && script->interface_array_schemas.has(p_name) && p_value.get_type() == Variant::ARRAY) {
const StringName schema_id = script->interface_array_schemas[p_name];
Array array = p_value;
for (int64_t i = 0; i < array.size(); i++) {
TypeScriptInterfaceResource *resource = Object::cast_to<TypeScriptInterfaceResource>(array[i]);
if (resource) {
resource->configure(schema_id);
}
}
}
if (placeholder) {
placeholder_properties[p_name] = p_value;
return true;
Expand Down
Loading