Skip to content

Commit

Permalink
Allow overriding how scripted objects are converted to strings
Browse files Browse the repository at this point in the history
solves #26796

- ADD `String to_string()` method to Object which can be overriden by `String _to_string()` in scripts
- ADD `String to_string(r_valid)` method to ScriptInstance to allow langauges to control how scripted objects are converted to strings
- IMPLEMENT to_string for GDScriptInstance, VisualScriptInstance, and NativeScriptInstance
- ADD Documentation about `Object.to_string` and `Object._to_string`
- Changed `Variant::operator String` to use `obj->to_string()`
  • Loading branch information
LeonardMeagher2 committed May 3, 2019
1 parent 5772f60 commit f7eb426
Show file tree
Hide file tree
Showing 14 changed files with 107 additions and 1 deletion.
1 change: 1 addition & 0 deletions core/core_string_names.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ CoreStringNames::CoreStringNames() :
_iter_next(StaticCString::create("_iter_next")),
_iter_get(StaticCString::create("_iter_get")),
get_rid(StaticCString::create("get_rid")),
_to_string(StaticCString::create("_to_string")),
#ifdef TOOLS_ENABLED
_sections_unfolded(StaticCString::create("_sections_unfolded")),
#endif
Expand Down
1 change: 1 addition & 0 deletions core/core_string_names.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class CoreStringNames {
StringName _iter_next;
StringName _iter_get;
StringName get_rid;
StringName _to_string;
#ifdef TOOLS_ENABLED
StringName _sections_unfolded;
#endif
Expand Down
12 changes: 12 additions & 0 deletions core/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,16 @@ void Object::notification(int p_notification, bool p_reversed) {
}
}

String Object::to_string() {
if (script_instance) {
bool valid;
String ret = script_instance->to_string(&valid);
if (valid)
return ret;
}
return "[" + get_class() + ":" + itos(get_instance_id()) + "]";
}

void Object::_changed_callback(Object *p_changed, const char *p_prop) {
}

Expand Down Expand Up @@ -1682,6 +1692,7 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_property_list"), &Object::_get_property_list_bind);
ClassDB::bind_method(D_METHOD("get_method_list"), &Object::_get_method_list_bind);
ClassDB::bind_method(D_METHOD("notification", "what", "reversed"), &Object::notification, DEFVAL(false));
ClassDB::bind_method(D_METHOD("to_string"), &Object::to_string);
ClassDB::bind_method(D_METHOD("get_instance_id"), &Object::get_instance_id);

ClassDB::bind_method(D_METHOD("set_script", "script"), &Object::set_script);
Expand Down Expand Up @@ -1768,6 +1779,7 @@ void Object::_bind_methods() {

#endif
BIND_VMETHOD(MethodInfo("_init"));
BIND_VMETHOD(MethodInfo(Variant::STRING, "_to_string"));

BIND_CONSTANT(NOTIFICATION_POSTINITIALIZE);
BIND_CONSTANT(NOTIFICATION_PREDELETE);
Expand Down
1 change: 1 addition & 0 deletions core/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,7 @@ class Object {
void call_multilevel(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper

void notification(int p_notification, bool p_reversed = false);
String to_string();

//used mainly by script, get and set all INCLUDING string
virtual Variant getvar(const Variant &p_key, bool *r_valid = NULL) const;
Expand Down
1 change: 1 addition & 0 deletions core/script_language.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include "script_language.h"

#include "core/core_string_names.h"
#include "core/project_settings.h"

ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES];
Expand Down
5 changes: 5 additions & 0 deletions core/script_language.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ class ScriptInstance {
virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount);
virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount);
virtual void notification(int p_notification) = 0;
virtual String to_string(bool *r_valid) {
if (r_valid)
*r_valid = false;
return String();
}

//this is used by script languages that keep a reference counter of their own
//you can make make Ref<> not die when it reaches zero, so deleting the reference
Expand Down
2 changes: 1 addition & 1 deletion core/variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1582,7 +1582,7 @@ Variant::operator String() const {
};
};
#endif
return "[" + _get_obj().obj->get_class() + ":" + itos(_get_obj().obj->get_instance_id()) + "]";
return _get_obj().obj->to_string();
} else
return "[Object:null]";

Expand Down
16 changes: 16 additions & 0 deletions doc/classes/Object.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,22 @@
Sets a property. Returns [code]true[/code] if the [code]property[/code] exists.
</description>
</method>
<method name="_to_string" qualifiers="virtual">
<return type="String">
</return>
<description>
Returns a [String] representing the object. Default is [code]"[ClassName:RID]"[/code].
Override this method to customize the [String] representation of the object when it's being converted to a string, for example: [code]print(obj)[/code].
</description>
</method>
<method name="to_string">
<return type="String">
</return>
<description>
Returns a [String] representing the object. Default is [code]"[ClassName:RID]"[/code].
Override the method [method _to_string] to customize the [String] representation.
</description>
</method>
<method name="add_user_signal">
<return type="void">
</return>
Expand Down
22 changes: 22 additions & 0 deletions modules/gdnative/nativescript/nativescript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

#include "gdnative/gdnative.h"

#include "core/core_string_names.h"
#include "core/global_constants.h"
#include "core/io/file_access_encrypted.h"
#include "core/os/file_access.h"
Expand Down Expand Up @@ -771,6 +772,27 @@ void NativeScriptInstance::notification(int p_notification) {
call_multilevel("_notification", args, 1);
}

String NativeScriptInstance::to_string(bool *r_valid) {
if (has_method(CoreStringNames::get_singleton()->_to_string)) {
Variant::CallError ce;
Variant ret = call(CoreStringNames::get_singleton()->_to_string, NULL, 0, ce);
if (ce.error == Variant::CallError::CALL_OK) {
if (ret.get_type() != Variant::STRING) {
if (r_valid)
*r_valid = false;
ERR_EXPLAIN("Wrong type for " + CoreStringNames::get_singleton()->_to_string + ", must be a String.");
ERR_FAIL_V(String());
}
if (r_valid)
*r_valid = true;
return ret.operator String();
}
}
if (r_valid)
*r_valid = false;
return String();
}

void NativeScriptInstance::refcount_incremented() {
Variant::CallError err;
call("_refcount_incremented", NULL, 0, err);
Expand Down
1 change: 1 addition & 0 deletions modules/gdnative/nativescript/nativescript.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ class NativeScriptInstance : public ScriptInstance {
virtual bool has_method(const StringName &p_method) const;
virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error);
virtual void notification(int p_notification);
String to_string(bool *r_valid);
virtual Ref<Script> get_script() const;
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
Expand Down
22 changes: 22 additions & 0 deletions modules/gdscript/gdscript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include "gdscript.h"

#include "core/core_string_names.h"
#include "core/engine.h"
#include "core/global_constants.h"
#include "core/io/file_access_encrypted.h"
Expand Down Expand Up @@ -1234,6 +1235,27 @@ void GDScriptInstance::notification(int p_notification) {
}
}

String GDScriptInstance::to_string(bool *r_valid) {
if (has_method(CoreStringNames::get_singleton()->_to_string)) {
Variant::CallError ce;
Variant ret = call(CoreStringNames::get_singleton()->_to_string, NULL, 0, ce);
if (ce.error == Variant::CallError::CALL_OK) {
if (ret.get_type() != Variant::STRING) {
if (r_valid)
*r_valid = false;
ERR_EXPLAIN("Wrong type for " + CoreStringNames::get_singleton()->_to_string + ", must be a String.");
ERR_FAIL_V(String());
}
if (r_valid)
*r_valid = true;
return ret.operator String();
}
}
if (r_valid)
*r_valid = false;
return String();
}

Ref<Script> GDScriptInstance::get_script() const {

return script;
Expand Down
1 change: 1 addition & 0 deletions modules/gdscript/gdscript.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ class GDScriptInstance : public ScriptInstance {
Variant debug_get_member_by_index(int p_idx) const { return members[p_idx]; }

virtual void notification(int p_notification);
String to_string(bool *r_valid);

virtual Ref<Script> get_script() const;

Expand Down
22 changes: 22 additions & 0 deletions modules/visual_script/visual_script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include "visual_script.h"

#include "core/core_string_names.h"
#include "core/os/os.h"
#include "core/project_settings.h"
#include "scene/main/node.h"
Expand Down Expand Up @@ -1976,6 +1977,27 @@ void VisualScriptInstance::notification(int p_notification) {
call(VisualScriptLanguage::singleton->notification, &whatp, 1, ce); //do as call
}

String VisualScriptInstance::to_string(bool *r_valid) {
if (has_method(CoreStringNames::get_singleton()->_to_string)) {
Variant::CallError ce;
Variant ret = call(CoreStringNames::get_singleton()->_to_string, NULL, 0, ce);
if (ce.error == Variant::CallError::CALL_OK) {
if (ret.get_type() != Variant::STRING) {
if (r_valid)
*r_valid = false;
ERR_EXPLAIN("Wrong type for " + CoreStringNames::get_singleton()->_to_string + ", must be a String.");
ERR_FAIL_V(String());
}
if (r_valid)
*r_valid = true;
return ret.operator String();
}
}
if (r_valid)
*r_valid = false;
return String();
}

Ref<Script> VisualScriptInstance::get_script() const {

return script;
Expand Down
1 change: 1 addition & 0 deletions modules/visual_script/visual_script.h
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ class VisualScriptInstance : public ScriptInstance {
virtual bool has_method(const StringName &p_method) const;
virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error);
virtual void notification(int p_notification);
String to_string(bool *r_valid);

bool set_variable(const StringName &p_variable, const Variant &p_value) {

Expand Down

0 comments on commit f7eb426

Please sign in to comment.