Godot 4 源码分析 - 获取脚本

获取属性列表

今天搂草打兔,取得了脚本内容

因为已能取得属性值,那就再进一步,取得属性名列表

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属性,不过好象没内容,测试也还是真没内容返回

 但能取得这些信息,感觉已经足够用的了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/8900.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工信部、国家标准委联合印发《国家车联网产业指南(2023 版)》

国家工信部和标委发布了最新的《国家车联网产业标准体系建设指南&#xff08;智能网联汽车&#xff09;&#xff08;2023 版&#xff09;》&#xff0c;了解这篇文章&#xff0c;不论您是智能网联汽车的追随者&#xff0c;还是对智能网联汽车产业前景感兴趣的人&#xff0c;都非…

性能测试请求重试实现思路

文章目录 一、背景二、尝试的解决方案三、解决方案1&#xff1a;jmeter retrier插件&#xff01;有点用但是不是特别有用-_-||四&#xff0c;最终解决方案&#xff1a;lucust! 一、背景 最近系统需要压测一些活动&#xff0c;场景是新建抽奖活动之后&#xff0c;每隔2s查询1次…

Spring6——入门

文章目录 入门环境要求构建模块程序开发引入依赖创建java类创建配置文件创建测试类运行测试程序 程序分析启用Log4j2日志框架Log4j2日志概述引入Log4j2依赖加入日志配置文件测试使用日志 入门 环境要求 JDK&#xff1a;Java17&#xff08;Spring6要求JDK最低版本是Java17&…

1-Linux的目录结构

Linux的目录结构是规定好的&#xff0c;不可以随意进行更改&#xff01; Linux的文件系统是采用级层式的树状目录结构&#xff0c;最上层是根目录–/&#xff0c;然后再在根目录下创建其它的目录。 各个目录中主要负责的功能和作用如下&#xff1a;&#xff08;主体的结构一定…

引入第三方字体库 第三方字体库Google Fonts

googlefonts官方网站 googlefonts中国网站 本人是在微信小程序中引入 在static中建一个文件夹font-family 例如字体链接&#xff1a;https://fonts.font.im/css?familyKirangHaerang 将该链接的返回的资源的复制到css文件中 font-family.css /* [0] */ font-face {font-fam…

使用JMeter进行接口测试教程

安装 使用JMeter的前提需要安装JDK&#xff0c;需要JDK1.7以上版本目前在用的是JMeter5.2版本&#xff0c;大家可自行下载解压使用 运行 进入解压路径如E: \apache-jmeter-5.2\bin&#xff0c;双击jmeter.bat启动运行 启动后默认为英文版本&#xff0c;可通过Options – Ch…

使用node内置test runner,和 Jest say 拜拜

参考 https://nodejs.org/dist/latest-v20.x/docs/api/test.html#test-runner 在之前&#xff0c;我们写单元测试&#xff0c;必须安装第三方依赖包&#xff0c;而从node 20.0.0 版本之后&#xff0c;可以告别繁琐的第三方依赖包啦&#xff0c;可直接使用node的内置test runner…

centos中修改防火墙端口开放配置

1、直接进入文件修改 vim /etc/sysconfig/iptables 2、添加需要开放的端口 &#xff08;1&#xff09;添加需要开放的单个端口 4001 -A INPUT -m state --state NEW -m tcp -p tcp --dport 4001 -j ACCEPT &#xff08;2&#xff09;添加需要开放的某个网段端口 4001:4020 …

需求管理中最易忽视的6大重点

需求管理是产品经理的重点工作&#xff0c;如果无法有效进行需求管理&#xff0c;往往会引起需求变更、项目延期以及成本增加等问题。那么如何对需求进行高效管理&#xff0c;我们在需求管理中&#xff0c;往往最容易忽视的重点都有哪些&#xff1f; 1、重视项目整体管理计划 首…

VMWare虚拟机常用操作命令

今日一语&#xff1a;做到所有的细节都不放过&#xff0c;则可以避免99%已知的风险&#xff0c;但大多数都因懒惰而甘愿承受风险&#xff0c;至此悔不当初 查看虚拟机在本机网络的IP ip addr 本地向虚拟机传送文件 scp 文件 rootpath 虚拟机路径 enter后输入密码即可传输&am…

账号列表的删除编辑提交

<template><div><plan title"账号列表"><!-- selection-change"handleSelectionChange"添加这个属性就是点击可以得到你想要的value值 --><el-tablestyle"width: 100%":data"list"selection-change"h…

视频基础知识

1.视频比特率 视频的比特率是指传输过程中单位时间传输的数据量。可以理解为视频的编码采样率。单位是kbps&#xff0c;即每秒千比特。视频比特率是决定视频清晰度的一个重要指标。比特率越高&#xff0c;视频越清晰&#xff0c;但数据量也会越大。比如一部100分钟的电影&#…

K8S初级入门系列之五-Pod的高级特性

一、前言 前一篇我们了解了Pod的基本概念和操作&#xff0c;本篇我们继续研究Pod的一些高级特性&#xff0c;包括Pod的生命周期&#xff0c;pod探针&#xff0c;pod的调度等。 二、生命周期 1、Pod的生命周期 Pod的生命周期示意图如下&#xff1a; 挂起(Pending)&#xff0c…

【C进阶】指针进阶(1)_二次复习版

目录 1. 字符指针 1.1常量字符串的修改 加上const解决问题 打印常量字符串 1.2数组存放的字符串 1.3例题:数组创建与常量池的区别 2. 指针数组 2.1字符指针数组 2.2整型指针数组 2.3使用3个一维数组,模拟实现一个二维数组 2.4例题: 3.数组指针 3.1 数组指针的定义…

老年公寓人员定位管理系统:提升安全与关怀的智能解决方案

老年公寓作为提供安全居住环境和关怀服务的重要场所&#xff0c;面临着人员管理和安全控制的挑战。为了解决这些问题&#xff0c;老年公寓人员定位管理系统应运而生。基于为提供全面的安全管理和个性化关怀服务&#xff0c;华安联大便通过老年公寓人员定位管理系统的技术原理、…

数字孪生和 GIS 系统融合将为水利领域带来哪些变化?

随着科技的不断进步&#xff0c;数字孪生和 GIS 系统的融合应用逐渐成为了水利领域的新趋势。数字孪生是指通过数字化技术模拟物理实体和过程&#xff0c;将现实世界与虚拟世界相结合的技术&#xff0c;而 GIS 系统则是地理信息系统&#xff0c;用于收集、存储、管理和分析地理…

网工内推 | 售前、售后工程师,IE认证优先

01 广州佳杰科技有限公司 招聘岗位&#xff1a;IT售前工程师 职责描述&#xff1a; 1、负责所在区域 IT 产品的售前技术支持工作,包括客户交流、方案编写、配置报价、投标应标、测试、赋能等; 2、与厂商相关人员建立和保持良好的关系,相互配合,提高项目成功率和厂商满意度; 3、…

Python:使用openpyxl读取Excel文件转为json数据

文档 https://openpyxl.readthedocs.io/en/stable/https://pypi.org/project/openpyxl/ 安装 pip install openpyxl环境 $ python --version Python 3.7.0读取文件示例&#xff1a;将Excel文件读取为json数据 有如下一个文件 data.xlsx 实现代码 # -*- coding: utf-8 -…

如何恢复损坏/删除的 Word 文件

有关如何修复不可读的 Microsoft Word 文件或 Rich Text 文件中的文本的分步说明。这些说明有助于从损坏的*.doc、*.docx、*.dot、*.dotx、*.rtf文件&#xff08;任何版本和大小&#xff09;中提取文本&#xff0c;只需单击几下&#xff1a; 从此处下载奇客数据恢复 &#xff…

如何在Linux系统中安装ActiveMQ

1、环境 ActiveMQ是一个纯Java程序&#xff0c;这里安装5.18.2版ActiveMQ&#xff0c;该版MQ运行在JDK 11环境内&#xff0c;为此需要先搭建JDK 11环境&#xff0c;这里安装JDK 15。 1.1、卸载 卸载开源JDK软件包&#xff0c;如下所示&#xff1a; [rootlocalhost ~]# rpm -…