Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
处理兼容问题
听说你为方法添加了新参数、更改了返回类型、更改了参数的类型或默认值,而现在自动测试却在抱怨兼容性问题?
我们应该避免破坏兼容性,但如果必须破坏,也有相应的系统来处理这种情况,使过渡尽可能顺畅。
实际案例
这些修改取自拉取请求 #88047,为 AStarGrid2D 等 AStar 类添加了新的路径选项。其中包含了对 core/math/a_star_grid_2d.h 中的这些方法的修改:
Vector<Vector2> get_point_path(const Vector2i &p_from, const Vector2i &p_to);
TypedArray<Vector2i> get_id_path(const Vector2i &p_from, const Vector2i &p_to);
修改后:
Vector<Vector2> get_point_path(const Vector2i &p_from, const Vector2i &p_to, bool p_allow_partial_path = false);
TypedArray<Vector2i> get_id_path(const Vector2i &p_from, const Vector2i &p_to, bool p_allow_partial_path = false);
这段代码的作用是在文件中添加兼容方法的绑定,应该放在代码的 protected 部分,通常放在 _bind_methods() 旁边即可:
#ifndef DISABLE_DEPRECATED
TypedArray<Vector2i> _get_id_path_bind_compat_88047(const Vector2i &p_from, const Vector2i &p_to);
Vector<Vector2> _get_point_path_bind_compat_88047(const Vector2i &p_from, const Vector2i &p_to);
static void _bind_compatibility_methods();
#endif
这些方法的命名应该以 _ 开头,以表明它们是内部方法;结尾则应该是 _bind_compat_ ,后面紧跟引入该变更的 PR 编号(在这个例子里就是 88047)。这些兼容性方法需要在专门的文件中实现,比如在这个案例中,就是放在 core/math/a_star_grid_2d.compat.inc 这样的文件里:
/**************************************************************************/
/* a_star_grid_2d.compat.inc */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef DISABLE_DEPRECATED
#include "core/variant/typed_array.h"
TypedArray<Vector2i> AStarGrid2D::_get_id_path_bind_compat_88047(const Vector2i &p_from_id, const Vector2i &p_to_id) {
return get_id_path(p_from_id, p_to_id, false);
}
Vector<Vector2> AStarGrid2D::_get_point_path_bind_compat_88047(const Vector2i &p_from_id, const Vector2i &p_to_id) {
return get_point_path(p_from_id, p_to_id, false);
}
void AStarGrid2D::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStarGrid2D::_get_id_path_bind_compat_88047);
ClassDB::bind_compatibility_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStarGrid2D::_get_point_path_bind_compat_88047);
}
#endif // DISABLE_DEPRECATED
除非兼容性的变更非常复杂,否则兼容性方法应该直接调用那个被修改过的方法,而不是把那个方法的代码重新复制一遍。另外,请务必确保该方法的默认参数保持一致(在上面的例子中,默认参数应该是 false )。
该文件应当放置在原始文件旁,以 .compat.inc 结尾而不是 .cpp 和 .h。接下来,应当将该文件包含进需要添加兼容性方法的 .cpp 文件中,这样 core/math/a_star_grid_2d.cpp 就变成了这样:
#include "a_star_grid_2d.h"
#include "a_star_grid_2d.compat.inc"
#include "core/variant/typed_array.h"
最后,需要把 GDExtension API 的变更给记录下来。具体做法是:首先在主分支(master)上编译 Godot,然后运行它,并带上 --dump-extension-api 这个标志(命令行参数):
git switch master
scons
godot --dump-extension-api
这会在你当前的目录下生成一个名为 extension_api.json 的文件。接着,切换回你的功能分支(feature branch),重新编译 Godot,然后运行它。运行时需要带上 --validate-extension-api 标志,并在后面跟上你刚刚生成的那个 extension_api.json 文件的路径。
git switch my-feature-branch
scons
godot --validate-extension-api /path/to/extension_api.json
这会生成一些以 Validate extension JSON 开头的行,就像下面这样:
Validate extension JSON: Error: Field 'classes/AStar2D/methods/get_id_path/arguments': size changed value in new API, from 2 to 3.
Validate extension JSON: Error: Field 'classes/AStar2D/methods/get_point_path/arguments': size changed value in new API, from 2 to 3.
Validate extension JSON: Error: Field 'classes/AStar3D/methods/get_id_path/arguments': size changed value in new API, from 2 to 3.
Validate extension JSON: Error: Field 'classes/AStar3D/methods/get_point_path/arguments': size changed value in new API, from 2 to 3.
Validate extension JSON: Error: Field 'classes/AStarGrid2D/methods/get_id_path/arguments': size changed value in new API, from 2 to 3.
Validate extension JSON: Error: Field 'classes/AStarGrid2D/methods/get_point_path/arguments': size changed value in new API, from 2 to 3.
注意
如果你遇到了某个方法的 Hash changed (哈希值已变更)报错,这意味着对应的兼容性绑定(compatibility binding)缺失了或者不正确。这类行不应该被直接添加到验证文件中,而是应该通过正确绑定兼容性方法来解决。请务必仔细检查以下几点:
对于兼容性方法(也就是那个以 PR 编号结尾的方法),它的参数类型、参数名称以及默认值,必须与你修改之前的旧版方法保持完全一致。
在
_bind_compatibility_methods()函数中,ClassDB::bind_compatibility_method()里的D_METHOD()宏所传入的参数名称,必须与原始方法在ClassDB::bind_method()调用中使用的参数名称完全一致。
请添加这几行内容,并在后面附上一段注释,解释具体做了哪些 API 变更,以及为了防止程序崩溃(或兼容性破坏)采取了哪些措施。然后将这个验证文件以 GitHub 的 Pull Request(拉取请求)ID 来命名,并放入它原本会破坏兼容性的那个 Godot 版本对应的文件夹中。
因为这个例子是针对 PR #88047 的,所以它的文件名应该是 GH-88047.txt。又因为这是在 4.3 版本开发期间完成的(也就是相对于 4.2 版本有了变动),所以这个文件应该放在 misc/extension_api_validation/4.2-stable/ 文件夹中。
下面是对于 PR #88047的文档的完整示例:
GH-88047
--------
Validate extension JSON: Error: Field 'classes/AStar2D/methods/get_id_path/arguments': size changed value in new API, from 2 to 3.
Validate extension JSON: Error: Field 'classes/AStar2D/methods/get_point_path/arguments': size changed value in new API, from 2 to 3.
Validate extension JSON: Error: Field 'classes/AStar3D/methods/get_id_path/arguments': size changed value in new API, from 2 to 3.
Validate extension JSON: Error: Field 'classes/AStar3D/methods/get_point_path/arguments': size changed value in new API, from 2 to 3.
Validate extension JSON: Error: Field 'classes/AStarGrid2D/methods/get_id_path/arguments': size changed value in new API, from 2 to 3.
Validate extension JSON: Error: Field 'classes/AStarGrid2D/methods/get_point_path/arguments': size changed value in new API, from 2 to 3.
Added optional "allow_partial_path" argument to get_id_path and get_point_path methods in AStar classes.
Compatibility methods registered.
好啦,就是这样!在实际操作中,你可能会遇到一些更复杂的情况,比如需要重新排列参数、修改返回类型等等,但上面这些已经涵盖了使用这套系统的基础核心了。
详情见拉取请求 #76446。