Просмотр исходного кода

Implement CSharpScript::get_script_method_list and related functionality.

Ben Rog-Wilhelm 6 лет назад
Родитель
Сommit
f13f2d512f

+ 3 - 0
editor/property_selector.cpp

@@ -210,6 +210,9 @@ void PropertySelector::_update_search() {
 
 				methods.push_back(MethodInfo("*Script Methods"));
 				Object::cast_to<Script>(obj)->get_script_method_list(&methods);
+				// TODO: Filter out things unsuitable for explicit calls, like constructors.
+
+				// TODO: We should handle script class hierarchies somehow. Right now we don't; it's unclear where this functionality should live.
 			}
 
 			StringName base = base_type;

+ 30 - 0
modules/mono/csharp_script.cpp

@@ -2474,6 +2474,17 @@ void CSharpScript::set_source_code(const String &p_code) {
 #endif
 }
 
+void CSharpScript::get_script_method_list(List<MethodInfo> *p_list) const {
+
+	if (!script_class)
+		return;
+
+	const Vector<GDMonoMethod *> &methods = script_class->get_all_methods();
+	for (int i = 0; i < methods.size(); ++i) {
+		p_list->push_back(methods[i]->get_method_info());
+	}
+}
+
 bool CSharpScript::has_method(const StringName &p_method) const {
 
 	if (!script_class)
@@ -2482,6 +2493,25 @@ bool CSharpScript::has_method(const StringName &p_method) const {
 	return script_class->has_fetched_method_unknown_params(p_method);
 }
 
+MethodInfo CSharpScript::get_method_info(const StringName &p_method) const {
+
+	if (!script_class)
+		return MethodInfo();
+
+	GDMonoClass *top = script_class;
+
+	while (top && top != native) {
+		GDMonoMethod *params = top->get_fetched_method_unknown_params(p_method);
+		if (params) {
+			return params->get_method_info();
+		}
+
+		top = top->get_parent_class();
+	}
+
+	return MethodInfo();
+}
+
 Error CSharpScript::reload(bool p_keep_state) {
 
 	bool has_instances;

+ 2 - 2
modules/mono/csharp_script.h

@@ -174,9 +174,9 @@ public:
 	virtual Ref<Script> get_base_script() const;
 	virtual ScriptLanguage *get_language() const;
 
-	/* TODO */ virtual void get_script_method_list(List<MethodInfo> *p_list) const {}
+	virtual void get_script_method_list(List<MethodInfo> *p_list) const;
 	bool has_method(const StringName &p_method) const;
-	/* TODO */ MethodInfo get_method_info(const StringName &p_method) const { return MethodInfo(); }
+	MethodInfo get_method_info(const StringName &p_method) const;
 
 	virtual int get_member_line(const StringName &p_member) const;
 

+ 27 - 0
modules/mono/mono_gd/gd_mono_class.cpp

@@ -139,6 +139,20 @@ void GDMonoClass::fetch_attributes() {
 	attrs_fetched = true;
 }
 
+void GDMonoClass::fetch_method_list() {
+
+	if (method_list_fetched)
+		return;
+
+	void *iter = NULL;
+	MonoMethod *raw_method = NULL;
+	while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != NULL) {
+		method_list.push_back(memnew(GDMonoMethod(mono_method_get_name(raw_method), raw_method)));
+	}
+
+	method_list_fetched = true;
+}
+
 void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base) {
 
 	CRASH_COND(!CACHED_CLASS(GodotObject)->is_assignable_from(this));
@@ -151,6 +165,7 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base
 	while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != NULL) {
 		StringName name = mono_method_get_name(raw_method);
 
+		// get_method implicitly fetches methods and adds them to this->methods
 		GDMonoMethod *method = get_method(raw_method, name);
 		ERR_CONTINUE(!method);
 
@@ -449,6 +464,13 @@ const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() {
 	return delegates_list;
 }
 
+const Vector<GDMonoMethod *> &GDMonoClass::get_all_methods() {
+	if (!method_list_fetched)
+		fetch_method_list();
+
+	return method_list;
+}
+
 GDMonoClass::GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly) {
 
 	namespace_name = p_namespace;
@@ -460,6 +482,7 @@ GDMonoClass::GDMonoClass(const StringName &p_namespace, const StringName &p_name
 	attributes = NULL;
 
 	methods_fetched = false;
+	method_list_fetched = false;
 	fields_fetched = false;
 	properties_fetched = false;
 	delegates_fetched = false;
@@ -512,4 +535,8 @@ GDMonoClass::~GDMonoClass() {
 
 		methods.clear();
 	}
+
+	for (int i = 0; i < method_list.size(); ++i) {
+		memdelete(method_list[i]);
+	}
 }

+ 9 - 0
modules/mono/mono_gd/gd_mono_class.h

@@ -79,9 +79,14 @@ class GDMonoClass {
 	bool attrs_fetched;
 	MonoCustomAttrInfo *attributes;
 
+	// This contains both the original method names and remapped method names from the native Godot identifiers to the C# functions.
+	// Most method-related functions refer to this and it's possible this is unintuitive for outside users; this may be a prime location for refactoring or renaming.
 	bool methods_fetched;
 	HashMap<MethodKey, GDMonoMethod *, MethodKey::Hasher> methods;
 
+	bool method_list_fetched;
+	Vector<GDMonoMethod *> method_list;
+
 	bool fields_fetched;
 	Map<StringName, GDMonoField *> fields;
 	Vector<GDMonoField *> fields_list;
@@ -97,6 +102,8 @@ class GDMonoClass {
 	friend class GDMonoAssembly;
 	GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly);
 
+	void fetch_method_list();
+
 public:
 	static String get_full_name(MonoClass *p_mono_class);
 	static MonoType *get_mono_type(MonoClass *p_mono_class);
@@ -143,6 +150,8 @@ public:
 
 	const Vector<GDMonoClass *> &get_all_delegates();
 
+	const Vector<GDMonoMethod *> &get_all_methods();
+
 	~GDMonoClass();
 };
 

+ 27 - 0
modules/mono/mono_gd/gd_mono_method.cpp

@@ -68,6 +68,10 @@ void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) {
 
 		param_types.push_back(param_type);
 	}
+
+	// clear the cache
+	method_info_fetched = false;
+	method_info = MethodInfo();
 }
 
 bool GDMonoMethod::is_static() {
@@ -246,11 +250,34 @@ void GDMonoMethod::get_parameter_types(Vector<ManagedType> &types) const {
 	}
 }
 
+const MethodInfo &GDMonoMethod::get_method_info() {
+
+	if (!method_info_fetched) {
+		method_info.name = name;
+		method_info.return_val = PropertyInfo(GDMonoMarshal::managed_to_variant_type(return_type), "");
+
+		Vector<StringName> names;
+		get_parameter_names(names);
+
+		for (int i = 0; i < params_count; ++i) {
+			method_info.arguments.push_back(PropertyInfo(GDMonoMarshal::managed_to_variant_type(param_types[i]), names[i]));
+		}
+
+		// TODO: default arguments
+
+		method_info_fetched = true;
+	}
+
+	return method_info;
+}
+
 GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) {
 	name = p_name;
 
 	mono_method = p_method;
 
+	method_info_fetched = false;
+
 	attrs_fetched = false;
 	attributes = NULL;
 

+ 5 - 0
modules/mono/mono_gd/gd_mono_method.h

@@ -43,6 +43,9 @@ class GDMonoMethod : public GDMonoClassMember {
 	ManagedType return_type;
 	Vector<ManagedType> param_types;
 
+	bool method_info_fetched;
+	MethodInfo method_info;
+
 	bool attrs_fetched;
 	MonoCustomAttrInfo *attributes;
 
@@ -83,6 +86,8 @@ public:
 	void get_parameter_names(Vector<StringName> &names) const;
 	void get_parameter_types(Vector<ManagedType> &types) const;
 
+	const MethodInfo &get_method_info();
+
 	GDMonoMethod(StringName p_name, MonoMethod *p_method);
 	~GDMonoMethod();
 };