Up to date

This page is up to date for Godot 4.3. If you still find outdated information, please open an issue.

处理兼容问题

听说你为方法添加了新参数、更改了返回类型、更改了参数的类型或默认值,而现在自动测试却在抱怨兼容性问题?

我们应该避免破坏兼容性,但如果必须破坏,也有相应的系统来处理这种情况,使过渡尽可能顺畅。

实际案例

这些修改取自拉取请求 #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_compt_ 加上引入该修改的 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"

最后,应当将 API 验证环节中汇报的改动加入到相关的验证文件中。因为这个 PR 是在 4.3 开发过程中完成的,所以就应该是 misc/extension_api_validation/4.2-stable.expected(包含例子中未展示的改动):

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.

如何往该文件中添加内容的说明见该文件的开头。

如果出现某个方法“Hash changed”报错,就说明兼容性绑定缺失或不正确。这样的报错不应当加入到 .expected 文件中,应当通过正确绑定兼容性方法来修复。

这样就大功告成了!你可能还会遇到更加复杂的情况,比如重新排列参数、修改返回类型等,但这个系统的基本用法就是这样的。

详情见拉取请求 #76446