Godot/Gdscript: Почему str2var не работает с классами с помощью метода _init?

#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. Впечатляющий ответ, как всегда.