summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md19
-rw-r--r--core/variant/variant_call.cpp1
-rw-r--r--doc/classes/EditorResourcePicker.xml3
-rw-r--r--doc/classes/String.xml14
-rw-r--r--editor/editor_properties.cpp4
-rw-r--r--editor/editor_properties.h2
-rw-r--r--editor/editor_resource_picker.cpp6
-rw-r--r--editor/import/resource_importer_texture.cpp3
-rw-r--r--editor/plugins/theme_editor_plugin.cpp2
-rw-r--r--editor/plugins/theme_editor_plugin.h2
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp9
-rw-r--r--modules/gdscript/gdscript_tokenizer.h1
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out2
-rw-r--r--modules/gltf/doc_classes/GLTFMesh.xml2
-rw-r--r--modules/gltf/gltf_document.cpp37
-rw-r--r--modules/gltf/gltf_mesh.cpp11
-rw-r--r--modules/gltf/gltf_mesh.h3
-rw-r--r--scene/3d/fog_volume.cpp1
-rw-r--r--scene/resources/mesh_data_tool.cpp2
19 files changed, 102 insertions, 22 deletions
diff --git a/README.md b/README.md
index 8ddddf0e63..a7e67f8946 100644
--- a/README.md
+++ b/README.md
@@ -10,8 +10,8 @@
**[Godot Engine](https://godotengine.org) is a feature-packed, cross-platform
game engine to create 2D and 3D games from a unified interface.** It provides a
-comprehensive set of common tools, so that users can focus on making games
-without having to reinvent the wheel. Games can be exported in one click to a
+comprehensive set of [common tools](https://godotengine.org/features), so that users can focus on making games
+without having to reinvent the wheel. Games can be exported with one click to a
number of platforms, including the major desktop platforms (Linux, macOS,
Windows), mobile platforms (Android, iOS), as well as Web-based platforms
(HTML5) and
@@ -19,18 +19,19 @@ Windows), mobile platforms (Android, iOS), as well as Web-based platforms
## Free, open source and community-driven
-Godot is completely free and open source under the very permissive MIT license.
+Godot is completely free and open source under the very permissive [MIT license](https://godotengine.org/license).
No strings attached, no royalties, nothing. The users' games are theirs, down
to the last line of engine code. Godot's development is fully independent and
community-driven, empowering users to help shape their engine to match their
expectations. It is supported by the [Software Freedom Conservancy](https://sfconservancy.org/)
not-for-profit.
-Before being open sourced in February 2014, Godot had been developed by Juan
-Linietsky and Ariel Manzur (both still maintaining the project) for several
+Before being open sourced in [February 2014](https://github.com/godotengine/godot/commit/0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac),
+Godot had been developed by [Juan Linietsky](https://github.com/reduz) and
+[Ariel Manzur](https://github.com/punto-) (both still maintaining the project) for several
years as an in-house engine, used to publish several work-for-hire titles.
-![Screenshot of a 3D scene in Godot Engine](https://raw.githubusercontent.com/godotengine/godot-design/master/screenshots/editor_tps_demo_1920x1080.jpg)
+![Screenshot of a 3D scene in the Godot Engine editor](https://raw.githubusercontent.com/godotengine/godot-design/master/screenshots/editor_tps_demo_1920x1080.jpg)
## Getting the engine
@@ -49,7 +50,7 @@ for compilation instructions for every supported platform.
Godot is not only an engine but an ever-growing community of users and engine
developers. The main community channels are listed [on the homepage](https://godotengine.org/community).
-To get in touch with the engine developers, the best way is to join the
+The best way to get in touch with the core engine developers is to join the
[Godot Contributors Chat](https://chat.godotengine.org).
To get started contributing to the project, see the [contributing guide](CONTRIBUTING.md).
@@ -62,8 +63,8 @@ It is maintained by the Godot community in its own [GitHub repository](https://g
The [class reference](https://docs.godotengine.org/en/latest/classes/)
is also accessible from the Godot editor.
-The official demos are maintained in their own [GitHub repository](https://github.com/godotengine/godot-demo-projects)
-as well.
+We also maintain official demos in their own [GitHub repository](https://github.com/godotengine/godot-demo-projects)
+as well as a list of [awesome Godot community resources](https://github.com/godotengine/awesome-godot).
There are also a number of other
[learning resources](https://docs.godotengine.org/en/latest/community/tutorials.html)
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index ec3a6a5ca8..2b1d330942 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1366,6 +1366,7 @@ static void _register_variant_builtin_methods() {
bind_method(String, naturalnocasecmp_to, sarray("to"), varray());
bind_method(String, length, sarray(), varray());
bind_method(String, substr, sarray("from", "len"), varray(-1));
+ bind_method(String, get_slice, sarray("delimiter", "slice"), varray());
bind_methodv(String, find, static_cast<int (String::*)(const String &, int) const>(&String::find), sarray("what", "from"), varray(0));
bind_method(String, count, sarray("what", "from", "to"), varray(0, 0));
bind_method(String, countn, sarray("what", "from", "to"), varray(0, 0));
diff --git a/doc/classes/EditorResourcePicker.xml b/doc/classes/EditorResourcePicker.xml
index 9c490cbb3e..b26b6f9527 100644
--- a/doc/classes/EditorResourcePicker.xml
+++ b/doc/classes/EditorResourcePicker.xml
@@ -62,8 +62,9 @@
</signal>
<signal name="resource_selected">
<argument index="0" name="resource" type="Resource" />
+ <argument index="1" name="edit" type="bool" />
<description>
- Emitted when the resource value was set and user clicked to edit it.
+ Emitted when the resource value was set and user clicked to edit it. When [code]edit[/code] is [code]true[/code], the signal was caused by the context menu "Edit" option.
</description>
</signal>
</signals>
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 1190d90190..a58bfd5c15 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -202,6 +202,19 @@
If the string is a valid file path, returns the filename.
</description>
</method>
+ <method name="get_slice" qualifiers="const">
+ <return type="String" />
+ <argument index="0" name="delimiter" type="String" />
+ <argument index="1" name="slice" type="int" />
+ <description>
+ Splits a string using a [code]delimiter[/code] and returns a substring at index [code]slice[/code]. Returns an empty string if the index doesn't exist.
+ This is a more performant alternative to [method split] for cases when you need only one element from the array at a fixed index.
+ Example:
+ [codeblock]
+ print("i/am/example/string".get_slice("/", 2)) # Prints 'example'.
+ [/codeblock]
+ </description>
+ </method>
<method name="hash" qualifiers="const">
<return type="int" />
<description>
@@ -602,6 +615,7 @@
<description>
Splits the string by a [code]delimiter[/code] string and returns an array of the substrings. The [code]delimiter[/code] can be of any length.
If [code]maxsplit[/code] is specified, it defines the number of splits to do from the left up to [code]maxsplit[/code]. The default value of [code]0[/code] means that all items are split.
+ If you need only one element from the array at a specific index, [method get_slice] is a more performant option.
Example:
[codeblocks]
[gdscript]
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index e679222567..fbf80fef2e 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -2821,8 +2821,8 @@ void EditorPropertyResource::_set_read_only(bool p_read_only) {
resource_picker->set_editable(!p_read_only);
};
-void EditorPropertyResource::_resource_selected(const RES &p_resource) {
- if (use_sub_inspector) {
+void EditorPropertyResource::_resource_selected(const RES &p_resource, bool p_edit) {
+ if (!p_edit && use_sub_inspector) {
bool unfold = !get_edited_object()->editor_is_section_unfolded(get_edited_property());
get_edited_object()->editor_set_section_unfold(get_edited_property(), unfold);
update_property();
diff --git a/editor/editor_properties.h b/editor/editor_properties.h
index 9a687f1a72..6b07efb068 100644
--- a/editor/editor_properties.h
+++ b/editor/editor_properties.h
@@ -657,7 +657,7 @@ class EditorPropertyResource : public EditorProperty {
bool updating_theme = false;
bool opened_editor = false;
- void _resource_selected(const RES &p_resource);
+ void _resource_selected(const RES &p_resource, bool p_edit);
void _resource_changed(const RES &p_resource);
void _viewport_selected(const NodePath &p_path);
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index 9dbf69a779..a2d11c4b1f 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -106,7 +106,7 @@ void EditorResourcePicker::_resource_selected() {
return;
}
- emit_signal(SNAME("resource_selected"), edited_resource);
+ emit_signal(SNAME("resource_selected"), edited_resource, false);
}
void EditorResourcePicker::_file_selected(const String &p_path) {
@@ -266,7 +266,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
case OBJ_MENU_EDIT: {
if (edited_resource.is_valid()) {
- emit_signal(SNAME("resource_selected"), edited_resource);
+ emit_signal(SNAME("resource_selected"), edited_resource, true);
}
} break;
@@ -690,7 +690,7 @@ void EditorResourcePicker::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toggle_mode"), "set_toggle_mode", "is_toggle_mode");
- ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
+ ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::BOOL, "edit")));
ADD_SIGNAL(MethodInfo("resource_changed", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
}
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index 96a53b3257..e4553c625b 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -218,7 +218,8 @@ void ResourceImporterTexture::get_import_options(List<ImportOption> *r_options,
void ResourceImporterTexture::save_to_stex_format(FileAccess *f, const Ref<Image> &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality) {
switch (p_compress_mode) {
case COMPRESS_LOSSLESS: {
- bool lossless_force_png = ProjectSettings::get_singleton()->get("rendering/textures/lossless_compression/force_png");
+ bool lossless_force_png = ProjectSettings::get_singleton()->get("rendering/textures/lossless_compression/force_png") ||
+ !Image::_webp_mem_loader_func; // WebP module disabled.
bool use_webp = !lossless_force_png && p_image->get_width() <= 16383 && p_image->get_height() <= 16383; // WebP has a size limit
f->store_32(use_webp ? StreamTexture2D::DATA_FORMAT_WEBP : StreamTexture2D::DATA_FORMAT_PNG);
f->store_16(p_image->get_width());
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 127219546d..b1ef85b4f4 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -2848,7 +2848,7 @@ void ThemeTypeEditor::_font_size_item_changed(float p_value, String p_item_name)
edited_theme->set_font_size(p_item_name, edited_type, int(p_value));
}
-void ThemeTypeEditor::_edit_resource_item(RES p_resource) {
+void ThemeTypeEditor::_edit_resource_item(RES p_resource, bool p_edit) {
EditorNode::get_singleton()->edit_resource(p_resource);
}
diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h
index b6becbb1c7..f5ad577aff 100644
--- a/editor/plugins/theme_editor_plugin.h
+++ b/editor/plugins/theme_editor_plugin.h
@@ -362,7 +362,7 @@ class ThemeTypeEditor : public MarginContainer {
void _color_item_changed(Color p_value, String p_item_name);
void _constant_item_changed(float p_value, String p_item_name);
void _font_size_item_changed(float p_value, String p_item_name);
- void _edit_resource_item(RES p_resource);
+ void _edit_resource_item(RES p_resource, bool p_edit);
void _font_item_changed(Ref<Font> p_value, String p_item_name);
void _icon_item_changed(Ref<Texture2D> p_value, String p_item_name);
void _stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name);
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index d4a098811a..cd247d1d26 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -1064,7 +1064,8 @@ void GDScriptTokenizer::check_indent() {
// First time indenting, choose character now.
indent_char = current_indent_char;
} else if (current_indent_char != indent_char) {
- Token error = make_error(vformat("Used \"%s\" for indentation instead \"%s\" as used before in the file.", String(&current_indent_char, 1).c_escape(), String(&indent_char, 1).c_escape()));
+ Token error = make_error(vformat("Used %s character for indentation instead of %s as used before in the file.",
+ _get_indent_char_name(current_indent_char), _get_indent_char_name(indent_char)));
error.start_line = line;
error.start_column = 1;
error.leftmost_column = 1;
@@ -1114,6 +1115,12 @@ void GDScriptTokenizer::check_indent() {
}
}
+String GDScriptTokenizer::_get_indent_char_name(char32_t ch) {
+ ERR_FAIL_COND_V(ch != ' ' && ch != '\t', String(&ch, 1).c_escape());
+
+ return ch == ' ' ? "space" : "tab";
+}
+
void GDScriptTokenizer::_skip_whitespace() {
if (pending_indents != 0) {
// Still have some indent/dedent tokens to give.
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index 84b82c07f0..b4ee11fd9a 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -233,6 +233,7 @@ private:
bool has_error() const { return !error_stack.is_empty(); }
Token pop_error();
char32_t _advance();
+ String _get_indent_char_name(char32_t ch);
void _skip_whitespace();
void check_indent();
diff --git a/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out
index 6390de9788..31bed2dbc7 100644
--- a/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out
+++ b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out
@@ -1,2 +1,2 @@
GDTEST_PARSER_ERROR
-Used "\t" for indentation instead " " as used before in the file.
+Used tab character for indentation instead of space as used before in the file.
diff --git a/modules/gltf/doc_classes/GLTFMesh.xml b/modules/gltf/doc_classes/GLTFMesh.xml
index 1e7199d229..58853217e2 100644
--- a/modules/gltf/doc_classes/GLTFMesh.xml
+++ b/modules/gltf/doc_classes/GLTFMesh.xml
@@ -9,6 +9,8 @@
<members>
<member name="blend_weights" type="PackedFloat32Array" setter="set_blend_weights" getter="get_blend_weights" default="PackedFloat32Array()">
</member>
+ <member name="instance_materials" type="Array" setter="set_instance_materials" getter="get_instance_materials" default="[]">
+ </member>
<member name="mesh" type="ImporterMesh" setter="set_mesh" getter="get_mesh">
</member>
</members>
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 333fc4637d..a5e56640ed 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -795,6 +795,9 @@ Error GLTFDocument::_encode_buffer_views(Ref<GLTFState> state) {
buffers.push_back(d);
}
print_verbose("glTF: Total buffer views: " + itos(state->buffer_views.size()));
+ if (!buffers.size()) {
+ return OK;
+ }
state->json["bufferViews"] = buffers;
return OK;
}
@@ -884,6 +887,9 @@ Error GLTFDocument::_encode_accessors(Ref<GLTFState> state) {
accessors.push_back(d);
}
+ if (!accessors.size()) {
+ return OK;
+ }
state->json["accessors"] = accessors;
ERR_FAIL_COND_V(!state->json.has("accessors"), ERR_FILE_CORRUPT);
print_verbose("glTF: Total accessors: " + itos(state->accessors.size()));
@@ -2112,6 +2118,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
if (import_mesh.is_null()) {
continue;
}
+ Array instance_materials = state->meshes.write[gltf_mesh_i]->get_instance_materials();
Array primitives;
Dictionary gltf_mesh;
Array target_names;
@@ -2431,7 +2438,14 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
}
}
- Ref<BaseMaterial3D> mat = import_mesh->get_surface_material(surface_i);
+ Variant v;
+ if (surface_i < instance_materials.size()) {
+ v = instance_materials.get(surface_i);
+ }
+ Ref<BaseMaterial3D> mat = v;
+ if (!mat.is_valid()) {
+ mat = import_mesh->get_surface_material(surface_i);
+ }
if (mat.is_valid()) {
Map<Ref<BaseMaterial3D>, GLTFMaterialIndex>::Element *material_cache_i = state->material_cache.find(mat);
if (material_cache_i && material_cache_i->get() != -1) {
@@ -2475,6 +2489,9 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
meshes.push_back(gltf_mesh);
}
+ if (!meshes.size()) {
+ return OK;
+ }
state->json["meshes"] = meshes;
print_verbose("glTF: Total meshes: " + itos(meshes.size()));
@@ -3454,6 +3471,9 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
}
materials.push_back(d);
}
+ if (!materials.size()) {
+ return OK;
+ }
state->json["materials"] = materials;
print_verbose("Total materials: " + itos(state->materials.size()));
@@ -4837,6 +4857,9 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) {
}
}
+ if (!animations.size()) {
+ return OK;
+ }
state->json["animations"] = animations;
print_verbose("glTF: Total animations '" + itos(state->animations.size()) + "'.");
@@ -5057,6 +5080,18 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInst
}
Ref<GLTFMesh> gltf_mesh;
gltf_mesh.instantiate();
+ Array instance_materials;
+ for (int32_t surface_i = 0; surface_i < current_mesh->get_surface_count(); surface_i++) {
+ Ref<Material> mat = current_mesh->get_surface_material(surface_i);
+ if (p_mesh_instance->get_surface_override_material(surface_i).is_valid()) {
+ mat = p_mesh_instance->get_surface_override_material(surface_i);
+ }
+ if (p_mesh_instance->get_material_override().is_valid()) {
+ mat = p_mesh_instance->get_material_override();
+ }
+ instance_materials.append(mat);
+ }
+ gltf_mesh->set_instance_materials(instance_materials);
gltf_mesh->set_mesh(current_mesh);
gltf_mesh->set_blend_weights(blend_weights);
GLTFMeshIndex mesh_i = state->meshes.size();
diff --git a/modules/gltf/gltf_mesh.cpp b/modules/gltf/gltf_mesh.cpp
index 747820521a..7134345b30 100644
--- a/modules/gltf/gltf_mesh.cpp
+++ b/modules/gltf/gltf_mesh.cpp
@@ -36,9 +36,12 @@ void GLTFMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &GLTFMesh::set_mesh);
ClassDB::bind_method(D_METHOD("get_blend_weights"), &GLTFMesh::get_blend_weights);
ClassDB::bind_method(D_METHOD("set_blend_weights", "blend_weights"), &GLTFMesh::set_blend_weights);
+ ClassDB::bind_method(D_METHOD("get_instance_materials"), &GLTFMesh::get_instance_materials);
+ ClassDB::bind_method(D_METHOD("set_instance_materials", "instance_materials"), &GLTFMesh::set_instance_materials);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh"), "set_mesh", "get_mesh");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "blend_weights"), "set_blend_weights", "get_blend_weights"); // Vector<float>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "instance_materials"), "set_instance_materials", "get_instance_materials");
}
Ref<ImporterMesh> GLTFMesh::get_mesh() {
@@ -49,6 +52,14 @@ void GLTFMesh::set_mesh(Ref<ImporterMesh> p_mesh) {
mesh = p_mesh;
}
+Array GLTFMesh::get_instance_materials() {
+ return instance_materials;
+}
+
+void GLTFMesh::set_instance_materials(Array p_instance_materials) {
+ instance_materials = p_instance_materials;
+}
+
Vector<float> GLTFMesh::get_blend_weights() {
return blend_weights;
}
diff --git a/modules/gltf/gltf_mesh.h b/modules/gltf/gltf_mesh.h
index 3aba0ede32..cc2be93c09 100644
--- a/modules/gltf/gltf_mesh.h
+++ b/modules/gltf/gltf_mesh.h
@@ -43,6 +43,7 @@ class GLTFMesh : public Resource {
private:
Ref<ImporterMesh> mesh;
Vector<float> blend_weights;
+ Array instance_materials;
protected:
static void _bind_methods();
@@ -52,5 +53,7 @@ public:
void set_mesh(Ref<ImporterMesh> p_mesh);
Vector<float> get_blend_weights();
void set_blend_weights(Vector<float> p_blend_weights);
+ Array get_instance_materials();
+ void set_instance_materials(Array p_instance_materials);
};
#endif // GLTF_MESH_H
diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp
index cc4fbbb41b..694defd7dc 100644
--- a/scene/3d/fog_volume.cpp
+++ b/scene/3d/fog_volume.cpp
@@ -50,6 +50,7 @@ void FogVolume::_validate_property(PropertyInfo &property) const {
property.usage = PROPERTY_USAGE_NONE;
return;
}
+ VisualInstance3D::_validate_property(property);
}
void FogVolume::set_extents(const Vector3 &p_extents) {
diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp
index 04b2437ae8..9ecd8ec2f3 100644
--- a/scene/resources/mesh_data_tool.cpp
+++ b/scene/resources/mesh_data_tool.cpp
@@ -421,6 +421,7 @@ Vector<int> MeshDataTool::get_vertex_bones(int p_idx) const {
void MeshDataTool::set_vertex_bones(int p_idx, const Vector<int> &p_bones) {
ERR_FAIL_INDEX(p_idx, vertices.size());
+ ERR_FAIL_COND(p_bones.size() != 4);
vertices.write[p_idx].bones = p_bones;
format |= Mesh::ARRAY_FORMAT_BONES;
}
@@ -432,6 +433,7 @@ Vector<float> MeshDataTool::get_vertex_weights(int p_idx) const {
void MeshDataTool::set_vertex_weights(int p_idx, const Vector<float> &p_weights) {
ERR_FAIL_INDEX(p_idx, vertices.size());
+ ERR_FAIL_COND(p_weights.size() != 4);
vertices.write[p_idx].weights = p_weights;
format |= Mesh::ARRAY_FORMAT_WEIGHTS;
}