Godot 4 source code analysis - get the script

Get property list

Raised grass and beat rabbits today, and got the script content

Since the attribute value can already be obtained, then go one step further and obtain the list of attribute names

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);	
}

Correspondingly, a list of function names and a list of subobjects can be obtained

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);
	}
}

Among them, obtaining object information (GetObjectHint) is expected to display some corresponding information of the object

#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);
}

Test it and get all the property names of the root node (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]

See script property: [UnicodeString] type > value = script[OBJECT] = <GDScript#-9223372010984308353>

Then take a look at Book.script.propertyNames and find that the script content is returned

Take a closer look, it is the value of the attribute script/source. Then take a look at this attribute alone: ​​Book.script.script/source, and you will get the corresponding script content

It's interesting, the attribute name is script/source

Source code analysis

Find script/source in the source code, there are two places in gdscript.cpp, it should be this

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));
}

It turns out that when the GDScript object returns a list of attribute names, such a thing is added

In this way, when taking the list of attribute names, there is an attribute named script/source

Come down to see what actions are taken when getting this attribute, and debug and follow up

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();
	}
}

Specifically, it is processed in  bool success = _getv(p_name, ret);  and directly processed in 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;
}

Debugging shows that in constants, each constant information [key / value] is saved

 The custom structure (class) is saved in subclasses

 Finally, in the get_source_code function, directly return the source

String GDScript::get_source_code() const {
	return source;
}

That is, the script text content.

That's it.

Get the value of the variable in the script

From the above, you can see the attribute acquisition logic. In the process of script/source attribute acquisition, constants and subclasses are checked, so try to get the variable value in it

Send Book.script.AREA_OUT, the result is successful

custom structure

Continue to test custom structures

Send Book.script.TAutoTurn, the result is returned as object: <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>

Check the list of object property names

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 ====---:
						路径信息:
						子对象信息:

There are also script/source and source_code attributes, but it seems that there is no content, and the test still has no content to return

 But it is enough to get this information

Guess you like

Origin blog.csdn.net/drgraph/article/details/131919983