feat: updated engine version to 4.4-rc1

This commit is contained in:
Sara 2025-02-23 14:38:14 +01:00
parent ee00efde1f
commit 21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions

View file

@ -1,4 +1,5 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
Import("env_modules")

View file

@ -7,9 +7,7 @@ def configure(env):
def get_doc_classes():
return [
"GridMap",
]
return ["GridMap", "GridMapEditorPlugin"]
def get_doc_path():

View file

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GridMapEditorPlugin" inherits="EditorPlugin" keywords="tilemap" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Editor for [GridMap] nodes.
</brief_description>
<description>
GridMapEditorPlugin provides access to the [GridMap] editor functionality.
</description>
<tutorials>
</tutorials>
<methods>
<method name="clear_selection">
<return type="void" />
<description>
Deselects any currently selected cells.
</description>
</method>
<method name="get_current_grid_map" qualifiers="const">
<return type="GridMap" />
<description>
Returns the [GridMap] node currently edited by the grid map editor.
</description>
</method>
<method name="get_selected_cells" qualifiers="const">
<return type="Array" />
<description>
Returns an array of [Vector3i]s with the selected cells' coordinates.
</description>
</method>
<method name="get_selected_palette_item" qualifiers="const">
<return type="int" />
<description>
Returns the index of the selected [MeshLibrary] item in the grid map editor's palette or [code]-1[/code] if no item is selected.
[b]Note:[/b] The indices might not be in the same order as they appear in the editor's interface.
</description>
</method>
<method name="get_selection" qualifiers="const">
<return type="AABB" />
<description>
Returns the cell coordinate bounds of the current selection. Use [method has_selection] to check if there is an active selection.
</description>
</method>
<method name="has_selection" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if there are selected cells.
</description>
</method>
<method name="set_selected_palette_item" qualifiers="const">
<return type="void" />
<param index="0" name="item" type="int" />
<description>
Selects the [MeshLibrary] item with the given index in the grid map editor's palette. If a negative index is given, no item will be selected. If a value greater than the last index is given, the last item will be selected.
[b]Note:[/b] The indices might not be in the same order as they appear in the editor's interface.
</description>
</method>
<method name="set_selection">
<return type="void" />
<param index="0" name="begin" type="Vector3i" />
<param index="1" name="end" type="Vector3i" />
<description>
Selects the cells inside the given bounds from [param begin] to [param end].
</description>
</method>
</methods>
</class>

File diff suppressed because it is too large Load diff

View file

@ -44,6 +44,9 @@
class ConfirmationDialog;
class MenuButton;
class Node3DEditorPlugin;
class ButtonGroup;
class EditorZoomWidget;
class BaseButton;
class GridMapEditor : public VBoxContainer {
GDCLASS(GridMapEditor, VBoxContainer);
@ -54,6 +57,7 @@ class GridMapEditor : public VBoxContainer {
enum InputAction {
INPUT_NONE,
INPUT_TRANSFORM,
INPUT_PAINT,
INPUT_ERASE,
INPUT_PICK,
@ -71,11 +75,31 @@ class GridMapEditor : public VBoxContainer {
MenuButton *options = nullptr;
SpinBox *floor = nullptr;
double accumulated_floor_delta = 0.0;
HBoxContainer *toolbar = nullptr;
List<BaseButton *> viewport_shortcut_buttons;
Ref<ButtonGroup> mode_buttons_group;
// mode
Button *transform_mode_button = nullptr;
Button *select_mode_button = nullptr;
Button *erase_mode_button = nullptr;
Button *paint_mode_button = nullptr;
Button *pick_mode_button = nullptr;
// action
Button *fill_action_button = nullptr;
Button *move_action_button = nullptr;
Button *duplicate_action_button = nullptr;
Button *delete_action_button = nullptr;
// rotation
Button *rotate_x_button = nullptr;
Button *rotate_y_button = nullptr;
Button *rotate_z_button = nullptr;
EditorZoomWidget *zoom_widget = nullptr;
Button *mode_thumbnail = nullptr;
Button *mode_list = nullptr;
LineEdit *search_box = nullptr;
HSlider *size_slider = nullptr;
HBoxContainer *spatial_editor_hb = nullptr;
ConfirmationDialog *settings_dialog = nullptr;
VBoxContainer *settings_vbc = nullptr;
SpinBox *settings_pick_distance = nullptr;
@ -102,6 +126,7 @@ class GridMapEditor : public VBoxContainer {
RID grid[3];
RID grid_instance[3];
RID cursor_mesh;
RID cursor_instance;
RID selection_mesh;
RID selection_instance;
@ -119,7 +144,12 @@ class GridMapEditor : public VBoxContainer {
List<ClipboardItem> clipboard_items;
Color default_color;
Color erase_color;
Color pick_color;
Ref<StandardMaterial3D> indicator_mat;
Ref<StandardMaterial3D> cursor_inner_mat;
Ref<StandardMaterial3D> cursor_outer_mat;
Ref<StandardMaterial3D> inner_mat;
Ref<StandardMaterial3D> outer_mat;
Ref<StandardMaterial3D> selection_floor_mat;
@ -196,10 +226,11 @@ class GridMapEditor : public VBoxContainer {
void _item_selected_cbk(int idx);
void _update_cursor_transform();
void _update_cursor_instance();
void _on_tool_mode_changed();
void _update_theme();
void _text_changed(const String &p_text);
void _sbox_input(const Ref<InputEvent> &p_ie);
void _sbox_input(const Ref<InputEvent> &p_event);
void _mesh_library_palette_input(const Ref<InputEvent> &p_ie);
void _icon_size_changed(float p_value);
@ -208,9 +239,13 @@ class GridMapEditor : public VBoxContainer {
void _set_clipboard_data();
void _update_paste_indicator();
void _do_paste();
void _show_viewports_transform_gizmo(bool p_value);
void _update_selection_transform();
void _validate_selection();
void _set_selection(bool p_active, const Vector3 &p_begin = Vector3(), const Vector3 &p_end = Vector3());
AABB _get_selection() const;
bool _has_selection() const;
Array _get_selected_cells() const;
void _floor_changed(float p_value);
void _floor_mouse_exited();
@ -238,18 +273,29 @@ class GridMapEditorPlugin : public EditorPlugin {
GDCLASS(GridMapEditorPlugin, EditorPlugin);
GridMapEditor *grid_map_editor = nullptr;
Button *panel_button = nullptr;
protected:
void _notification(int p_what);
static void _bind_methods();
public:
virtual EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return grid_map_editor->forward_spatial_input_event(p_camera, p_event); }
virtual String get_name() const override { return "GridMap"; }
virtual String get_plugin_name() const override { return "GridMap"; }
bool has_main_screen() const override { return false; }
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
GridMap *get_current_grid_map() const;
void set_selection(const Vector3i &p_begin, const Vector3i &p_end);
void clear_selection();
AABB get_selection() const;
bool has_selection() const;
Array get_selected_cells() const;
void set_selected_palette_item(int p_item) const;
int get_selected_palette_item() const;
GridMapEditorPlugin();
~GridMapEditorPlugin();
};

View file

@ -31,14 +31,26 @@
#include "grid_map.h"
#include "core/io/marshalls.h"
#include "scene/3d/light_3d.h"
#include "core/math/convex_hull.h"
#include "scene/resources/3d/box_shape_3d.h"
#include "scene/resources/3d/capsule_shape_3d.h"
#include "scene/resources/3d/concave_polygon_shape_3d.h"
#include "scene/resources/3d/convex_polygon_shape_3d.h"
#include "scene/resources/3d/cylinder_shape_3d.h"
#include "scene/resources/3d/height_map_shape_3d.h"
#include "scene/resources/3d/mesh_library.h"
#include "scene/resources/3d/navigation_mesh_source_geometry_data_3d.h"
#include "scene/resources/3d/primitive_meshes.h"
#include "scene/resources/3d/shape_3d.h"
#include "scene/resources/3d/sphere_shape_3d.h"
#include "scene/resources/physics_material.h"
#include "scene/resources/surface_tool.h"
#include "servers/navigation_server_3d.h"
#include "servers/rendering_server.h"
Callable GridMap::_navmesh_source_geometry_parsing_callback;
RID GridMap::_navmesh_source_geometry_parser;
bool GridMap::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
@ -70,7 +82,7 @@ bool GridMap::_set(const StringName &p_name, const Variant &p_value) {
for (int i = 0; i < meshes.size(); i++) {
BakedMesh bm;
bm.mesh = meshes[i];
ERR_CONTINUE(!bm.mesh.is_valid());
ERR_CONTINUE(bm.mesh.is_null());
bm.instance = RS::get_singleton()->instance_create();
RS::get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid());
RS::get_singleton()->instance_attach_object_instance_id(bm.instance, get_instance_id());
@ -255,11 +267,11 @@ RID GridMap::get_navigation_map() const {
}
void GridMap::set_mesh_library(const Ref<MeshLibrary> &p_mesh_library) {
if (!mesh_library.is_null()) {
if (mesh_library.is_valid()) {
mesh_library->disconnect_changed(callable_mp(this, &GridMap::_recreate_octant_data));
}
mesh_library = p_mesh_library;
if (!mesh_library.is_null()) {
if (mesh_library.is_valid()) {
mesh_library->connect_changed(callable_mp(this, &GridMap::_recreate_octant_data));
}
@ -596,7 +608,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
ERR_CONTINUE(!cell_map.has(E));
const Cell &c = cell_map[E];
if (!mesh_library.is_valid() || !mesh_library->has_item(c.item)) {
if (mesh_library.is_null() || !mesh_library->has_item(c.item)) {
continue;
}
@ -625,7 +637,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
// add the item's shape at given xform to octant's static_body
for (int i = 0; i < shapes.size(); i++) {
// add the item's shape
if (!shapes[i].shape.is_valid()) {
if (shapes[i].shape.is_null()) {
continue;
}
PhysicsServer3D::get_singleton()->body_add_shape(g.static_body, shapes[i].shape->get_rid(), xform * shapes[i].local_transform);
@ -714,6 +726,9 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
RS::get_singleton()->instance_set_transform(instance, get_global_transform());
}
RS::ShadowCastingSetting cast_shadows = (RS::ShadowCastingSetting)mesh_library->get_item_mesh_cast_shadow(E.key);
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(instance, cast_shadows);
mmi.multimesh = mm;
mmi.instance = instance;
@ -801,8 +816,8 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) {
if (!g.navigation_debug_edge_connections_instance.is_valid()) {
g.navigation_debug_edge_connections_instance = RenderingServer::get_singleton()->instance_create();
}
if (!g.navigation_debug_edge_connections_mesh.is_valid()) {
g.navigation_debug_edge_connections_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
if (g.navigation_debug_edge_connections_mesh.is_null()) {
g.navigation_debug_edge_connections_mesh.instantiate();
}
_update_octant_navigation_debug_edge_connections_mesh(p_key);
@ -847,7 +862,7 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) {
g.navigation_debug_edge_connections_instance = RID();
}
if (g.navigation_debug_edge_connections_mesh.is_valid()) {
RenderingServer::get_singleton()->free(g.navigation_debug_edge_connections_mesh->get_rid());
g.navigation_debug_edge_connections_mesh.unref();
}
}
#endif // DEBUG_ENABLED
@ -888,7 +903,7 @@ void GridMap::_octant_clean_up(const OctantKey &p_key) {
g.navigation_debug_edge_connections_instance = RID();
}
if (g.navigation_debug_edge_connections_mesh.is_valid()) {
RenderingServer::get_singleton()->free(g.navigation_debug_edge_connections_mesh->get_rid());
g.navigation_debug_edge_connections_mesh.unref();
}
}
#endif // DEBUG_ENABLED
@ -1224,7 +1239,7 @@ void GridMap::clear_baked_meshes() {
}
void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texel_size) {
if (!mesh_library.is_valid()) {
if (mesh_library.is_null()) {
return;
}
@ -1240,7 +1255,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe
}
Ref<Mesh> mesh = mesh_library->get_item_mesh(item);
if (!mesh.is_valid()) {
if (mesh.is_null()) {
continue;
}
@ -1335,6 +1350,143 @@ GridMap::GridMap() {
#endif // DEBUG_ENABLED
}
void GridMap::navmesh_parse_init() {
ERR_FAIL_NULL(NavigationServer3D::get_singleton());
if (!_navmesh_source_geometry_parser.is_valid()) {
_navmesh_source_geometry_parsing_callback = callable_mp_static(&GridMap::navmesh_parse_source_geometry);
_navmesh_source_geometry_parser = NavigationServer3D::get_singleton()->source_geometry_parser_create();
NavigationServer3D::get_singleton()->source_geometry_parser_set_callback(_navmesh_source_geometry_parser, _navmesh_source_geometry_parsing_callback);
}
}
void GridMap::navmesh_parse_source_geometry(const Ref<NavigationMesh> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry_data, Node *p_node) {
GridMap *gridmap = Object::cast_to<GridMap>(p_node);
if (gridmap == nullptr) {
return;
}
NavigationMesh::ParsedGeometryType parsed_geometry_type = p_navigation_mesh->get_parsed_geometry_type();
uint32_t parsed_collision_mask = p_navigation_mesh->get_collision_mask();
if (parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_MESH_INSTANCES || parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_BOTH) {
Array meshes = gridmap->get_meshes();
Transform3D xform = gridmap->get_global_transform();
for (int i = 0; i < meshes.size(); i += 2) {
Ref<Mesh> mesh = meshes[i + 1];
if (mesh.is_valid()) {
p_source_geometry_data->add_mesh(mesh, xform * (Transform3D)meshes[i]);
}
}
}
else if ((parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_BOTH) && (gridmap->get_collision_layer() & parsed_collision_mask)) {
Array shapes = gridmap->get_collision_shapes();
for (int i = 0; i < shapes.size(); i += 2) {
RID shape = shapes[i + 1];
PhysicsServer3D::ShapeType type = PhysicsServer3D::get_singleton()->shape_get_type(shape);
Variant data = PhysicsServer3D::get_singleton()->shape_get_data(shape);
switch (type) {
case PhysicsServer3D::SHAPE_SPHERE: {
real_t radius = data;
Array arr;
arr.resize(RS::ARRAY_MAX);
SphereMesh::create_mesh_array(arr, radius, radius * 2.0);
p_source_geometry_data->add_mesh_array(arr, shapes[i]);
} break;
case PhysicsServer3D::SHAPE_BOX: {
Vector3 extents = data;
Array arr;
arr.resize(RS::ARRAY_MAX);
BoxMesh::create_mesh_array(arr, extents * 2.0);
p_source_geometry_data->add_mesh_array(arr, shapes[i]);
} break;
case PhysicsServer3D::SHAPE_CAPSULE: {
Dictionary dict = data;
real_t radius = dict["radius"];
real_t height = dict["height"];
Array arr;
arr.resize(RS::ARRAY_MAX);
CapsuleMesh::create_mesh_array(arr, radius, height);
p_source_geometry_data->add_mesh_array(arr, shapes[i]);
} break;
case PhysicsServer3D::SHAPE_CYLINDER: {
Dictionary dict = data;
real_t radius = dict["radius"];
real_t height = dict["height"];
Array arr;
arr.resize(RS::ARRAY_MAX);
CylinderMesh::create_mesh_array(arr, radius, radius, height);
p_source_geometry_data->add_mesh_array(arr, shapes[i]);
} break;
case PhysicsServer3D::SHAPE_CONVEX_POLYGON: {
PackedVector3Array vertices = data;
Geometry3D::MeshData md;
Error err = ConvexHullComputer::convex_hull(vertices, md);
if (err == OK) {
PackedVector3Array faces;
for (const Geometry3D::MeshData::Face &face : md.faces) {
for (uint32_t k = 2; k < face.indices.size(); ++k) {
faces.push_back(md.vertices[face.indices[0]]);
faces.push_back(md.vertices[face.indices[k - 1]]);
faces.push_back(md.vertices[face.indices[k]]);
}
}
p_source_geometry_data->add_faces(faces, shapes[i]);
}
} break;
case PhysicsServer3D::SHAPE_CONCAVE_POLYGON: {
Dictionary dict = data;
PackedVector3Array faces = Variant(dict["faces"]);
p_source_geometry_data->add_faces(faces, shapes[i]);
} break;
case PhysicsServer3D::SHAPE_HEIGHTMAP: {
Dictionary dict = data;
///< dict( int:"width", int:"depth",float:"cell_size", float_array:"heights"
int heightmap_depth = dict["depth"];
int heightmap_width = dict["width"];
if (heightmap_depth >= 2 && heightmap_width >= 2) {
const Vector<real_t> &map_data = dict["heights"];
Vector2 heightmap_gridsize(heightmap_width - 1, heightmap_depth - 1);
Vector3 start = Vector3(heightmap_gridsize.x, 0, heightmap_gridsize.y) * -0.5;
Vector<Vector3> vertex_array;
vertex_array.resize((heightmap_depth - 1) * (heightmap_width - 1) * 6);
Vector3 *vertex_array_ptrw = vertex_array.ptrw();
const real_t *map_data_ptr = map_data.ptr();
int vertex_index = 0;
for (int d = 0; d < heightmap_depth - 1; d++) {
for (int w = 0; w < heightmap_width - 1; w++) {
vertex_array_ptrw[vertex_index] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + w], d);
vertex_array_ptrw[vertex_index + 1] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + w + 1], d);
vertex_array_ptrw[vertex_index + 2] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + heightmap_width + w], d + 1);
vertex_array_ptrw[vertex_index + 3] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + w + 1], d);
vertex_array_ptrw[vertex_index + 4] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + heightmap_width + w + 1], d + 1);
vertex_array_ptrw[vertex_index + 5] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + heightmap_width + w], d + 1);
vertex_index += 6;
}
}
if (vertex_array.size() > 0) {
p_source_geometry_data->add_faces(vertex_array, shapes[i]);
}
}
} break;
default: {
WARN_PRINT("Unsupported collision shape type.");
} break;
}
}
}
}
#ifdef DEBUG_ENABLED
void GridMap::_update_navigation_debug_edge_connections() {
if (bake_navigation) {
@ -1386,8 +1538,8 @@ void GridMap::_update_octant_navigation_debug_edge_connections_mesh(const Octant
g.navigation_debug_edge_connections_instance = RenderingServer::get_singleton()->instance_create();
}
if (!g.navigation_debug_edge_connections_mesh.is_valid()) {
g.navigation_debug_edge_connections_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
if (g.navigation_debug_edge_connections_mesh.is_null()) {
g.navigation_debug_edge_connections_mesh.instantiate();
}
g.navigation_debug_edge_connections_mesh->clear_surfaces();

View file

@ -38,6 +38,8 @@
//heh heh, godotsphir!! this shares no code and the design is completely different with previous projects i've done..
//should scale better with hardware that supports instancing
class NavigationMesh;
class NavigationMeshSourceGeometryData3D;
class PhysicsMaterial;
class GridMap : public Node3D {
@ -300,6 +302,14 @@ public:
Array get_bake_meshes();
RID get_bake_mesh_instance(int p_idx);
private:
static Callable _navmesh_source_geometry_parsing_callback;
static RID _navmesh_source_geometry_parser;
public:
static void navmesh_parse_init();
static void navmesh_parse_source_geometry(const Ref<NavigationMesh> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry_data, Node *p_node);
GridMap();
~GridMap();
};

View file

@ -43,9 +43,11 @@
void initialize_gridmap_module(ModuleInitializationLevel p_level) {
if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
GDREGISTER_CLASS(GridMap);
GridMap::navmesh_parse_init();
}
#ifdef TOOLS_ENABLED
if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
GDREGISTER_CLASS(GridMapEditorPlugin);
EditorPlugins::add_by_type<GridMapEditorPlugin>();
}
#endif