获取属性列表
今天搂草打兔,取得了脚本内容
因为已能取得属性值,那就再进一步,取得属性名列表
if (SameText(drGet.propertyName, "propertyNames", DRGRAPH_FLAG_CASESENSITIVE)) {List<PropertyInfo> *p_list = new List<PropertyInfo>;bool p_reversed = true;destObject->get_property_list(p_list, p_reversed);cofs << "OK";for (List<PropertyInfo>::Iterator it = p_list->begin(); it != p_list->end(); ++it) {Variant value = destObject->get(it->name);cofs << str_format(U"%s[%s] = %s", it->name.utf8().get_data(),VarType2String(it->type).c_str(), value.operator String().utf8().get_data());}delete p_list;cofs << GetObjectHint(destObject);
}
相应地,可以取得函数名列表、子对象列表
if (SameText(drGet.propertyName, "methodNames", DRGRAPH_FLAG_CASESENSITIVE)) {List<MethodInfo> *p_list = new List<MethodInfo>;destObject->get_method_list(p_list);cofs << "OK";for (List<MethodInfo>::Iterator it = p_list->begin(); it != p_list->end(); ++it) {String content = it->name + "(";for (List<PropertyInfo>::Iterator iter = it->arguments.begin(); iter != it->arguments.end(); ++iter) {if (iter != it->arguments.begin())content += ", ";content += str_format("%s %s", VarType2String(iter->type).c_str(), iter->name.utf8().get_data()).c_str();}content += ")";cofs << content;}delete p_list;cofs << GetObjectHint(destObject);
}
if (SameText(drGet.propertyName, "childNames", DRGRAPH_FLAG_CASESENSITIVE)) {if (Node *node = dynamic_cast<Node *>(destObject)) {int count = node->get_child_count();for (int i = 0; i < count; ++i) {Node *subNode = node->get_child(i);cofs << str_format(U"%s[%s]", subNode->get_name().operator String().utf8().get_data(),subNode->get_class_name().operator String().utf8().get_data());}cofs << GetObjectHint(destObject);}
}
其中,获取对象信息(GetObjectHint)是期望能显示对象的一些相应信息
#define CAST(T, ptr) dynamic_cast<T>(static_cast<T>(ptr))
std::string GetObjectHint(void* ptr) {String result = U"未处理对象";if (Object *object = CAST(Object *, ptr)) {result = str_format(U" ---==== [%s]类型对象 0X%08x ====---", object->get_class_name().operator String().utf8().get_data(), int(ptr));if (Node *node = CAST(Node *, ptr)) {String path = node->get_name();Node *parent = node->get_parent();while (parent) {path = parent->get_name().operator String() + U"." + path;parent = parent->get_parent();}result += U":\n\t\t\t\t\t\t路径信息:";result += path + U"\n\t\t\t\t\t\t子对象信息:";int count = node->get_child_count();for (int i = 0; i < count; ++i) {Node *subNode = node->get_child(i);result += str_format(U" %s[%s]", String2std(subNode->get_name().operator String()).c_str(),String2std(subNode->get_class_name().operator String()).c_str());}}} else if (Engine *engine = CAST(Engine *, ptr)) {result = str_format(U"[Engine]类型对象 0X%08x", int(ptr));}return String2std(result);
}
测试一下,取得根节点(Book)的所有属性名: Book.propertyNames
261. 15:58:53:368 > 【主线程】 > [Pipe.发送] > 发送数据中内容[DrGraph.78: Request - wait 1000 ms]: [int]类型 > 值 = 2[UnicodeString]类型 > 值 = Book[UnicodeString]类型 > 值 = propertyNames
262. 15:58:53:614 > 【主线程】 > [Pipe.Read] > 发送数据[DrGraph.78: Request - wait 1000 ms]成功返回 2396 字节... > PIPE响应中内容[godot -> DrGraph.78: Response - no return]: [int]类型 > 值 = 3[UnicodeString]类型 > 值 = OK[UnicodeString]类型 > 值 = book.gd[NIL] = <null>[UnicodeString]类型 > 值 = singlePage[BOOL] = false[UnicodeString]类型 > 值 = middleBarWidth[INT] = 0[UnicodeString]类型 > 值 = shader_rect[OBJECT] = ShaderRect:<ColorRect#26944209309>[UnicodeString]类型 > 值 = currentPageMode[BOOL] = false[UnicodeString]类型 > 值 = currentAreaType[INT] = 5[UnicodeString]类型 > 值 = triggleAreaMoment[INT] = 745493[UnicodeString]类型 > 值 = currentPageIndex[INT] = 30[UnicodeString]类型 > 值 = pageCount[INT] = 100[UnicodeString]类型 > 值 = pageImgPath[STRING] = res://Pages/[UnicodeString]类型 > 值 = leftMouseDownMoment[INT] = 0[UnicodeString]类型 > 值 = underAutoTurnPage[BOOL] = false[UnicodeString]类型 > 值 = leftMouseDownPos[VECTOR2] = (0, 0)[UnicodeString]类型 > 值 = dllStream[OBJECT] = <DllStream#67024979098>[UnicodeString]类型 > 值 = AutoTurnObject[OBJECT] = <RefCounted#-9223372009692462686>[UnicodeString]类型 > 值 = Node2D[NIL] = <null>[UnicodeString]类型 > 值 = Transform[NIL] = <null>[UnicodeString]类型 > 值 = position[VECTOR2] = (0, 0)[UnicodeString]类型 > 值 = rotation[FLOAT] = 0[UnicodeString]类型 > 值 = rotation_degrees[FLOAT] = 0[UnicodeString]类型 > 值 = scale[VECTOR2] = (1, 1)[UnicodeString]类型 > 值 = skew[FLOAT] = 0[UnicodeString]类型 > 值 = transform[TRANSFORM2D] = [X: (1, 0), Y: (0, 1), O: (0, 0)][UnicodeString]类型 > 值 = global_position[VECTOR2] = (0, 0)[UnicodeString]类型 > 值 = global_rotation[FLOAT] = 0[UnicodeString]类型 > 值 = global_rotation_degrees[FLOAT] = 0[UnicodeString]类型 > 值 = global_scale[VECTOR2] = (1, 1)[UnicodeString]类型 > 值 = global_skew[FLOAT] = 0[UnicodeString]类型 > 值 = global_transform[TRANSFORM2D] = [X: (1, 0), Y: (0, 1), O: (0, 0)][UnicodeString]类型 > 值 = CanvasItem[NIL] = <null>[UnicodeString]类型 > 值 = Visibility[NIL] = <null>[UnicodeString]类型 > 值 = visible[BOOL] = true[UnicodeString]类型 > 值 = modulate[COLOR] = (1, 1, 1, 1)[UnicodeString]类型 > 值 = self_modulate[COLOR] = (1, 1, 1, 1)[UnicodeString]类型 > 值 = show_behind_parent[BOOL] = false[UnicodeString]类型 > 值 = top_level[BOOL] = false[UnicodeString]类型 > 值 = clip_children[INT] = 0[UnicodeString]类型 > 值 = light_mask[INT] = 1[UnicodeString]类型 > 值 = visibility_layer[INT] = 1[UnicodeString]类型 > 值 = Ordering[NIL] = <null>[UnicodeString]类型 > 值 = z_index[INT] = 0[UnicodeString]类型 > 值 = z_as_relative[BOOL] = true[UnicodeString]类型 > 值 = y_sort_enabled[BOOL] = false[UnicodeString]类型 > 值 = Texture[NIL] = <null>[UnicodeString]类型 > 值 = texture_filter[INT] = 0[UnicodeString]类型 > 值 = texture_repeat[INT] = 0[UnicodeString]类型 > 值 = Material[NIL] = <null>[UnicodeString]类型 > 值 = material[OBJECT] = <Object#null>[UnicodeString]类型 > 值 = use_parent_material[BOOL] = false[UnicodeString]类型 > 值 = Node[NIL] = <null>[UnicodeString]类型 > 值 = _import_path[NODE_PATH] = [UnicodeString]类型 > 值 = name[STRING_NAME] = Book[UnicodeString]类型 > 值 = unique_name_in_owner[BOOL] = false[UnicodeString]类型 > 值 = scene_file_path[STRING] = res://book.tscn[UnicodeString]类型 > 值 = owner[OBJECT] = <Object#null>[UnicodeString]类型 > 值 = multiplayer[OBJECT] = <SceneMultiplayer#-9223372011168857674>[UnicodeString]类型 > 值 = Process[NIL] = <null>[UnicodeString]类型 > 值 = process_mode[INT] = 0[UnicodeString]类型 > 值 = process_priority[INT] = 0[UnicodeString]类型 > 值 = Editor Description[NIL] = <null>[UnicodeString]类型 > 值 = editor_description[STRING] = [UnicodeString]类型 > 值 = script[OBJECT] = <GDScript#-9223372010984308353>[UnicodeString]类型 > 值 = ---==== [Node2D]类型对象 0X4d7c5600 ====---:路径信息:root.Book子对象信息: LeftPage[Sprite2D] RightPage[Sprite2D] ShaderRect[ColorRect] LeftButton[Button] RightButton[Button] AutoTurnTimer[Timer] DrGraph[Node]
看到script属性:[UnicodeString]类型 > 值 = script[OBJECT] = <GDScript#-9223372010984308353>
那就再取得Book.script.propertyNames来看下,结果发现返回了脚本内容
仔细一看,是属性 script/source 的值。那就单独看一下该属性: Book.script.script/source,果然得到相应脚本内容
倒是有点意思,属性名称为 script/source
源码分析
在源码中查找 script/source,在gdscript.cpp中有两处,应该是这个
void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const {p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
}
原来GDScript对象返回属性名称列表时,就添加了这么一个玩意
这样取属性名称列表时,就有一个名为 script/source 的属性
下来看看get该属性时具体有哪些动作,调试跟进
Variant Object::get(const StringName &p_name, bool *r_valid) const {Variant ret;if (script_instance) {if (script_instance->get(p_name, ret)) {if (r_valid) {*r_valid = true;}return ret;}}if (_extension && _extension->get) {
// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
#endifif (_extension->get(_extension_instance, (const GDExtensionStringNamePtr)&p_name, (GDExtensionVariantPtr)&ret)) {if (r_valid) {*r_valid = true;}return ret;}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif}// Try built-in getter.{if (ClassDB::get_property(const_cast<Object *>(this), p_name, ret)) {if (r_valid) {*r_valid = true;}return ret;}}if (p_name == CoreStringNames::get_singleton()->_script) {ret = get_script();if (r_valid) {*r_valid = true;}return ret;}const Variant *const *V = metadata_properties.getptr(p_name);if (V) {ret = **V;if (r_valid) {*r_valid = true;}return ret;} else {
#ifdef TOOLS_ENABLEDif (script_instance) {bool valid;ret = script_instance->property_get_fallback(p_name, &valid);if (valid) {if (r_valid) {*r_valid = true;}return ret;}}
#endif// Something inside the object... :|bool success = _getv(p_name, ret);if (success) {if (r_valid) {*r_valid = true;}return ret;}if (r_valid) {*r_valid = false;}return Variant();}
}
具体是在 bool success = _getv(p_name, ret); 中处理,直接在GDScript::_get中实质处理
bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {{const GDScript *top = this;while (top) {{HashMap<StringName, Variant>::ConstIterator E = top->constants.find(p_name);if (E) {r_ret = E->value;return true;}}{HashMap<StringName, Ref<GDScript>>::ConstIterator E = subclasses.find(p_name);if (E) {r_ret = E->value;return true;}}top = top->_base;}if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) {r_ret = get_source_code();return true;}}return false;
}
调试可知,在constants中,保存了各常量信息[key / value]
而subclasses中保存了自定义的结构(类)
最终在get_source_code函数中,直接返回source
String GDScript::get_source_code() const {return source;
}
也就是脚本文本内容。
就这。
获取脚本中变量值
从上面可看到属性获取逻辑,在script/source属性获取过程中,检查了constants和subclasses,那试试能否获取其中的变量值
发送Book.script.AREA_OUT,结果成功
自定义结构
继续测试自定义结构
发送Book.script.TAutoTurn,结果返回为对象: <GDScript#-9223372010833313372>
279. 16:18:07:517 > 【主线程】 > [Pipe.发送] > 发送数据中内容[DrGraph.87: Request - wait 1000 ms]: [int]类型 > 值 = 2[UnicodeString]类型 > 值 = Book.script[UnicodeString]类型 > 值 = TAutoTurn
280. 16:18:07:617 > 【主线程】 > [Pipe.Read] > 发送数据[DrGraph.87: Request - wait 1000 ms]成功返回 168 字节... > PIPE响应中内容[godot -> DrGraph.87: Response - no return]: [int]类型 > 值 = 3[UnicodeString]类型 > 值 = OK[UnicodeString]类型 > 值 = <GDScript#-9223372010833313372>
检查该对象属性名列表
281. 16:18:21:175 > 【主线程】 > [Pipe.发送] > 发送数据中内容[DrGraph.88: Request - wait 1000 ms]: [int]类型 > 值 = 2[UnicodeString]类型 > 值 = Book.script.TAutoTurn[UnicodeString]类型 > 值 = propertyNames
282. 16:18:21:272 > 【主线程】 > [Pipe.Read] > 发送数据[DrGraph.88: Request - wait 1000 ms]成功返回 423 字节... > PIPE响应中内容[godot -> DrGraph.88: Response - no return]: [int]类型 > 值 = 3[UnicodeString]类型 > 值 = OK[UnicodeString]类型 > 值 = GDScript[NIL] = <null>[UnicodeString]类型 > 值 = script/source[STRING] = [UnicodeString]类型 > 值 = Script[NIL] = <null>[UnicodeString]类型 > 值 = source_code[STRING] = [UnicodeString]类型 > 值 = Resource[NIL] = <null>[UnicodeString]类型 > 值 = Resource[NIL] = <null>[UnicodeString]类型 > 值 = resource_local_to_scene[BOOL] = false[UnicodeString]类型 > 值 = resource_path[STRING] = [UnicodeString]类型 > 值 = resource_name[STRING] = [UnicodeString]类型 > 值 = RefCounted[NIL] = <null>[UnicodeString]类型 > 值 = ---==== [GDScript]类型对象 0X4d771310 ====---:路径信息:子对象信息:
也有script/source、source_code属性,不过好象没内容,测试也还是真没内容返回
但能取得这些信息,感觉已经足够用的了