#serialization #godot #gdscript
Вопрос:
Давайте определим 2 класса
A.gd
class_name A
var v = null
func _init(v_):
v = v_
B.gd
class_name B
var v = null
Теперь, когда я пытаюсь использовать str2var/var2str, вот что я получаю
var a = A.new("aaa")
var b = B.new()
b.v = "bbb"
printt("var2str(a):", var2str(a))
printt("var2str(b):", var2str(b))
printt ("var2str(str2var(var2str(a))):", var2str(str2var(var2str(a))))
printt ("var2str(str2var(var2str(b))):", var2str(str2var(var2str(b))))
Выход:
var2str(a): Object(Reference,"script":Resource( "res://Scripts/AI/A.gd"),"v":"aaa")
var2str(b): Object(Reference,"script":Resource( "res://Scripts/AI/B.gd"),"v":"bbb")
var2str(str2var(var2str(a))): Object(Reference,"script":null)
var2str(str2var(var2str(b))): Object(Reference,"script":Resource( "res://Scripts/AI/B.gd"),"v":"bbb")
Почему str2var(a) не работает?
Как мне это исправить?
Ответ №1:
Решение
Исправьте это, сделав параметр необязательным, например:
class_name A
var v = null
func _init(v_ = null):
v = v_
В этом нет никакой ошибки. Я получаю этот вывод:
var2str(a): Object(Reference,"script":Resource( "res://A.gd"),"v":"aaa")
var2str(b): Object(Reference,"script":Resource( "res://B.gd"),"v":"bbb")
var2str(str2var(var2str(a))): Object(Reference,"script":Resource( "res://A.gd"),"v":"aaa")
var2str(str2var(var2str(b))): Object(Reference,"script":Resource( "res://B.gd"),"v":"bbb")
Проблема
Для абстрактного, str2var
не будет передавать никаких аргументов _init
. Он все равно не знал бы, что передать.
Остальная часть ответа — это процесс подтверждения, который str2var
приведет к вызову _init
без аргумента.
Когда я пробую ваш код, я получаю эту ошибку:
E 0:00:00.630 _create_instance: Condition "r_error.error != Variant::CallError::CALL_OK" is true. Returned: __null
<C Source> modules/gdscript/gdscript.cpp:121 @ _create_instance()
<Stack Trace> main.gd:12 @ _ready()
Мы можем найти строку, которая выдает ошибку _create_instance
, посмотрев на источник.
К сожалению, это не дает мне много информации. Итак, я решил поискать, как str2var
это реализовано.
Мы находим это внутри GDScriptFunctions::call
, здесь. Который звонит VariantParser::parse
, который звонит VariantParser::parse_value
. Нас интересует случай "Object"
(здесь). И это приводит к вызову ClassDB::instance(type)
. Там будет тип "Reference"
, а затем он будет задавать все свойства по мере их поступления. Быть первым "script":Resource("res://A.gd")
.
Когда мы установим сценарий (здесь), это приведет к вызову GDScript::instance_create
. Который вызывает GDScript::_create_instance
(здесь):
return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this) != NULL, unchecked_error)
Без аргумента для _init
( NULL
это массив аргументов и 0
количество аргументов). Это подпись для GDScript::_create_instance
:
GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError amp;r_error)
Конечно, initializer->call(instance, p_args, p_argcount, r_error);
терпит неудачу, потому _init
что требует аргументации. И мы находим строку, которая отбрасывает ошибку дальше вниз. Примечание: initializer
создается при разборе скрипта.
Комментарии:
1. Впечатляющий ответ, как всегда.