Godot 4 源码分析 - 获取脚本

news2025/1/11 0:21:14

获取属性列表

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

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

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"
#endif

		if (_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_ENABLED
		if (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.coloradmin.cn/o/787350.html

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

相关文章

8年测试整理,自动化测试框架从0到1实施,一篇打通自动化...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 框架本身一般不完…

【LeetCode】62.不同路径

题目 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&#xff1f; …

信息的表示与处理 (深入理解计算机系统第二章)

刚学习这本书没多久&#xff0c;感觉里面讲的东西挺多的&#xff0c;前后的关联性比较强。学着后面的还需要看看前的才可以更好的理解。 2.1信息存储 无符号(unsigned) 编码是基于传统的二进制表示法的&#xff0c;表示大于或者等于零的数字。 二进制补码(twos-complement)编…

7.string字符串的加法

字符串的加法其实是一个拼接生成新的一个字符串&#xff0c; #include <iostream> #include <Windows.h> #include <string> using namespace std; int main(void) { string s1 "武当派"; string s2 "张三丰"; string s3 "太极…

[Ubuntu 22.04] containerd配置HTTP方式拉取私仓Harbor

文章目录 1. 基础环境配置2. Docker安装3. 部署Harbor&#xff0c;HTTP访问4. 部署ContainerD5. 修改docker配置文件&#xff0c;向harbor中推入镜像6. 配置containerd6.1. 拉取镜像验证6.2. 推送镜像验证 1. 基础环境配置 [Ubuntu 22.04] 安装K8S基础环境准备脚本 2. Docker安…

防静电实时监控系统可以实现的功能

防静电实时监控系统是一种用于监测和识别静电相关问题的技术系统。静电是指由于电荷分布不均匀而引起的电势差&#xff0c;这可能导致电击、电磁干扰和设备故障等问题。 防静电实时监控系统可以通过以下方式实现&#xff1a; 感应传感器&#xff1a;该系统通常使用静电传感器…

flutter开发实战-自定义相机camera功能

flutter开发实战-自定义相机camera功能。 Flutter 本质上只是一个 UI 框架&#xff0c;运行在宿主平台之上&#xff0c;Flutter 本身是无法提供一些系统能力&#xff0c;比如使用蓝牙、相机、GPS等&#xff0c;因此要在 Flutter 中调用这些能力就必须和原生平台进行通信。 实现…

软件测试经典面试题——如何测试一支签字笔(尽量全面)

前几天过了两个电话面试&#xff0c;其中有一个问题&#xff1a;给你一支签字笔&#xff0c;你要如何测试它。 大白如我&#xff0c;后来才知道&#xff0c;这是一个软测的面试老题目了&#xff0c;当时稀里糊涂答了一通&#xff0c;后来才回味过来&#xff0c;其实HR是想看我的…

ROS2自定义消息并在同一功能包与其他功能包中使用

1创建自定义消息 1.1. 创建工作空间 mkdir -p ros2_ws/src1.2.创建功能包 cd ros2_ws/src ros2 pkg create msg_pkg --build-type ament_cmake --dependencies rclcpp std_msgs1.3.创建消息 在功能包msg_pkg中创建msg文件夹,并在msg目录中创建消息文件.类型.msg. 如Student…

【C++】从0到1讲继承|复杂的菱形继承

个人主页&#xff1a;&#x1f35d;在肯德基吃麻辣烫 我的gitee&#xff1a;gitee仓库 分享一句喜欢的话&#xff1a;热烈的火焰&#xff0c;冰封在最沉默的火山深处。 前言 本文主要讲述的是继承的概念&#xff0c;以及基类和派生类和衍生出的各种东西&#xff0c;还有多继承…

js实现css样式变换的实训

js实现css样式变换的实训 一、需求二、效果展示1.效果展示 三、实现四、其他1.其它系统 一、需求 完成以下功能&#xff1a; 1.掌控板三颗RGB灯初始所有RGB灯为红色 2.当掌控板P被触摸时&#xff0c;第一颗灯为白色&#xff0c;其他为红色&#xff1b;当掌控板Y被触摸时&…

C# GDI+编程之Graphics类

最近需要使用到C#DrawLine绘制直线这个功能&#xff0c;对这个了解的不多&#xff0c;记录一下使用的时候遇到的问题。 绘制线的基础部分&#xff0c;这个之前在《C#自学笔记&#xff08;四十&#xff09;之Windows绘图》就写过&#xff0c;有兴趣的可以看下 我这里主要说下Gra…

选择最佳安全文件传输方法的重要性

在数字化时代&#xff0c;文件的传输是商务、教育、科研、医学等领域不可或缺的工作流程。为了保障数据安全&#xff0c;选择最佳安全文件传输方法非常关键。在本文中&#xff0c;我们将探讨选择最佳安全文件传输方法的重要性。 第一、最佳安全文件传输方法可以保证文件内容不被…

【C++进阶】可变模版参数

一、前言 我们在之前Linux的学习中了解过命令行参数&#xff0c;可以让我们在命令行中传入多个参数&#xff0c;并且之前在学习printf&#xff0c;scanf等接口时&#xff0c;接触过可变模版参数&#xff1a; 而今天学习的可变参数模板和普通模板的语义是一样的&#xff0c;只…

Mac 系统钥匙串证书不受信任

Mac 系统钥匙串证书不受信任 解决办法 通过尝试安装 Apple PKI 的 Worldwide Developer Relations - G4 (Expiring 12/10/2030 00:00:00 UTC) 解决该异常问题 以上便是此次分享的全部内容&#xff0c;希望能对大家有所帮助!

[USACO14OPEN] Odometer S

洛谷[USACO14OPEN] Odometer S 题目大意 当一个数的每一位中有至少一半的数字相同&#xff0c;那么这个数就是一个有趣的数。求区间 [ L , R ] [L,R] [L,R]中有多少个有趣的数。 100 ≤ L ≤ R ≤ 1 0 18 100\leq L\leq R\leq 10^{18} 100≤L≤R≤1018 题解 这道题很容易能想…

AcWing242. 一个简单的整数问题

输入样例&#xff1a; 10 5 1 2 3 4 5 6 7 8 9 10 Q 4 Q 1 Q 2 C 1 6 3 Q 2输出样例&#xff1a; 4 1 2 5 #include<bits/stdc.h> using namespace std; const int N1e55; int n,m,a[N],c[N],x,y,d; char ch; int lowbit(int x){return x&-x; } void add(int x,int…

pytest--allure报告中添加用例详情

前言 前面介绍了如何生成allure的报告&#xff0c;看着allure的页面非常好看&#xff0c;但是感觉少了一些内容&#xff0c;allure还可以增加一些用例详情内容&#xff0c;这样让我们的报告看着更加绚丽。 allure增加用例详情 我们可以在报告测试套件中增加用例详情内容。 …

Spring初识(四)

文章目录 前言一.Bean的作用域1.1 作用域例子1.2 Bean的作用域类型 二.Bean的生命周期 前言 在前面我们学习了spring简单的读取和存储对象之后,Spring 中 Bean 是最核心的操作资源&#xff0c;我们接下来会介绍Bean对象. 一.Bean的作用域 什么是Bean作用域呢? 限定程序中变…

[DDPM] Denoising Diffusion Probabilistic Models

直接看paper云里雾里&#xff0c;一些推荐的讲解&#xff1a; The Annotated Diffusion Model 生成扩散模型漫谈&#xff08;一&#xff09;&#xff1a;DDPM 拆楼 建楼 生成扩散模型漫谈&#xff08;二&#xff09;&#xff1a;DDPM 自回归式VAE 生成扩散模型漫谈&#xff…