summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/bullet/SCsub2
-rw-r--r--modules/bullet/bullet_physics_server.cpp4
-rw-r--r--modules/bullet/bullet_physics_server.h2
-rw-r--r--modules/bullet/godot_result_callbacks.cpp4
-rw-r--r--modules/bullet/godot_result_callbacks.h4
-rw-r--r--modules/bullet/rigid_body_bullet.cpp10
-rw-r--r--modules/bullet/rigid_body_bullet.h4
-rw-r--r--modules/bullet/space_bullet.cpp41
-rw-r--r--modules/bullet/space_bullet.h4
-rw-r--r--modules/csg/csg_gizmos.cpp4
-rw-r--r--modules/csg/csg_gizmos.h4
-rw-r--r--modules/csg/csg_shape.cpp701
-rw-r--r--modules/csg/csg_shape.h19
-rw-r--r--modules/csg/doc_classes/CSGPolygon3D.xml42
-rw-r--r--modules/csg/doc_classes/CSGShape3D.xml24
-rw-r--r--modules/denoise/lightmap_denoiser.cpp2
-rw-r--r--modules/enet/doc_classes/ENetConnection.xml2
-rw-r--r--modules/enet/enet_multiplayer_peer.cpp2
-rw-r--r--modules/fbx/data/fbx_material.cpp6
-rw-r--r--modules/fbx/data/fbx_mesh_data.cpp4
-rw-r--r--modules/fbx/data/fbx_mesh_data.h2
-rw-r--r--modules/fbx/fbx_parser/FBXParser.cpp2
-rw-r--r--modules/freetype/SCsub1
-rw-r--r--modules/gdnative/gdnative/packed_arrays.cpp2
-rw-r--r--modules/gdnative/gdnative/variant.cpp116
-rw-r--r--modules/gdnative/nativescript/api_generator.cpp8
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp22
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.cpp17
-rw-r--r--modules/gdnative/text/text_server_gdnative.cpp8
-rw-r--r--modules/gdnative/text/text_server_gdnative.h6
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp52
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.h2
-rw-r--r--modules/gdscript/gdscript.cpp9
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp85
-rw-r--r--modules/gdscript/gdscript_analyzer.h2
-rw-r--r--modules/gdscript/gdscript_cache.cpp2
-rw-r--r--modules/gdscript/gdscript_compiler.cpp5
-rw-r--r--modules/gdscript/gdscript_editor.cpp74
-rw-r--r--modules/gdscript/gdscript_function.h6
-rw-r--r--modules/gdscript/gdscript_parser.cpp50
-rw-r--r--modules/gdscript/gdscript_parser.h1
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp2
-rw-r--r--modules/gdscript/gdscript_vm.cpp2
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp36
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.h2
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp127
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.h3
-rw-r--r--modules/gdscript/language_server/lsp.hpp60
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.gd3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.out3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.out1
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.gd11
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.out2
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp2
-rw-r--r--modules/gltf/gltf_document.cpp12
-rw-r--r--modules/gltf/gltf_document.h4
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml24
-rw-r--r--modules/gridmap/grid_map.cpp48
-rw-r--r--modules/gridmap/grid_map.h8
-rw-r--r--modules/gridmap/grid_map_editor_plugin.cpp2
-rw-r--r--modules/mobile_vr/mobile_vr_interface.h8
-rw-r--r--modules/mono/csharp_script.cpp195
-rw-r--r--modules/mono/csharp_script.h17
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs20
-rw-r--r--modules/mono/editor/bindings_generator.cpp12
-rw-r--r--modules/mono/editor/bindings_generator.h2
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs259
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs4
-rw-r--r--modules/mono/glue/base_object_glue.cpp10
-rw-r--r--modules/mono/glue/collections_glue.cpp15
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp54
-rw-r--r--modules/mono/mono_gd/gd_mono.h16
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.cpp7
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp8
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp19
-rw-r--r--modules/mono/register_types.cpp8
-rw-r--r--modules/navigation/navigation_mesh_generator.cpp6
-rw-r--r--modules/navigation/navigation_mesh_generator.h2
-rw-r--r--modules/text_server_adv/SCsub2
-rw-r--r--modules/text_server_adv/bitmap_font_adv.cpp2
-rw-r--r--modules/text_server_adv/text_server_adv.cpp448
-rw-r--r--modules/text_server_adv/text_server_adv.h7
-rw-r--r--modules/text_server_fb/text_server_fb.cpp391
-rw-r--r--modules/text_server_fb/text_server_fb.h7
-rw-r--r--modules/vhacd/register_types.cpp2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptCustomNode.xml54
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSubCall.xml7
-rw-r--r--modules/visual_script/register_types.cpp8
-rw-r--r--modules/visual_script/visual_script.cpp20
-rw-r--r--modules/visual_script/visual_script_editor.cpp44
-rw-r--r--modules/visual_script/visual_script_editor.h27
-rw-r--r--modules/visual_script/visual_script_nodes.cpp164
-rw-r--r--modules/visual_script/visual_script_nodes.h26
-rw-r--r--modules/visual_script/visual_script_property_selector.cpp4
-rw-r--r--modules/visual_script/visual_script_yield_nodes.cpp6
-rw-r--r--modules/visual_script/visual_script_yield_nodes.h6
-rw-r--r--modules/websocket/emws_peer.cpp2
105 files changed, 2010 insertions, 1616 deletions
diff --git a/modules/bullet/SCsub b/modules/bullet/SCsub
index bfac0df5b0..ba57de303e 100644
--- a/modules/bullet/SCsub
+++ b/modules/bullet/SCsub
@@ -12,6 +12,8 @@ thirdparty_obj = []
if env["builtin_bullet"]:
# Build only version 2 for now (as of 2.89)
# Sync file list with relevant upstream CMakeLists.txt for each folder.
+ if env["float"] == "64":
+ env.Append(CPPDEFINES=["BT_USE_DOUBLE_PRECISION=1"])
thirdparty_dir = "#thirdparty/bullet/"
bullet2_src = [
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index e07be14c5b..fc876a81cf 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -842,12 +842,12 @@ PhysicsDirectBodyState3D *BulletPhysicsServer3D::body_get_direct_state(RID p_bod
return BulletPhysicsDirectBodyState3D::get_singleton(body);
}
-bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes) {
+bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, false);
ERR_FAIL_COND_V(!body->get_space(), false);
- return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes);
+ return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes, p_exclude);
}
int BulletPhysicsServer3D::body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) {
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index d34d619ba2..7f0934e679 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -253,7 +253,7 @@ public:
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override;
- virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override;
+ virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) override;
virtual int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override;
/* SOFT BODY API */
diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp
index 399b102284..1f962772e7 100644
--- a/modules/bullet/godot_result_callbacks.cpp
+++ b/modules/bullet/godot_result_callbacks.cpp
@@ -135,6 +135,10 @@ bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *prox
if (m_self_object->has_collision_exception(gObj) || gObj->has_collision_exception(m_self_object)) {
return false;
}
+
+ if (m_exclude->has(gObj->get_self())) {
+ return false;
+ }
}
return true;
} else {
diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h
index 9216322108..96a649d77a 100644
--- a/modules/bullet/godot_result_callbacks.h
+++ b/modules/bullet/godot_result_callbacks.h
@@ -100,11 +100,13 @@ public:
struct GodotKinClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback {
public:
const RigidBodyBullet *m_self_object;
+ const Set<RID> *m_exclude;
const bool m_infinite_inertia;
- GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_infinite_inertia) :
+ GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_infinite_inertia, const Set<RID> *p_exclude) :
btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld),
m_self_object(p_self_object),
+ m_exclude(p_exclude),
m_infinite_inertia(p_infinite_inertia) {}
virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index ce39d4f0df..0d2cd1f5a0 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -114,6 +114,16 @@ Transform3D BulletPhysicsDirectBodyState3D::get_transform() const {
return body->get_transform();
}
+Vector3 BulletPhysicsDirectBodyState3D::get_velocity_at_local_position(const Vector3 &p_position) const {
+ btVector3 local_position;
+ G_TO_B(p_position, local_position);
+
+ Vector3 velocity;
+ B_TO_G(body->btBody->getVelocityInLocalPoint(local_position), velocity);
+
+ return velocity;
+}
+
void BulletPhysicsDirectBodyState3D::add_central_force(const Vector3 &p_force) {
body->apply_central_force(p_force);
}
diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h
index 606df7134b..01ac1e4836 100644
--- a/modules/bullet/rigid_body_bullet.h
+++ b/modules/bullet/rigid_body_bullet.h
@@ -110,6 +110,8 @@ public:
virtual void set_transform(const Transform3D &p_transform) override;
virtual Transform3D get_transform() const override;
+ virtual Vector3 get_velocity_at_local_position(const Vector3 &p_position) const override;
+
virtual void add_central_force(const Vector3 &p_force) override;
virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) override;
virtual void add_torque(const Vector3 &p_torque) override;
@@ -299,7 +301,7 @@ public:
void reload_axis_lock();
/// Doc:
- /// https://web.archive.org/web/20180404091446/http://www.bulletphysics.org/mediawiki-1.5.8/index.php/Anti_tunneling_by_Motion_Clamping
+ /// https://web.archive.org/web/20180404091446/https://www.bulletphysics.org/mediawiki-1.5.8/index.php/Anti_tunneling_by_Motion_Clamping
void set_continuous_collision_detection(bool p_enable);
bool is_continuous_collision_detection_enabled() const;
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index 583900e6bc..a9a811c445 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -908,7 +908,7 @@ static Ref<StandardMaterial3D> red_mat;
static Ref<StandardMaterial3D> blue_mat;
#endif
-bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) {
+bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
#if debug_test_motion
/// Yes I know this is not good, but I've used it as fast debugging hack.
/// I'm leaving it here just for speedup the other eventual debugs
@@ -945,10 +945,15 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p
G_TO_B(p_from, body_transform);
UNSCALE_BT_BASIS(body_transform);
+ if (!p_body->get_kinematic_utilities()) {
+ p_body->init_kinematic_utilities();
+ p_body->reload_kinematic_shapes();
+ }
+
btVector3 initial_recover_motion(0, 0, 0);
{ /// Phase one - multi shapes depenetration using margin
for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) {
- if (!recover_from_penetration(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, initial_recover_motion)) {
+ if (!recover_from_penetration(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, initial_recover_motion, nullptr, p_exclude)) {
break;
}
}
@@ -958,6 +963,9 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p
btVector3 motion;
G_TO_B(p_motion, motion);
+ real_t total_length = motion.length();
+ real_t unsafe_fraction = 1.0;
+ real_t safe_fraction = 1.0;
{
// Phase two - sweep test, from a secure position without margin
@@ -1000,13 +1008,22 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p
break;
}
- GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, p_infinite_inertia);
+ GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, p_infinite_inertia, &p_exclude);
btResult.m_collisionFilterGroup = p_body->get_collision_layer();
btResult.m_collisionFilterMask = p_body->get_collision_mask();
dynamicsWorld->convexSweepTest(convex_shape_test, shape_world_from, shape_world_to, btResult, dynamicsWorld->getDispatchInfo().m_allowedCcdPenetration);
if (btResult.hasHit()) {
+ if (total_length > CMP_EPSILON) {
+ real_t hit_fraction = btResult.m_closestHitFraction * motion.length() / total_length;
+ if (hit_fraction < unsafe_fraction) {
+ unsafe_fraction = hit_fraction;
+ real_t margin = p_body->get_kinematic_utilities()->safe_margin;
+ safe_fraction = MAX(hit_fraction - (1 - ((total_length - margin) / total_length)), 0);
+ }
+ }
+
/// Since for each sweep test I fix the motion of new shapes in base the recover result,
/// if another shape will hit something it means that has a deepest penetration respect the previous shape
motion *= btResult.m_closestHitFraction;
@@ -1023,7 +1040,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p
btVector3 __rec(0, 0, 0);
RecoverResult r_recover_result;
- has_penetration = recover_from_penetration(p_body, body_transform, 1, p_infinite_inertia, __rec, &r_recover_result);
+ has_penetration = recover_from_penetration(p_body, body_transform, 1, p_infinite_inertia, __rec, &r_recover_result, p_exclude);
// Parse results
if (r_result) {
@@ -1043,6 +1060,9 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p
r_result->collider_id = collisionObject->get_instance_id();
r_result->collider_shape = r_recover_result.other_compound_shape_index;
r_result->collision_local_shape = r_recover_result.local_shape_most_recovered;
+ r_result->collision_depth = Math::abs(r_recover_result.penetration_distance);
+ r_result->collision_safe_fraction = safe_fraction;
+ r_result->collision_unsafe_fraction = unsafe_fraction;
#if debug_test_motion
Vector3 sup_line2;
@@ -1067,6 +1087,11 @@ int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform3D
G_TO_B(p_transform, body_transform);
UNSCALE_BT_BASIS(body_transform);
+ if (!p_body->get_kinematic_utilities()) {
+ p_body->init_kinematic_utilities();
+ p_body->reload_kinematic_shapes();
+ }
+
btVector3 recover_motion(0, 0, 0);
int rays_found = 0;
@@ -1173,7 +1198,7 @@ public:
}
};
-bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) {
+bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result, const Set<RID> &p_exclude) {
// Calculate the cumulative AABB of all shapes of the kinematic body
btVector3 aabb_min, aabb_max;
bool shapes_found = false;
@@ -1242,6 +1267,12 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran
for (int i = recover_broad_result.results.size() - 1; 0 <= i; --i) {
btCollisionObject *otherObject = recover_broad_result.results[i].collision_object;
+
+ CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(otherObject->getUserPointer());
+ if (p_exclude.has(gObj->get_self())) {
+ continue;
+ }
+
if (p_infinite_inertia && !otherObject->isStaticOrKinematicObject()) {
otherObject->activate(); // Force activation of hitten rigid, soft body
continue;
diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h
index 36d0538e6b..2070e0e633 100644
--- a/modules/bullet/space_bullet.h
+++ b/modules/bullet/space_bullet.h
@@ -188,7 +188,7 @@ public:
real_t get_linear_damp() const { return linear_damp; }
real_t get_angular_damp() const { return angular_damp; }
- bool test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes);
+ bool test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude = Set<RID>());
int test_ray_separation(RigidBodyBullet *p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin);
private:
@@ -209,7 +209,7 @@ private:
RecoverResult() {}
};
- bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr);
+ bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr, const Set<RID> &p_exclude = Set<RID>());
/// This is an API that recover a kinematic object from penetration
/// This allow only Convex Convex test and it always use GJK algorithm, With this API we don't benefit of Bullet special accelerated functions
bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr);
diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp
index 42f8b9f163..2f8b354bb7 100644
--- a/modules/csg/csg_gizmos.cpp
+++ b/modules/csg/csg_gizmos.cpp
@@ -98,7 +98,7 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo
return Variant();
}
-void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const {
+void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
Transform3D gt = cs->get_global_transform();
@@ -201,7 +201,7 @@ void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_i
}
}
-void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const {
+void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
if (Object::cast_to<CSGSphere3D>(cs)) {
diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h
index 847313c0b4..2a6ab91102 100644
--- a/modules/csg/csg_gizmos.h
+++ b/modules/csg/csg_gizmos.h
@@ -47,8 +47,8 @@ public:
virtual String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
virtual Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- virtual void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const override;
- virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const override;
+ virtual void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
+ virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) override;
CSGShape3DGizmoPlugin();
};
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index b47fa35f1a..bf11cc7f68 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -29,8 +29,8 @@
/*************************************************************************/
#include "csg_shape.h"
+
#include "core/math/geometry_2d.h"
-#include "scene/3d/path_3d.h"
void CSGShape3D::set_use_collision(bool p_enable) {
if (use_collision == p_enable) {
@@ -88,36 +88,40 @@ uint32_t CSGShape3D::get_collision_mask() const {
return collision_mask;
}
-void CSGShape3D::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
- uint32_t mask = get_collision_mask();
+void CSGShape3D::set_collision_layer_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
+ uint32_t collision_layer = get_collision_layer();
if (p_value) {
- mask |= 1 << p_bit;
+ collision_layer |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ collision_layer &= ~(1 << (p_layer_number - 1));
}
- set_collision_mask(mask);
+ set_collision_layer(collision_layer);
}
-bool CSGShape3D::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+bool CSGShape3D::get_collision_layer_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_layer() & (1 << (p_layer_number - 1));
}
-void CSGShape3D::set_collision_layer_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
- uint32_t layer = get_collision_layer();
+void CSGShape3D::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
+ uint32_t mask = get_collision_mask();
if (p_value) {
- layer |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- layer &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
- set_collision_layer(layer);
+ set_collision_mask(mask);
}
-bool CSGShape3D::get_collision_layer_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
- return get_collision_layer() & (1 << p_bit);
+bool CSGShape3D::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
bool CSGShape3D::is_root_shape() const {
@@ -605,11 +609,11 @@ void CSGShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CSGShape3D::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &CSGShape3D::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CSGShape3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CSGShape3D::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &CSGShape3D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &CSGShape3D::get_collision_mask_value);
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &CSGShape3D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CSGShape3D::get_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &CSGShape3D::set_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &CSGShape3D::get_collision_layer_value);
ClassDB::bind_method(D_METHOD("set_calculate_tangents", "enabled"), &CSGShape3D::set_calculate_tangents);
ClassDB::bind_method(D_METHOD("is_calculating_tangents"), &CSGShape3D::is_calculating_tangents);
@@ -1676,109 +1680,80 @@ CSGTorus3D::CSGTorus3D() {
///////////////
CSGBrush *CSGPolygon3D::_build_brush() {
- // set our bounding box
+ CSGBrush *brush = memnew(CSGBrush);
if (polygon.size() < 3) {
- return memnew(CSGBrush);
+ return brush;
}
- Vector<Point2> final_polygon = polygon;
-
- if (Triangulate::get_area(final_polygon) > 0) {
- final_polygon.reverse();
+ // Triangulate polygon shape.
+ Vector<Point2> shape_polygon = polygon;
+ if (Triangulate::get_area(shape_polygon) > 0) {
+ shape_polygon.reverse();
}
-
- Vector<int> triangles = Geometry2D::triangulate_polygon(final_polygon);
-
- if (triangles.size() < 3) {
- return memnew(CSGBrush);
+ int shape_sides = shape_polygon.size();
+ Vector<int> shape_faces = Geometry2D::triangulate_polygon(shape_polygon);
+ ERR_FAIL_COND_V_MSG(shape_faces.size() < 3, brush, "Failed to triangulate CSGPolygon");
+
+ // Get polygon enclosing Rect2.
+ Rect2 shape_rect(shape_polygon[0], Vector2());
+ for (int i = 1; i < shape_sides; i++) {
+ shape_rect.expand_to(shape_polygon[i]);
}
- Path3D *path = nullptr;
+ // If MODE_PATH, check if curve has changed.
Ref<Curve3D> curve;
-
- // get bounds for our polygon
- Vector2 final_polygon_min;
- Vector2 final_polygon_max;
- for (int i = 0; i < final_polygon.size(); i++) {
- Vector2 p = final_polygon[i];
- if (i == 0) {
- final_polygon_min = p;
- final_polygon_max = final_polygon_min;
- } else {
- if (p.x < final_polygon_min.x) {
- final_polygon_min.x = p.x;
- }
- if (p.y < final_polygon_min.y) {
- final_polygon_min.y = p.y;
- }
-
- if (p.x > final_polygon_max.x) {
- final_polygon_max.x = p.x;
+ if (mode == MODE_PATH) {
+ Path3D *current_path = Object::cast_to<Path3D>(get_node_or_null(path_node));
+ if (path != current_path) {
+ if (path) {
+ path->disconnect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited));
+ path->disconnect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed));
}
- if (p.y > final_polygon_max.y) {
- final_polygon_max.y = p.y;
+ path = current_path;
+ if (path) {
+ path->connect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited));
+ path->connect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed));
}
}
- }
- Vector2 final_polygon_size = final_polygon_max - final_polygon_min;
- if (mode == MODE_PATH) {
- if (!has_node(path_node)) {
- return memnew(CSGBrush);
- }
- Node *n = get_node(path_node);
- if (!n) {
- return memnew(CSGBrush);
- }
- path = Object::cast_to<Path3D>(n);
if (!path) {
- return memnew(CSGBrush);
+ return brush;
}
- if (path != path_cache) {
- if (path_cache) {
- path_cache->disconnect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited));
- path_cache->disconnect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed));
- path_cache = nullptr;
- }
-
- path_cache = path;
-
- path_cache->connect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited));
- path_cache->connect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed));
- }
curve = path->get_curve();
- if (curve.is_null()) {
- return memnew(CSGBrush);
- }
- if (curve->get_baked_length() <= 0) {
- return memnew(CSGBrush);
+ if (curve.is_null() || curve->get_point_count() < 2) {
+ return brush;
}
}
- CSGBrush *brush = memnew(CSGBrush);
-
- int face_count = 0;
+ // Calculate the number extrusions, ends and faces.
+ int extrusions = 0;
+ int extrusion_face_count = shape_sides * 2;
+ int end_count = 0;
+ int shape_face_count = shape_faces.size() / 3;
switch (mode) {
case MODE_DEPTH:
- face_count = triangles.size() * 2 / 3 + (final_polygon.size()) * 2;
+ extrusions = 1;
+ end_count = 2;
break;
case MODE_SPIN:
- face_count = (spin_degrees < 360 ? triangles.size() * 2 / 3 : 0) + (final_polygon.size()) * 2 * spin_sides;
+ extrusions = spin_sides;
+ if (spin_degrees < 360) {
+ end_count = 2;
+ }
break;
case MODE_PATH: {
- float bl = curve->get_baked_length();
- int splits = MAX(2, Math::ceil(bl / path_interval));
- if (path_joined) {
- face_count = splits * final_polygon.size() * 2;
- } else {
- face_count = triangles.size() * 2 / 3 + splits * final_polygon.size() * 2;
+ extrusions = Math::ceil(1.0 * curve->get_point_count() / path_interval);
+ if (!path_joined) {
+ end_count = 2;
+ extrusions -= 1;
}
} break;
}
+ int face_count = extrusions * extrusion_face_count + end_count * shape_face_count;
- bool invert_val = is_inverting_faces();
+ // Intialize variables used to create the mesh.
Ref<Material> material = get_material();
Vector<Vector3> faces;
@@ -1789,362 +1764,216 @@ CSGBrush *CSGPolygon3D::_build_brush() {
faces.resize(face_count * 3);
uvs.resize(face_count * 3);
-
smooth.resize(face_count);
materials.resize(face_count);
invert.resize(face_count);
- AABB aabb; //must be computed
- {
- Vector3 *facesw = faces.ptrw();
- Vector2 *uvsw = uvs.ptrw();
- bool *smoothw = smooth.ptrw();
- Ref<Material> *materialsw = materials.ptrw();
- bool *invertw = invert.ptrw();
-
- int face = 0;
-
- switch (mode) {
- case MODE_DEPTH: {
- //add triangles, front and back
- for (int i = 0; i < 2; i++) {
- for (int j = 0; j < triangles.size(); j += 3) {
- for (int k = 0; k < 3; k++) {
- int src[3] = { 0, i == 0 ? 1 : 2, i == 0 ? 2 : 1 };
- Vector2 p = final_polygon[triangles[j + src[k]]];
- Vector3 v = Vector3(p.x, p.y, 0);
- if (i == 0) {
- v.z -= depth;
- }
- facesw[face * 3 + k] = v;
- uvsw[face * 3 + k] = (p - final_polygon_min) / final_polygon_size;
- if (i == 0) {
- uvsw[face * 3 + k].x = 1.0 - uvsw[face * 3 + k].x; /* flip x */
- }
- }
-
- smoothw[face] = false;
- materialsw[face] = material;
- invertw[face] = invert_val;
- face++;
- }
- }
-
- //add triangles for depth
- for (int i = 0; i < final_polygon.size(); i++) {
- int i_n = (i + 1) % final_polygon.size();
-
- Vector3 v[4] = {
- Vector3(final_polygon[i].x, final_polygon[i].y, -depth),
- Vector3(final_polygon[i_n].x, final_polygon[i_n].y, -depth),
- Vector3(final_polygon[i_n].x, final_polygon[i_n].y, 0),
- Vector3(final_polygon[i].x, final_polygon[i].y, 0),
- };
-
- Vector2 u[4] = {
- Vector2(0, 0),
- Vector2(0, 1),
- Vector2(1, 1),
- Vector2(1, 0)
- };
+ Vector3 *facesw = faces.ptrw();
+ Vector2 *uvsw = uvs.ptrw();
+ bool *smoothw = smooth.ptrw();
+ Ref<Material> *materialsw = materials.ptrw();
+ bool *invertw = invert.ptrw();
+
+ int face = 0;
+ Transform3D base_xform;
+ Transform3D current_xform;
+ Transform3D previous_xform;
+ double u_step = 1.0 / extrusions;
+ double v_step = 1.0 / shape_sides;
+ double spin_step = Math::deg2rad(spin_degrees / spin_sides);
+ double extrusion_step = 1.0 / extrusions;
+ if (mode == MODE_PATH) {
+ if (path_joined) {
+ extrusion_step = 1.0 / (extrusions - 1);
+ }
+ extrusion_step *= curve->get_baked_length();
+ }
- // face 1
- facesw[face * 3 + 0] = v[0];
- facesw[face * 3 + 1] = v[1];
- facesw[face * 3 + 2] = v[2];
+ if (mode == MODE_PATH) {
+ if (!path_local) {
+ base_xform = path->get_global_transform();
+ }
- uvsw[face * 3 + 0] = u[0];
- uvsw[face * 3 + 1] = u[1];
- uvsw[face * 3 + 2] = u[2];
+ Vector3 current_point = curve->interpolate_baked(0);
+ Vector3 next_point = curve->interpolate_baked(extrusion_step);
+ Vector3 current_up = Vector3(0, 1, 0);
+ Vector3 direction = next_point - current_point;
- smoothw[face] = smooth_faces;
- invertw[face] = invert_val;
- materialsw[face] = material;
+ if (path_joined) {
+ Vector3 last_point = curve->interpolate_baked(curve->get_baked_length());
+ direction = next_point - last_point;
+ }
- face++;
+ switch (path_rotation) {
+ case PATH_ROTATION_POLYGON:
+ direction = Vector3(0, 0, -1);
+ break;
+ case PATH_ROTATION_PATH:
+ break;
+ case PATH_ROTATION_PATH_FOLLOW:
+ current_up = curve->interpolate_baked_up_vector(0);
+ break;
+ }
- // face 2
- facesw[face * 3 + 0] = v[2];
- facesw[face * 3 + 1] = v[3];
- facesw[face * 3 + 2] = v[0];
+ Transform3D facing = Transform3D().looking_at(direction, current_up);
+ current_xform = base_xform.translated(current_point) * facing;
+ }
- uvsw[face * 3 + 0] = u[2];
- uvsw[face * 3 + 1] = u[3];
- uvsw[face * 3 + 2] = u[0];
+ // Create the mesh.
+ if (end_count > 0) {
+ // Add front end face.
+ for (int face_idx = 0; face_idx < shape_face_count; face_idx++) {
+ for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) {
+ // We need to reverse the rotation of the shape face vertices.
+ int index = shape_faces[face_idx * 3 + 2 - face_vertex_idx];
+ Point2 p = shape_polygon[index];
+ Point2 uv = (p - shape_rect.position) / shape_rect.size;
+
+ // Use the left side of the bottom half of the y-inverted texture.
+ uv.x = uv.x / 2;
+ uv.y = 1 - (uv.y / 2);
+
+ facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0));
+ uvsw[face * 3 + face_vertex_idx] = uv;
+ }
- smoothw[face] = smooth_faces;
- invertw[face] = invert_val;
- materialsw[face] = material;
+ smoothw[face] = false;
+ materialsw[face] = material;
+ invertw[face] = invert_faces;
+ face++;
+ }
+ }
- face++;
- }
+ // Add extrusion faces.
+ for (int x0 = 0; x0 < extrusions; x0++) {
+ previous_xform = current_xform;
+ switch (mode) {
+ case MODE_DEPTH: {
+ current_xform.translate(Vector3(0, 0, -depth));
} break;
case MODE_SPIN: {
- for (int i = 0; i < spin_sides; i++) {
- float inci = float(i) / spin_sides;
- float inci_n = float((i + 1)) / spin_sides;
-
- float angi = -Math::deg2rad(inci * spin_degrees);
- float angi_n = -Math::deg2rad(inci_n * spin_degrees);
-
- Vector3 normali = Vector3(Math::cos(angi), 0, Math::sin(angi));
- Vector3 normali_n = Vector3(Math::cos(angi_n), 0, Math::sin(angi_n));
-
- //add triangles for depth
- for (int j = 0; j < final_polygon.size(); j++) {
- int j_n = (j + 1) % final_polygon.size();
-
- Vector3 v[4] = {
- Vector3(normali.x * final_polygon[j].x, final_polygon[j].y, normali.z * final_polygon[j].x),
- Vector3(normali.x * final_polygon[j_n].x, final_polygon[j_n].y, normali.z * final_polygon[j_n].x),
- Vector3(normali_n.x * final_polygon[j_n].x, final_polygon[j_n].y, normali_n.z * final_polygon[j_n].x),
- Vector3(normali_n.x * final_polygon[j].x, final_polygon[j].y, normali_n.z * final_polygon[j].x),
- };
-
- Vector2 u[4] = {
- Vector2(0, 0),
- Vector2(0, 1),
- Vector2(1, 1),
- Vector2(1, 0)
- };
-
- // face 1
- facesw[face * 3 + 0] = v[0];
- facesw[face * 3 + 1] = v[2];
- facesw[face * 3 + 2] = v[1];
-
- uvsw[face * 3 + 0] = u[0];
- uvsw[face * 3 + 1] = u[2];
- uvsw[face * 3 + 2] = u[1];
-
- smoothw[face] = smooth_faces;
- invertw[face] = invert_val;
- materialsw[face] = material;
-
- face++;
-
- // face 2
- facesw[face * 3 + 0] = v[2];
- facesw[face * 3 + 1] = v[0];
- facesw[face * 3 + 2] = v[3];
-
- uvsw[face * 3 + 0] = u[2];
- uvsw[face * 3 + 1] = u[0];
- uvsw[face * 3 + 2] = u[3];
-
- smoothw[face] = smooth_faces;
- invertw[face] = invert_val;
- materialsw[face] = material;
-
- face++;
- }
-
- if (i == 0 && spin_degrees < 360) {
- for (int j = 0; j < triangles.size(); j += 3) {
- for (int k = 0; k < 3; k++) {
- int src[3] = { 0, 2, 1 };
- Vector2 p = final_polygon[triangles[j + src[k]]];
- Vector3 v = Vector3(p.x, p.y, 0);
- facesw[face * 3 + k] = v;
- uvsw[face * 3 + k] = (p - final_polygon_min) / final_polygon_size;
- }
-
- smoothw[face] = false;
- materialsw[face] = material;
- invertw[face] = invert_val;
- face++;
- }
- }
-
- if (i == spin_sides - 1 && spin_degrees < 360) {
- for (int j = 0; j < triangles.size(); j += 3) {
- for (int k = 0; k < 3; k++) {
- int src[3] = { 0, 1, 2 };
- Vector2 p = final_polygon[triangles[j + src[k]]];
- Vector3 v = Vector3(normali_n.x * p.x, p.y, normali_n.z * p.x);
- facesw[face * 3 + k] = v;
- uvsw[face * 3 + k] = (p - final_polygon_min) / final_polygon_size;
- uvsw[face * 3 + k].x = 1.0 - uvsw[face * 3 + k].x; /* flip x */
- }
-
- smoothw[face] = false;
- materialsw[face] = material;
- invertw[face] = invert_val;
- face++;
- }
- }
- }
+ current_xform.rotate(Vector3(0, 1, 0), spin_step);
} break;
case MODE_PATH: {
- float bl = curve->get_baked_length();
- int splits = MAX(2, Math::ceil(bl / path_interval));
- float u1 = 0.0;
- float u2 = path_continuous_u ? 0.0 : 1.0;
-
- Transform3D path_to_this;
- if (!path_local) {
- // center on paths origin
- path_to_this = get_global_transform().affine_inverse() * path->get_global_transform();
- }
-
- Transform3D prev_xf;
-
- Vector3 lookat_dir;
-
- if (path_rotation == PATH_ROTATION_POLYGON) {
- lookat_dir = (path->get_global_transform().affine_inverse() * get_global_transform()).xform(Vector3(0, 0, -1));
- } else {
- Vector3 p1, p2;
- p1 = curve->interpolate_baked(0);
- p2 = curve->interpolate_baked(0.1);
- lookat_dir = (p2 - p1).normalized();
- }
-
- for (int i = 0; i <= splits; i++) {
- float ofs = i * path_interval;
- if (ofs > bl) {
- ofs = bl;
- }
- if (i == splits && path_joined) {
- ofs = 0.0;
- }
-
- Transform3D xf;
- xf.origin = curve->interpolate_baked(ofs);
-
- Vector3 local_dir;
-
- if (path_rotation == PATH_ROTATION_PATH_FOLLOW && ofs > 0) {
- //before end
- Vector3 p1 = curve->interpolate_baked(ofs - 0.1);
- Vector3 p2 = curve->interpolate_baked(ofs);
- local_dir = (p2 - p1).normalized();
-
+ double previous_offset = x0 * extrusion_step;
+ double current_offset = (x0 + 1) * extrusion_step;
+ double next_offset = (x0 + 2) * extrusion_step;
+ if (x0 == extrusions - 1) {
+ if (path_joined) {
+ current_offset = 0;
+ next_offset = extrusion_step;
} else {
- local_dir = lookat_dir;
- }
-
- xf = xf.looking_at(xf.origin + local_dir, Vector3(0, 1, 0));
- Basis rot(Vector3(0, 0, 1), curve->interpolate_baked_tilt(ofs));
-
- xf = xf * rot; //post mult
-
- xf = path_to_this * xf;
-
- if (i > 0) {
- if (path_continuous_u) {
- u1 = u2;
- u2 += (prev_xf.origin - xf.origin).length();
- };
-
- //put triangles where they belong
- //add triangles for depth
- for (int j = 0; j < final_polygon.size(); j++) {
- int j_n = (j + 1) % final_polygon.size();
-
- Vector3 v[4] = {
- prev_xf.xform(Vector3(final_polygon[j].x, final_polygon[j].y, 0)),
- prev_xf.xform(Vector3(final_polygon[j_n].x, final_polygon[j_n].y, 0)),
- xf.xform(Vector3(final_polygon[j_n].x, final_polygon[j_n].y, 0)),
- xf.xform(Vector3(final_polygon[j].x, final_polygon[j].y, 0)),
- };
-
- Vector2 u[4] = {
- Vector2(u1, 1),
- Vector2(u1, 0),
- Vector2(u2, 0),
- Vector2(u2, 1)
- };
-
- // face 1
- facesw[face * 3 + 0] = v[0];
- facesw[face * 3 + 1] = v[1];
- facesw[face * 3 + 2] = v[2];
-
- uvsw[face * 3 + 0] = u[0];
- uvsw[face * 3 + 1] = u[1];
- uvsw[face * 3 + 2] = u[2];
-
- smoothw[face] = smooth_faces;
- invertw[face] = invert_val;
- materialsw[face] = material;
-
- face++;
-
- // face 2
- facesw[face * 3 + 0] = v[2];
- facesw[face * 3 + 1] = v[3];
- facesw[face * 3 + 2] = v[0];
-
- uvsw[face * 3 + 0] = u[2];
- uvsw[face * 3 + 1] = u[3];
- uvsw[face * 3 + 2] = u[0];
-
- smoothw[face] = smooth_faces;
- invertw[face] = invert_val;
- materialsw[face] = material;
-
- face++;
- }
- }
-
- if (i == 0 && !path_joined) {
- for (int j = 0; j < triangles.size(); j += 3) {
- for (int k = 0; k < 3; k++) {
- int src[3] = { 0, 1, 2 };
- Vector2 p = final_polygon[triangles[j + src[k]]];
- Vector3 v = Vector3(p.x, p.y, 0);
- facesw[face * 3 + k] = xf.xform(v);
- uvsw[face * 3 + k] = (p - final_polygon_min) / final_polygon_size;
- }
-
- smoothw[face] = false;
- materialsw[face] = material;
- invertw[face] = invert_val;
- face++;
- }
+ next_offset = current_offset;
}
+ }
- if (i == splits && !path_joined) {
- for (int j = 0; j < triangles.size(); j += 3) {
- for (int k = 0; k < 3; k++) {
- int src[3] = { 0, 2, 1 };
- Vector2 p = final_polygon[triangles[j + src[k]]];
- Vector3 v = Vector3(p.x, p.y, 0);
- facesw[face * 3 + k] = xf.xform(v);
- uvsw[face * 3 + k] = (p - final_polygon_min) / final_polygon_size;
- uvsw[face * 3 + k].x = 1.0 - uvsw[face * 3 + k].x; /* flip x */
- }
-
- smoothw[face] = false;
- materialsw[face] = material;
- invertw[face] = invert_val;
- face++;
- }
- }
+ Vector3 previous_point = curve->interpolate_baked(previous_offset);
+ Vector3 current_point = curve->interpolate_baked(current_offset);
+ Vector3 next_point = curve->interpolate_baked(next_offset);
+ Vector3 current_up = Vector3(0, 1, 0);
+ Vector3 direction = next_point - previous_point;
- prev_xf = xf;
+ switch (path_rotation) {
+ case PATH_ROTATION_POLYGON:
+ direction = Vector3(0, 0, -1);
+ break;
+ case PATH_ROTATION_PATH:
+ break;
+ case PATH_ROTATION_PATH_FOLLOW:
+ current_up = curve->interpolate_baked_up_vector(current_offset);
+ break;
}
+ Transform3D facing = Transform3D().looking_at(direction, current_up);
+ current_xform = base_xform.translated(current_point) * facing;
} break;
}
- if (face != face_count) {
- ERR_PRINT("Face mismatch bug! fix code");
+ double u0 = x0 * u_step;
+ double u1 = ((x0 + 1) * u_step);
+ if (mode == MODE_PATH && !path_continuous_u) {
+ u0 = 0.0;
+ u1 = 1.0;
}
- for (int i = 0; i < face_count * 3; i++) {
- if (i == 0) {
- aabb.position = facesw[i];
- } else {
- aabb.expand_to(facesw[i]);
+
+ for (int y0 = 0; y0 < shape_sides; y0++) {
+ int y1 = (y0 + 1) % shape_sides;
+ // Use the top half of the texture.
+ double v0 = (y0 * v_step) / 2;
+ double v1 = ((y0 + 1) * v_step) / 2;
+
+ Vector3 v[4] = {
+ previous_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)),
+ current_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)),
+ current_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)),
+ previous_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)),
+ };
+
+ Vector2 u[4] = {
+ Vector2(u0, v0),
+ Vector2(u1, v0),
+ Vector2(u1, v1),
+ Vector2(u0, v1),
+ };
+
+ // Face 1
+ facesw[face * 3 + 0] = v[0];
+ facesw[face * 3 + 1] = v[1];
+ facesw[face * 3 + 2] = v[2];
+
+ uvsw[face * 3 + 0] = u[0];
+ uvsw[face * 3 + 1] = u[1];
+ uvsw[face * 3 + 2] = u[2];
+
+ smoothw[face] = smooth_faces;
+ invertw[face] = invert_faces;
+ materialsw[face] = material;
+
+ face++;
+
+ // Face 2
+ facesw[face * 3 + 0] = v[2];
+ facesw[face * 3 + 1] = v[3];
+ facesw[face * 3 + 2] = v[0];
+
+ uvsw[face * 3 + 0] = u[2];
+ uvsw[face * 3 + 1] = u[3];
+ uvsw[face * 3 + 2] = u[0];
+
+ smoothw[face] = smooth_faces;
+ invertw[face] = invert_faces;
+ materialsw[face] = material;
+
+ face++;
+ }
+ }
+
+ if (end_count > 1) {
+ // Add back end face.
+ for (int face_idx = 0; face_idx < shape_face_count; face_idx++) {
+ for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) {
+ int index = shape_faces[face_idx * 3 + face_vertex_idx];
+ Point2 p = shape_polygon[index];
+ Point2 uv = (p - shape_rect.position) / shape_rect.size;
+
+ // Use the x-inverted ride side of the bottom half of the y-inverted texture.
+ uv.x = 1 - uv.x / 2;
+ uv.y = 1 - (uv.y / 2);
+
+ facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0));
+ uvsw[face * 3 + face_vertex_idx] = uv;
}
- // invert UVs on the Y-axis OpenGL = upside down
- uvsw[i].y = 1.0 - uvsw[i].y;
+ smoothw[face] = false;
+ materialsw[face] = material;
+ invertw[face] = invert_faces;
+ face++;
}
}
+ ERR_FAIL_COND_V_MSG(face != face_count, brush, "Bug: Failed to create the CSGPolygon mesh correctly.");
+
brush->build_from_faces(faces, uvs, smooth, materials, invert);
return brush;
@@ -2152,10 +1981,10 @@ CSGBrush *CSGPolygon3D::_build_brush() {
void CSGPolygon3D::_notification(int p_what) {
if (p_what == NOTIFICATION_EXIT_TREE) {
- if (path_cache) {
- path_cache->disconnect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited));
- path_cache->disconnect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed));
- path_cache = nullptr;
+ if (path) {
+ path->disconnect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited));
+ path->disconnect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed));
+ path = nullptr;
}
}
}
@@ -2180,7 +2009,7 @@ void CSGPolygon3D::_path_changed() {
}
void CSGPolygon3D::_path_exited() {
- path_cache = nullptr;
+ path = nullptr;
}
void CSGPolygon3D::_bind_methods() {
@@ -2202,10 +2031,10 @@ void CSGPolygon3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_path_node", "path"), &CSGPolygon3D::set_path_node);
ClassDB::bind_method(D_METHOD("get_path_node"), &CSGPolygon3D::get_path_node);
- ClassDB::bind_method(D_METHOD("set_path_interval", "distance"), &CSGPolygon3D::set_path_interval);
+ ClassDB::bind_method(D_METHOD("set_path_interval", "interval"), &CSGPolygon3D::set_path_interval);
ClassDB::bind_method(D_METHOD("get_path_interval"), &CSGPolygon3D::get_path_interval);
- ClassDB::bind_method(D_METHOD("set_path_rotation", "mode"), &CSGPolygon3D::set_path_rotation);
+ ClassDB::bind_method(D_METHOD("set_path_rotation", "path_rotation"), &CSGPolygon3D::set_path_rotation);
ClassDB::bind_method(D_METHOD("get_path_rotation"), &CSGPolygon3D::get_path_rotation);
ClassDB::bind_method(D_METHOD("set_path_local", "enable"), &CSGPolygon3D::set_path_local);
@@ -2228,11 +2057,11 @@ void CSGPolygon3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Depth,Spin,Path"), "set_mode", "get_mode");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_depth", "get_depth");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_RANGE, "0.01,100.0,0.01,or_greater,exp"), "set_depth", "get_depth");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spin_degrees", PROPERTY_HINT_RANGE, "1,360,0.1"), "set_spin_degrees", "get_spin_degrees");
ADD_PROPERTY(PropertyInfo(Variant::INT, "spin_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_spin_sides", "get_spin_sides");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path3D"), "set_path_node", "get_path_node");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_path_interval", "get_path_interval");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_RANGE, "0.1,1.0,0.05,exp"), "set_path_interval", "get_path_interval");
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_rotation", PROPERTY_HINT_ENUM, "Polygon,Path,PathFollow"), "set_path_rotation", "get_path_rotation");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_local"), "set_path_local", "is_path_local");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_continuous_u"), "set_path_continuous_u", "is_path_continuous_u");
@@ -2301,7 +2130,7 @@ float CSGPolygon3D::get_spin_degrees() const {
return spin_degrees;
}
-void CSGPolygon3D::set_spin_sides(const int p_spin_sides) {
+void CSGPolygon3D::set_spin_sides(int p_spin_sides) {
ERR_FAIL_COND(p_spin_sides < 3);
spin_sides = p_spin_sides;
_make_dirty();
@@ -2323,7 +2152,7 @@ NodePath CSGPolygon3D::get_path_node() const {
}
void CSGPolygon3D::set_path_interval(float p_interval) {
- ERR_FAIL_COND_MSG(p_interval < 0.001, "Path interval cannot be smaller than 0.001.");
+ ERR_FAIL_COND_MSG(p_interval <= 0 || p_interval > 1, "Path interval must be greater than 0 and less than or equal to 1.0.");
path_interval = p_interval;
_make_dirty();
update_gizmos();
@@ -2400,10 +2229,10 @@ CSGPolygon3D::CSGPolygon3D() {
spin_degrees = 360;
spin_sides = 8;
smooth_faces = false;
- path_interval = 1;
- path_rotation = PATH_ROTATION_PATH;
+ path_interval = 1.0;
+ path_rotation = PATH_ROTATION_PATH_FOLLOW;
path_local = false;
- path_continuous_u = false;
+ path_continuous_u = true;
path_joined = false;
- path_cache = nullptr;
+ path = nullptr;
}
diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h
index de7de09f00..5cf371665e 100644
--- a/modules/csg/csg_shape.h
+++ b/modules/csg/csg_shape.h
@@ -34,6 +34,7 @@
#define CSGJS_HEADER_ONLY
#include "csg.h"
+#include "scene/3d/path_3d.h"
#include "scene/3d/visual_instance_3d.h"
#include "scene/resources/concave_polygon_shape_3d.h"
#include "thirdparty/misc/mikktspace.h"
@@ -83,14 +84,14 @@ private:
Vector<Vector3> vertices;
Vector<Vector3> normals;
Vector<Vector2> uvs;
- Vector<float> tans;
+ Vector<real_t> tans;
Ref<Material> material;
int last_added = 0;
Vector3 *verticesw = nullptr;
Vector3 *normalsw = nullptr;
Vector2 *uvsw = nullptr;
- float *tansw = nullptr;
+ real_t *tansw = nullptr;
};
//mikktspace callbacks
@@ -136,11 +137,11 @@ public:
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
+ void set_collision_layer_value(int p_layer_number, bool p_value);
+ bool get_collision_layer_value(int p_layer_number) const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void set_snap(float p_snap);
float get_snap() const;
@@ -168,10 +169,8 @@ public:
class CSGPrimitive3D : public CSGShape3D {
GDCLASS(CSGPrimitive3D, CSGShape3D);
-private:
- bool invert_faces;
-
protected:
+ bool invert_faces;
CSGBrush *_create_brush_from_arrays(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uv, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials);
static void _bind_methods();
@@ -361,7 +360,7 @@ private:
PathRotation path_rotation;
bool path_local;
- Node *path_cache;
+ Path3D *path;
bool smooth_faces;
bool path_continuous_u;
diff --git a/modules/csg/doc_classes/CSGPolygon3D.xml b/modules/csg/doc_classes/CSGPolygon3D.xml
index 4f29786779..5309cde956 100644
--- a/modules/csg/doc_classes/CSGPolygon3D.xml
+++ b/modules/csg/doc_classes/CSGPolygon3D.xml
@@ -4,7 +4,7 @@
Extrudes a 2D polygon shape to create a 3D mesh.
</brief_description>
<description>
- This node takes a 2D polygon shape and extrudes it to create a 3D mesh.
+ An array of 2D points is extruded to quickly and easily create a variety of 3D meshes.
</description>
<tutorials>
</tutorials>
@@ -12,63 +12,65 @@
</methods>
<members>
<member name="depth" type="float" setter="set_depth" getter="get_depth" default="1.0">
- Extrusion depth when [member mode] is [constant MODE_DEPTH].
+ When [member mode] is [constant MODE_DEPTH], the depth of the extrusion.
</member>
<member name="material" type="Material" setter="set_material" getter="get_material">
- Material to use for the resulting mesh.
+ Material to use for the resulting mesh. The UV maps the top half of the material to the extruded shape (U along the length of the extrusions and V around the outline of the [member polygon]), the bottom-left quarter to the front end face, and the bottom-right quarter to the back end face.
</member>
<member name="mode" type="int" setter="set_mode" getter="get_mode" enum="CSGPolygon3D.Mode" default="0">
- Extrusion mode.
+ The [member mode] used to extrude the [member polygon].
</member>
<member name="path_continuous_u" type="bool" setter="set_path_continuous_u" getter="is_path_continuous_u">
- If [code]true[/code] the u component of our uv will continuously increase in unison with the distance traveled along our path when [member mode] is [constant MODE_PATH].
+ When [member mode] is [constant MODE_PATH], by default, the top half of the [member material] is stretched along the entire length of the extruded shape. If [code]false[/code] the top half of the material is repeated every step of the extrusion.
</member>
<member name="path_interval" type="float" setter="set_path_interval" getter="get_path_interval">
- Interval at which a new extrusion slice is added along the path when [member mode] is [constant MODE_PATH].
+ When [member mode] is [constant MODE_PATH], the path interval or ratio of path points to extrusions.
</member>
<member name="path_joined" type="bool" setter="set_path_joined" getter="is_path_joined">
- If [code]true[/code] the start and end of our path are joined together ensuring there is no seam when [member mode] is [constant MODE_PATH].
+ When [member mode] is [constant MODE_PATH], if [code]true[/code] the ends of the path are joined, by adding an extrusion between the last and first points of the path.
</member>
<member name="path_local" type="bool" setter="set_path_local" getter="is_path_local">
- If [code]false[/code] we extrude centered on our path, if [code]true[/code] we extrude in relation to the position of our CSGPolygon3D when [member mode] is [constant MODE_PATH].
+ When [member mode] is [constant MODE_PATH], if [code]true[/code] the [Transform3D] of the [CSGPolygon3D] is used as the starting point for the extrusions, not the [Transform3D] of the [member path_node].
</member>
<member name="path_node" type="NodePath" setter="set_path_node" getter="get_path_node">
- The [Shape3D] object containing the path along which we extrude when [member mode] is [constant MODE_PATH].
+ When [member mode] is [constant MODE_PATH], the location of the [Path3D] object used to extrude the [member polygon].
</member>
<member name="path_rotation" type="int" setter="set_path_rotation" getter="get_path_rotation" enum="CSGPolygon3D.PathRotation">
- The method by which each slice is rotated along the path when [member mode] is [constant MODE_PATH].
+ When [member mode] is [constant MODE_PATH], the [enum PathRotation] method used to rotate the [member polygon] as it is extruded.
</member>
<member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array(0, 0, 0, 1, 1, 1, 1, 0)">
- Point array that defines the shape that we'll extrude.
+ The point array that defines the 2D polygon that is extruded.
</member>
<member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="false">
- Generates smooth normals so smooth shading is applied to our mesh.
+ If [code]true[/code], applies smooth shading to the extrusions.
</member>
<member name="spin_degrees" type="float" setter="set_spin_degrees" getter="get_spin_degrees">
- Degrees to rotate our extrusion for each slice when [member mode] is [constant MODE_SPIN].
+ When [member mode] is [constant MODE_SPIN], the total number of degrees the [member polygon] is rotated when extruding.
</member>
<member name="spin_sides" type="int" setter="set_spin_sides" getter="get_spin_sides">
- Number of extrusion when [member mode] is [constant MODE_SPIN].
+ When [member mode] is [constant MODE_SPIN], the number of extrusions made.
</member>
</members>
<constants>
<constant name="MODE_DEPTH" value="0" enum="Mode">
- Shape3D is extruded to [member depth].
+ The [member polygon] shape is extruded along the negative Z axis.
</constant>
<constant name="MODE_SPIN" value="1" enum="Mode">
- Shape3D is extruded by rotating it around an axis.
+ The [member polygon] shape is extruded by rotating it around the Y axis.
</constant>
<constant name="MODE_PATH" value="2" enum="Mode">
- Shape3D is extruded along a path set by a [Shape3D] set in [member path_node].
+ The [member polygon] shape is extruded along the [Path3D] specified in [member path_node].
</constant>
<constant name="PATH_ROTATION_POLYGON" value="0" enum="PathRotation">
- Slice is not rotated.
+ The [member polygon] shape is not rotated.
+ [b]Note:[/b] Requires the path Z coordinates to continually decrease to ensure viable shapes.
</constant>
<constant name="PATH_ROTATION_PATH" value="1" enum="PathRotation">
- Slice is rotated around the up vector of the path.
+ The [member polygon] shape is rotated along the path, but it is not rotated around the path axis.
+ [b]Note:[/b] Requires the path Z coordinates to continually decrease to ensure viable shapes.
</constant>
<constant name="PATH_ROTATION_PATH_FOLLOW" value="2" enum="PathRotation">
- Slice is rotate to match the path exactly.
+ The [member polygon] shape follows the path and its rotations around the path axis.
</constant>
</constants>
</class>
diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml
index f42ce8c379..446269f3f0 100644
--- a/modules/csg/doc_classes/CSGShape3D.xml
+++ b/modules/csg/doc_classes/CSGShape3D.xml
@@ -9,18 +9,18 @@
<tutorials>
</tutorials>
<methods>
- <method name="get_collision_layer_bit" qualifiers="const">
+ <method name="get_collision_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns an individual bit on the collision mask.
+ Returns whether or not the specified layer of the [member collision_layer] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="get_collision_mask_bit" qualifiers="const">
+ <method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns an individual bit on the collision mask.
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="get_meshes" qualifiers="const">
@@ -35,20 +35,20 @@
Returns [code]true[/code] if this is a root shape and is thus the object that is rendered.
</description>
</method>
- <method name="set_collision_layer_bit">
+ <method name="set_collision_layer_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- Sets individual bits on the layer mask. Use this if you only need to change one layer's value.
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_layer], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="set_collision_mask_bit">
+ <method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- Sets individual bits on the collision mask. Use this if you only need to change one layer's value.
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
</methods>
diff --git a/modules/denoise/lightmap_denoiser.cpp b/modules/denoise/lightmap_denoiser.cpp
index 003bc832b0..71dcc1d75f 100644
--- a/modules/denoise/lightmap_denoiser.cpp
+++ b/modules/denoise/lightmap_denoiser.cpp
@@ -31,6 +31,8 @@
#include "lightmap_denoiser.h"
#include "denoise_wrapper.h"
+#include "core/io/image.h"
+
LightmapDenoiser *LightmapDenoiserOIDN::create_oidn_denoiser() {
return memnew(LightmapDenoiserOIDN);
}
diff --git a/modules/enet/doc_classes/ENetConnection.xml b/modules/enet/doc_classes/ENetConnection.xml
index c2a85ffdf8..01ac64f74c 100644
--- a/modules/enet/doc_classes/ENetConnection.xml
+++ b/modules/enet/doc_classes/ENetConnection.xml
@@ -155,7 +155,7 @@
ENet's built-in range encoding. Works well on small packets, but is not the most efficient algorithm on packets larger than 4 KB.
</constant>
<constant name="COMPRESS_FASTLZ" value="2" enum="CompressionMode">
- [url=http://fastlz.org/]FastLZ[/url] compression. This option uses less CPU resources compared to [constant COMPRESS_ZLIB], at the expense of using more bandwidth.
+ [url=https://fastlz.org/]FastLZ[/url] compression. This option uses less CPU resources compared to [constant COMPRESS_ZLIB], at the expense of using more bandwidth.
</constant>
<constant name="COMPRESS_ZLIB" value="3" enum="CompressionMode">
[url=https://www.zlib.net/]Zlib[/url] compression. This option uses less bandwidth compared to [constant COMPRESS_FASTLZ], at the expense of using more CPU resources.
diff --git a/modules/enet/enet_multiplayer_peer.cpp b/modules/enet/enet_multiplayer_peer.cpp
index aa0e09bcde..38ca38385c 100644
--- a/modules/enet/enet_multiplayer_peer.cpp
+++ b/modules/enet/enet_multiplayer_peer.cpp
@@ -242,8 +242,8 @@ bool ENetMultiplayerPeer::_poll_client() {
}
switch (ret) {
case ENetConnection::EVENT_CONNECT: {
- emit_signal(SNAME("peer_connected"), 1);
connection_status = CONNECTION_CONNECTED;
+ emit_signal(SNAME("peer_connected"), 1);
emit_signal(SNAME("connection_succeeded"));
return false;
}
diff --git a/modules/fbx/data/fbx_material.cpp b/modules/fbx/data/fbx_material.cpp
index fb6c67f7b9..86baec4244 100644
--- a/modules/fbx/data/fbx_material.cpp
+++ b/modules/fbx/data/fbx_material.cpp
@@ -31,7 +31,7 @@
#include "fbx_material.h"
// FIXME: Shouldn't depend on core_bind.h! Use DirAccessRef like the rest of
-// the engine instead of _Directory.
+// the engine instead of core_bind::Directory.
#include "core/core_bind.h"
#include "scene/resources/material.h"
#include "scene/resources/texture.h"
@@ -55,7 +55,7 @@ void FBXMaterial::add_search_string(String p_filename, String p_current_director
}
String find_file(const String &p_base, const String &p_file_to_find) {
- _Directory dir;
+ core_bind::Directory dir;
dir.open(p_base);
dir.list_dir_begin();
@@ -84,7 +84,7 @@ String find_file(const String &p_base, const String &p_file_to_find) {
// fbx will not give us good path information and let's not regex them to fix them
// no relative paths are in fbx generally they have a rel field but it's populated incorrectly by the SDK.
String FBXMaterial::find_texture_path_by_filename(const String p_filename, const String p_current_directory) {
- _Directory dir;
+ core_bind::Directory dir;
Vector<String> paths;
add_search_string(p_filename, p_current_directory, "", paths);
add_search_string(p_filename, p_current_directory, "texture", paths);
diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp
index 8b4b1e08b3..dcea476275 100644
--- a/modules/fbx/data/fbx_mesh_data.cpp
+++ b/modules/fbx/data/fbx_mesh_data.cpp
@@ -433,7 +433,7 @@ void FBXMeshData::sanitize_vertex_weights(const ImportState &state) {
{
// Sort
- real_t *weights_ptr = vm->weights.ptrw();
+ float *weights_ptr = vm->weights.ptrw();
int *bones_ptr = vm->bones.ptrw();
for (int i = 0; i < vm->weights.size(); i += 1) {
for (int x = i + 1; x < vm->weights.size(); x += 1) {
@@ -449,7 +449,7 @@ void FBXMeshData::sanitize_vertex_weights(const ImportState &state) {
// Resize
vm->weights.resize(max_vertex_influence_count);
vm->bones.resize(max_vertex_influence_count);
- real_t *weights_ptr = vm->weights.ptrw();
+ float *weights_ptr = vm->weights.ptrw();
int *bones_ptr = vm->bones.ptrw();
for (int i = initial_size; i < max_vertex_influence_count; i += 1) {
weights_ptr[i] = 0.0;
diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h
index 7486c5c59c..24db4a5469 100644
--- a/modules/fbx/data/fbx_mesh_data.h
+++ b/modules/fbx/data/fbx_mesh_data.h
@@ -64,7 +64,7 @@ struct SurfaceData {
};
struct VertexWeightMapping {
- Vector<real_t> weights;
+ Vector<float> weights;
Vector<int> bones;
// This extra vector is used because the bone id is computed in a second step.
// TODO Get rid of this extra step is a good idea.
diff --git a/modules/fbx/fbx_parser/FBXParser.cpp b/modules/fbx/fbx_parser/FBXParser.cpp
index a92b23f4ee..d9ef025a16 100644
--- a/modules/fbx/fbx_parser/FBXParser.cpp
+++ b/modules/fbx/fbx_parser/FBXParser.cpp
@@ -575,7 +575,7 @@ void ReadBinaryDataArray(char type, uint32_t count, const char *&data, const cha
std::copy(data, end, buff.begin());
} else if (encmode == 1) {
// zlib/deflate, next comes ZIP head (0x78 0x01)
- // see http://www.ietf.org/rfc/rfc1950.txt
+ // see https://www.ietf.org/rfc/rfc1950.txt
z_stream zstream;
zstream.opaque = Z_NULL;
diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub
index fc2535a6ca..476cb9cf2a 100644
--- a/modules/freetype/SCsub
+++ b/modules/freetype/SCsub
@@ -80,6 +80,7 @@ if env["builtin_freetype"]:
# Forcibly undefine this macro so SIMD is not used in this file,
# since currently unsupported in WASM
tmp_env = env_freetype.Clone()
+ tmp_env.disable_warnings()
tmp_env.Append(CPPFLAGS=["-U__OPTIMIZE__"])
sfnt = tmp_env.Object(sfnt)
thirdparty_sources += [sfnt]
diff --git a/modules/gdnative/gdnative/packed_arrays.cpp b/modules/gdnative/gdnative/packed_arrays.cpp
index 396109e576..f03c94aeb8 100644
--- a/modules/gdnative/gdnative/packed_arrays.cpp
+++ b/modules/gdnative/gdnative/packed_arrays.cpp
@@ -51,8 +51,6 @@ static_assert(sizeof(godot_packed_color_array) == sizeof(PackedColorArray), "Pac
extern "C" {
#endif
-#define memnew_placement_custom(m_placement, m_class, m_constr) _post_initialize(new (m_placement, sizeof(m_class), "") m_constr)
-
// byte
void GDAPI godot_packed_byte_array_new(godot_packed_byte_array *p_self) {
diff --git a/modules/gdnative/gdnative/variant.cpp b/modules/gdnative/gdnative/variant.cpp
index 1d75ea206c..ec9aaa0a55 100644
--- a/modules/gdnative/gdnative/variant.cpp
+++ b/modules/gdnative/gdnative/variant.cpp
@@ -48,8 +48,6 @@ static_assert(sizeof(godot_variant) == sizeof(Variant), "Variant size mismatch")
#pragma GCC optimize("-O0")
#endif
-#define memnew_placement_custom(m_placement, m_class, m_constr) _post_initialize(new (m_placement, sizeof(m_class), "") m_constr)
-
#if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) && \
(__GNUC__ == 6 || (__GNUC__ == 7 && __GNUC_MINOR__ < 4) || (__GNUC__ == 8 && __GNUC_MINOR__ < 1))
#pragma GCC pop_options
@@ -70,131 +68,131 @@ void GDAPI godot_variant_new_nil(godot_variant *r_dest) {
void GDAPI godot_variant_new_bool(godot_variant *r_dest, const godot_bool p_b) {
Variant *dest = (Variant *)r_dest;
- memnew_placement_custom(dest, Variant, Variant(p_b));
+ memnew_placement(dest, Variant(p_b));
}
void GDAPI godot_variant_new_int(godot_variant *r_dest, const godot_int p_i) {
Variant *dest = (Variant *)r_dest;
- memnew_placement_custom(dest, Variant, Variant(p_i));
+ memnew_placement(dest, Variant(p_i));
}
void GDAPI godot_variant_new_float(godot_variant *r_dest, const godot_float p_r) {
Variant *dest = (Variant *)r_dest;
- memnew_placement_custom(dest, Variant, Variant(p_r));
+ memnew_placement(dest, Variant(p_r));
}
void GDAPI godot_variant_new_string(godot_variant *r_dest, const godot_string *p_s) {
Variant *dest = (Variant *)r_dest;
const String *s = (const String *)p_s;
- memnew_placement_custom(dest, Variant, Variant(*s));
+ memnew_placement(dest, Variant(*s));
}
void GDAPI godot_variant_new_string_name(godot_variant *r_dest, const godot_string_name *p_s) {
Variant *dest = (Variant *)r_dest;
const StringName *s = (const StringName *)p_s;
- memnew_placement_custom(dest, Variant, Variant(*s));
+ memnew_placement(dest, Variant(*s));
}
void GDAPI godot_variant_new_vector2(godot_variant *r_dest, const godot_vector2 *p_v2) {
Variant *dest = (Variant *)r_dest;
const Vector2 *v2 = (const Vector2 *)p_v2;
- memnew_placement_custom(dest, Variant, Variant(*v2));
+ memnew_placement(dest, Variant(*v2));
}
void GDAPI godot_variant_new_vector2i(godot_variant *r_dest, const godot_vector2i *p_v2) {
Variant *dest = (Variant *)r_dest;
const Vector2i *v2 = (const Vector2i *)p_v2;
- memnew_placement_custom(dest, Variant, Variant(*v2));
+ memnew_placement(dest, Variant(*v2));
}
void GDAPI godot_variant_new_rect2(godot_variant *r_dest, const godot_rect2 *p_rect2) {
Variant *dest = (Variant *)r_dest;
const Rect2 *rect2 = (const Rect2 *)p_rect2;
- memnew_placement_custom(dest, Variant, Variant(*rect2));
+ memnew_placement(dest, Variant(*rect2));
}
void GDAPI godot_variant_new_rect2i(godot_variant *r_dest, const godot_rect2i *p_rect2) {
Variant *dest = (Variant *)r_dest;
const Rect2i *rect2 = (const Rect2i *)p_rect2;
- memnew_placement_custom(dest, Variant, Variant(*rect2));
+ memnew_placement(dest, Variant(*rect2));
}
void GDAPI godot_variant_new_vector3(godot_variant *r_dest, const godot_vector3 *p_v3) {
Variant *dest = (Variant *)r_dest;
const Vector3 *v3 = (const Vector3 *)p_v3;
- memnew_placement_custom(dest, Variant, Variant(*v3));
+ memnew_placement(dest, Variant(*v3));
}
void GDAPI godot_variant_new_vector3i(godot_variant *r_dest, const godot_vector3i *p_v3) {
Variant *dest = (Variant *)r_dest;
const Vector3i *v3 = (const Vector3i *)p_v3;
- memnew_placement_custom(dest, Variant, Variant(*v3));
+ memnew_placement(dest, Variant(*v3));
}
void GDAPI godot_variant_new_transform2d(godot_variant *r_dest, const godot_transform2d *p_t2d) {
Variant *dest = (Variant *)r_dest;
const Transform2D *t2d = (const Transform2D *)p_t2d;
- memnew_placement_custom(dest, Variant, Variant(*t2d));
+ memnew_placement(dest, Variant(*t2d));
}
void GDAPI godot_variant_new_plane(godot_variant *r_dest, const godot_plane *p_plane) {
Variant *dest = (Variant *)r_dest;
const Plane *plane = (const Plane *)p_plane;
- memnew_placement_custom(dest, Variant, Variant(*plane));
+ memnew_placement(dest, Variant(*plane));
}
void GDAPI godot_variant_new_quaternion(godot_variant *r_dest, const godot_quaternion *p_quaternion) {
Variant *dest = (Variant *)r_dest;
const Quaternion *quaternion = (const Quaternion *)p_quaternion;
- memnew_placement_custom(dest, Variant, Variant(*quaternion));
+ memnew_placement(dest, Variant(*quaternion));
}
void GDAPI godot_variant_new_aabb(godot_variant *r_dest, const godot_aabb *p_aabb) {
Variant *dest = (Variant *)r_dest;
const AABB *aabb = (const AABB *)p_aabb;
- memnew_placement_custom(dest, Variant, Variant(*aabb));
+ memnew_placement(dest, Variant(*aabb));
}
void GDAPI godot_variant_new_basis(godot_variant *r_dest, const godot_basis *p_basis) {
Variant *dest = (Variant *)r_dest;
const Basis *basis = (const Basis *)p_basis;
- memnew_placement_custom(dest, Variant, Variant(*basis));
+ memnew_placement(dest, Variant(*basis));
}
void GDAPI godot_variant_new_transform3d(godot_variant *r_dest, const godot_transform3d *p_trans) {
Variant *dest = (Variant *)r_dest;
const Transform3D *trans = (const Transform3D *)p_trans;
- memnew_placement_custom(dest, Variant, Variant(*trans));
+ memnew_placement(dest, Variant(*trans));
}
void GDAPI godot_variant_new_color(godot_variant *r_dest, const godot_color *p_color) {
Variant *dest = (Variant *)r_dest;
const Color *color = (const Color *)p_color;
- memnew_placement_custom(dest, Variant, Variant(*color));
+ memnew_placement(dest, Variant(*color));
}
void GDAPI godot_variant_new_node_path(godot_variant *r_dest, const godot_node_path *p_np) {
Variant *dest = (Variant *)r_dest;
const NodePath *np = (const NodePath *)p_np;
- memnew_placement_custom(dest, Variant, Variant(*np));
+ memnew_placement(dest, Variant(*np));
}
void GDAPI godot_variant_new_rid(godot_variant *r_dest, const godot_rid *p_rid) {
Variant *dest = (Variant *)r_dest;
const RID *rid = (const RID *)p_rid;
- memnew_placement_custom(dest, Variant, Variant(*rid));
+ memnew_placement(dest, Variant(*rid));
}
void GDAPI godot_variant_new_callable(godot_variant *r_dest, const godot_callable *p_cb) {
Variant *dest = (Variant *)r_dest;
const Callable *cb = (const Callable *)p_cb;
- memnew_placement_custom(dest, Variant, Variant(*cb));
+ memnew_placement(dest, Variant(*cb));
}
void GDAPI godot_variant_new_signal(godot_variant *r_dest, const godot_signal *p_signal) {
Variant *dest = (Variant *)r_dest;
const Signal *signal = (const Signal *)p_signal;
- memnew_placement_custom(dest, Variant, Variant(*signal));
+ memnew_placement(dest, Variant(*signal));
}
void GDAPI godot_variant_new_object(godot_variant *r_dest, const godot_object *p_obj) {
@@ -206,81 +204,81 @@ void GDAPI godot_variant_new_object(godot_variant *r_dest, const godot_object *p
ref = REF(ref_counted);
}
if (!ref.is_null()) {
- memnew_placement_custom(dest, Variant, Variant(ref));
+ memnew_placement(dest, Variant(ref));
} else {
#if defined(DEBUG_METHODS_ENABLED)
if (ref_counted) {
ERR_PRINT("RefCounted object has 0 refcount in godot_variant_new_object - you lost it somewhere.");
}
#endif
- memnew_placement_custom(dest, Variant, Variant(obj));
+ memnew_placement(dest, Variant(obj));
}
}
void GDAPI godot_variant_new_dictionary(godot_variant *r_dest, const godot_dictionary *p_dict) {
Variant *dest = (Variant *)r_dest;
const Dictionary *dict = (const Dictionary *)p_dict;
- memnew_placement_custom(dest, Variant, Variant(*dict));
+ memnew_placement(dest, Variant(*dict));
}
void GDAPI godot_variant_new_array(godot_variant *r_dest, const godot_array *p_arr) {
Variant *dest = (Variant *)r_dest;
const Array *arr = (const Array *)p_arr;
- memnew_placement_custom(dest, Variant, Variant(*arr));
+ memnew_placement(dest, Variant(*arr));
}
void GDAPI godot_variant_new_packed_byte_array(godot_variant *r_dest, const godot_packed_byte_array *p_pba) {
Variant *dest = (Variant *)r_dest;
const PackedByteArray *pba = (const PackedByteArray *)p_pba;
- memnew_placement_custom(dest, Variant, Variant(*pba));
+ memnew_placement(dest, Variant(*pba));
}
void GDAPI godot_variant_new_packed_int32_array(godot_variant *r_dest, const godot_packed_int32_array *p_pia) {
Variant *dest = (Variant *)r_dest;
const PackedInt32Array *pia = (const PackedInt32Array *)p_pia;
- memnew_placement_custom(dest, Variant, Variant(*pia));
+ memnew_placement(dest, Variant(*pia));
}
void GDAPI godot_variant_new_packed_int64_array(godot_variant *r_dest, const godot_packed_int64_array *p_pia) {
Variant *dest = (Variant *)r_dest;
const PackedInt64Array *pia = (const PackedInt64Array *)p_pia;
- memnew_placement_custom(dest, Variant, Variant(*pia));
+ memnew_placement(dest, Variant(*pia));
}
void GDAPI godot_variant_new_packed_float32_array(godot_variant *r_dest, const godot_packed_float32_array *p_pra) {
Variant *dest = (Variant *)r_dest;
const PackedFloat32Array *pra = (const PackedFloat32Array *)p_pra;
- memnew_placement_custom(dest, Variant, Variant(*pra));
+ memnew_placement(dest, Variant(*pra));
}
void GDAPI godot_variant_new_packed_float64_array(godot_variant *r_dest, const godot_packed_float64_array *p_pra) {
Variant *dest = (Variant *)r_dest;
const PackedFloat64Array *pra = (const PackedFloat64Array *)p_pra;
- memnew_placement_custom(dest, Variant, Variant(*pra));
+ memnew_placement(dest, Variant(*pra));
}
void GDAPI godot_variant_new_packed_string_array(godot_variant *r_dest, const godot_packed_string_array *p_psa) {
Variant *dest = (Variant *)r_dest;
const PackedStringArray *psa = (const PackedStringArray *)p_psa;
- memnew_placement_custom(dest, Variant, Variant(*psa));
+ memnew_placement(dest, Variant(*psa));
}
void GDAPI godot_variant_new_packed_vector2_array(godot_variant *r_dest, const godot_packed_vector2_array *p_pv2a) {
Variant *dest = (Variant *)r_dest;
const PackedVector2Array *pv2a = (const PackedVector2Array *)p_pv2a;
- memnew_placement_custom(dest, Variant, Variant(*pv2a));
+ memnew_placement(dest, Variant(*pv2a));
}
void GDAPI godot_variant_new_packed_vector3_array(godot_variant *r_dest, const godot_packed_vector3_array *p_pv3a) {
Variant *dest = (Variant *)r_dest;
const PackedVector3Array *pv3a = (const PackedVector3Array *)p_pv3a;
- memnew_placement_custom(dest, Variant, Variant(*pv3a));
+ memnew_placement(dest, Variant(*pv3a));
}
void GDAPI godot_variant_new_packed_color_array(godot_variant *r_dest, const godot_packed_color_array *p_pca) {
Variant *dest = (Variant *)r_dest;
const PackedColorArray *pca = (const PackedColorArray *)p_pca;
- memnew_placement_custom(dest, Variant, Variant(*pca));
+ memnew_placement(dest, Variant(*pca));
}
godot_bool GDAPI godot_variant_as_bool(const godot_variant *p_self) {
@@ -568,7 +566,7 @@ void GDAPI godot_variant_call(godot_variant *p_self, const godot_string_name *p_
Variant ret;
Callable::CallError error;
self->call(*method, args, p_argcount, ret, error);
- memnew_placement_custom(r_return, Variant, Variant(ret));
+ memnew_placement(r_return, Variant(ret));
if (r_error) {
r_error->error = (godot_variant_call_error_error)error.error;
@@ -584,7 +582,7 @@ void GDAPI godot_variant_call_with_cstring(godot_variant *p_self, const char *p_
Variant ret;
Callable::CallError error;
self->call(method, args, p_argcount, ret, error);
- memnew_placement_custom(r_return, Variant, Variant(ret));
+ memnew_placement(r_return, Variant(ret));
if (r_error) {
r_error->error = (godot_variant_call_error_error)error.error;
@@ -600,7 +598,7 @@ void GDAPI godot_variant_call_static(godot_variant_type p_type, const godot_stri
Variant ret;
Callable::CallError error;
Variant::call_static(type, *method, args, p_argcount, ret, error);
- memnew_placement_custom(r_return, Variant, Variant(ret));
+ memnew_placement(r_return, Variant(ret));
if (r_error) {
r_error->error = (godot_variant_call_error_error)error.error;
@@ -616,7 +614,7 @@ void GDAPI godot_variant_call_static_with_cstring(godot_variant_type p_type, con
Variant ret;
Callable::CallError error;
Variant::call_static(type, method, args, p_argcount, ret, error);
- memnew_placement_custom(r_return, Variant, Variant(ret));
+ memnew_placement(r_return, Variant(ret));
if (r_error) {
r_error->error = (godot_variant_call_error_error)error.error;
@@ -679,7 +677,7 @@ godot_variant GDAPI godot_variant_get(const godot_variant *p_self, const godot_v
ret = self->get(*key, r_valid);
godot_variant result;
- memnew_placement_custom(&result, Variant, Variant(ret));
+ memnew_placement(&result, Variant(ret));
return result;
}
@@ -690,7 +688,7 @@ godot_variant GDAPI godot_variant_get_named(const godot_variant *p_self, const g
ret = self->get_named(*key, *r_valid);
godot_variant result;
- memnew_placement_custom(&result, Variant, Variant(ret));
+ memnew_placement(&result, Variant(ret));
return result;
}
@@ -701,7 +699,7 @@ godot_variant GDAPI godot_variant_get_named_with_cstring(const godot_variant *p_
ret = self->get_named(*key, *r_valid);
godot_variant result;
- memnew_placement_custom(&result, Variant, Variant(ret));
+ memnew_placement(&result, Variant(ret));
return result;
}
@@ -712,7 +710,7 @@ godot_variant GDAPI godot_variant_get_keyed(const godot_variant *p_self, const g
ret = self->get_keyed(*key, *r_valid);
godot_variant result;
- memnew_placement_custom(&result, Variant, Variant(ret));
+ memnew_placement(&result, Variant(ret));
return result;
}
@@ -722,7 +720,7 @@ godot_variant GDAPI godot_variant_get_indexed(const godot_variant *p_self, godot
ret = self->get_indexed(p_index, *r_valid, *r_oob);
godot_variant result;
- memnew_placement_custom(&result, Variant, Variant(ret));
+ memnew_placement(&result, Variant(ret));
return result;
}
@@ -747,7 +745,7 @@ godot_variant GDAPI godot_variant_iter_get(const godot_variant *p_self, godot_va
Variant result = self->iter_next(*iter, *r_valid);
godot_variant ret;
- memnew_placement_custom(&ret, Variant, Variant(result));
+ memnew_placement(&ret, Variant(result));
return ret;
}
@@ -781,7 +779,7 @@ godot_variant GDAPI godot_variant_duplicate(const godot_variant *p_self, godot_b
const Variant *self = (const Variant *)p_self;
Variant result = self->duplicate(p_deep);
godot_variant ret;
- memnew_placement_custom(&ret, Variant, Variant(result));
+ memnew_placement(&ret, Variant(result));
return ret;
}
@@ -789,7 +787,7 @@ godot_string GDAPI godot_variant_stringify(const godot_variant *p_self) {
const Variant *self = (const Variant *)p_self;
String result = *self;
godot_string ret;
- memnew_placement_custom(&ret, String, String(result));
+ memnew_placement(&ret, String(result));
return ret;
}
@@ -811,7 +809,7 @@ godot_variant_type GDAPI godot_variant_get_operator_return_type(godot_variant_op
godot_string GDAPI godot_variant_get_operator_name(godot_variant_operator p_operator) {
String op_name = Variant::get_operator_name((Variant::Operator)p_operator);
godot_string ret;
- memnew_placement_custom(&ret, String, String(op_name));
+ memnew_placement(&ret, String(op_name));
return ret;
}
@@ -916,7 +914,7 @@ void GDAPI godot_variant_get_builtin_method_list(godot_variant_type p_type, godo
Variant::get_builtin_method_list((Variant::Type)p_type, &list);
int i = 0;
for (const StringName &E : list) {
- memnew_placement_custom(&r_list[i], StringName, StringName(E));
+ memnew_placement(&r_list[i], StringName(E));
}
}
@@ -971,7 +969,7 @@ void GDAPI godot_variant_get_member_list(godot_variant_type p_type, godot_string
Variant::get_member_list((Variant::Type)p_type, &members);
int i = 0;
for (const StringName &E : members) {
- memnew_placement_custom(&r_list[i++], StringName, StringName(E));
+ memnew_placement(&r_list[i++], StringName(E));
}
}
@@ -1076,7 +1074,7 @@ void GDAPI godot_variant_get_constants_list(godot_variant_type p_type, godot_str
int i = 0;
Variant::get_constants_for_type((Variant::Type)p_type, &constants);
for (const StringName &E : constants) {
- memnew_placement_custom(&r_list[i++], StringName, StringName(E));
+ memnew_placement(&r_list[i++], StringName(E));
}
}
@@ -1091,14 +1089,14 @@ bool GDAPI godot_variant_has_constant_with_cstring(godot_variant_type p_type, co
godot_variant GDAPI godot_variant_get_constant_value(godot_variant_type p_type, const godot_string_name *p_constant) {
Variant constant = Variant::get_constant_value((Variant::Type)p_type, *((const StringName *)p_constant));
godot_variant ret;
- memnew_placement_custom(&ret, Variant, Variant(constant));
+ memnew_placement(&ret, Variant(constant));
return ret;
}
godot_variant GDAPI godot_variant_get_constant_value_with_cstring(godot_variant_type p_type, const char *p_constant) {
Variant constant = Variant::get_constant_value((Variant::Type)p_type, StringName(p_constant));
godot_variant ret;
- memnew_placement_custom(&ret, Variant, Variant(constant));
+ memnew_placement(&ret, Variant(constant));
return ret;
}
@@ -1183,14 +1181,14 @@ godot_variant_type GDAPI godot_variant_get_utility_function_argument_type_with_c
godot_string GDAPI godot_variant_get_utility_function_argument_name(const godot_string_name *p_function, int p_argument) {
String argument_name = Variant::get_utility_function_argument_name(*((const StringName *)p_function), p_argument);
godot_string ret;
- memnew_placement_custom(&ret, String, String(argument_name));
+ memnew_placement(&ret, String(argument_name));
return ret;
}
godot_string GDAPI godot_variant_get_utility_function_argument_name_with_cstring(const char *p_function, int p_argument) {
String argument_name = Variant::get_utility_function_argument_name(StringName(p_function), p_argument);
godot_string ret;
- memnew_placement_custom(&ret, String, String(argument_name));
+ memnew_placement(&ret, String(argument_name));
return ret;
}
@@ -1228,7 +1226,7 @@ void GDAPI godot_variant_get_utility_function_list(godot_string_name *r_function
Variant::get_utility_function_list(&functions);
for (const StringName &E : functions) {
- memnew_placement_custom(func++, StringName, StringName(E));
+ memnew_placement(func++, StringName(E));
}
}
@@ -1258,7 +1256,7 @@ bool GDAPI godot_variant_has_key(const godot_variant *p_self, const godot_varian
godot_string GDAPI godot_variant_get_type_name(godot_variant_type p_type) {
String name = Variant::get_type_name((Variant::Type)p_type);
godot_string ret;
- memnew_placement_custom(&ret, String, String(name));
+ memnew_placement(&ret, String(name));
return ret;
}
diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp
index df0f29277e..2d9b45cb07 100644
--- a/modules/gdnative/nativescript/api_generator.cpp
+++ b/modules/gdnative/nativescript/api_generator.cpp
@@ -242,13 +242,9 @@ List<ClassAPI> generate_c_api_classes() {
class_api.class_name = class_name;
class_api.super_class_name = ClassDB::get_parent_class(class_name);
{
- String name = class_name;
- if (name.begins_with("_")) {
- name.remove(0);
- }
- class_api.is_singleton = Engine::get_singleton()->has_singleton(name);
+ class_api.is_singleton = Engine::get_singleton()->has_singleton(class_name);
if (class_api.is_singleton) {
- class_api.singleton_name = name;
+ class_api.singleton_name = class_name;
}
}
class_api.is_instantiable = !class_api.is_singleton && ClassDB::can_instantiate(class_name);
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index f3a0e9603f..26d3aed702 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -114,9 +114,25 @@ void NativeScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder)
#endif
bool NativeScript::inherits_script(const Ref<Script> &p_script) const {
-#ifndef _MSC_VER
-#warning inheritance needs to be implemented in NativeScript
-#endif
+ Ref<NativeScript> ns = p_script;
+ if (ns.is_null()) {
+ return false;
+ }
+
+ const NativeScriptDesc *other_s = ns->get_script_desc();
+ if (!other_s) {
+ return false;
+ }
+
+ const NativeScriptDesc *s = get_script_desc();
+
+ while (s) {
+ if (s == other_s) {
+ return true;
+ }
+ s = s->base_data;
+ }
+
return false;
}
diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp
index 7fc8178e34..5380858582 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_script.cpp
@@ -139,9 +139,20 @@ bool PluginScript::can_instantiate() const {
}
bool PluginScript::inherits_script(const Ref<Script> &p_script) const {
-#ifndef _MSC_VER
-#warning inheritance needs to be implemented in PluginScript
-#endif
+ Ref<PluginScript> ps = p_script;
+ if (ps.is_null()) {
+ return false;
+ }
+
+ const PluginScript *s = this;
+
+ while (s) {
+ if (s == p_script.ptr()) {
+ return true;
+ }
+ s = Object::cast_to<PluginScript>(s->_ref_base_parent.ptr());
+ }
+
return false;
}
diff --git a/modules/gdnative/text/text_server_gdnative.cpp b/modules/gdnative/text/text_server_gdnative.cpp
index 81dd570bcb..3ed3f5449e 100644
--- a/modules/gdnative/text/text_server_gdnative.cpp
+++ b/modules/gdnative/text/text_server_gdnative.cpp
@@ -449,12 +449,12 @@ bool TextServerGDNative::shaped_text_add_string(RID p_shaped, const String &p_te
return interface->shaped_text_add_string(data, (godot_rid *)&p_shaped, (const godot_string *)&p_text, (const godot_rid **)p_fonts.ptr(), p_size, (const godot_dictionary *)&p_opentype_features, (const godot_string *)&p_language);
}
-bool TextServerGDNative::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) {
+bool TextServerGDNative::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
ERR_FAIL_COND_V(interface == nullptr, false);
return interface->shaped_text_add_object(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key, (const godot_vector2 *)&p_size, (godot_int)p_inline_align, p_length);
}
-bool TextServerGDNative::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align) {
+bool TextServerGDNative::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
ERR_FAIL_COND_V(interface == nullptr, false);
return interface->shaped_text_resize_object(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key, (const godot_vector2 *)&p_size, (godot_int)p_inline_align);
}
@@ -498,9 +498,9 @@ bool TextServerGDNative::shaped_text_update_justification_ops(RID p_shaped) {
return interface->shaped_text_update_justification_ops(data, (godot_rid *)&p_shaped);
}
-void TextServerGDNative::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_clip_flags) {
+void TextServerGDNative::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_trim_flags) {
ERR_FAIL_COND(interface == nullptr);
- interface->shaped_text_overrun_trim_to_width(data, (godot_rid *)&p_shaped_line, p_width, p_clip_flags);
+ interface->shaped_text_overrun_trim_to_width(data, (godot_rid *)&p_shaped_line, p_width, p_trim_flags);
};
bool TextServerGDNative::shaped_text_is_ready(RID p_shaped) const {
diff --git a/modules/gdnative/text/text_server_gdnative.h b/modules/gdnative/text/text_server_gdnative.h
index 7a0725f3d9..e1b36f4264 100644
--- a/modules/gdnative/text/text_server_gdnative.h
+++ b/modules/gdnative/text/text_server_gdnative.h
@@ -154,8 +154,8 @@ public:
virtual bool shaped_text_get_preserve_control(RID p_shaped) const override;
virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override;
- virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) override;
- virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) override;
+ virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override;
+ virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override;
virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
virtual RID shaped_text_get_parent(RID p_shaped) const override;
@@ -167,7 +167,7 @@ public:
virtual bool shaped_text_update_breaks(RID p_shaped) override;
virtual bool shaped_text_update_justification_ops(RID p_shaped) override;
- virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_clip_flags) override;
+ virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_trim_flags) override;
virtual bool shaped_text_is_ready(RID p_shaped) const override;
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index ed8b0a4690..8b9bd2659d 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -45,7 +45,7 @@ static bool _is_bin_symbol(char32_t c) {
return (c == '0' || c == '1');
}
-Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line) {
+Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_line) {
Dictionary color_map;
Type next_type = NONE;
@@ -449,25 +449,21 @@ void GDScriptSyntaxHighlighter::_update_cache() {
color_region_cache.clear();
font_color = text_edit->get_theme_color(SNAME("font_color"));
- symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color");
- function_color = EDITOR_GET("text_editor/highlighting/function_color");
- number_color = EDITOR_GET("text_editor/highlighting/number_color");
- member_color = EDITOR_GET("text_editor/highlighting/member_variable_color");
+ symbol_color = EDITOR_GET("text_editor/theme/highlighting/symbol_color");
+ function_color = EDITOR_GET("text_editor/theme/highlighting/function_color");
+ number_color = EDITOR_GET("text_editor/theme/highlighting/number_color");
+ member_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color");
/* Engine types. */
- const Color types_color = EDITOR_GET("text_editor/highlighting/engine_type_color");
+ const Color types_color = EDITOR_GET("text_editor/theme/highlighting/engine_type_color");
List<StringName> types;
ClassDB::get_class_list(&types);
for (const StringName &E : types) {
- String n = E;
- if (n.begins_with("_")) {
- n = n.substr(1, n.length());
- }
- keywords[n] = types_color;
+ keywords[E] = types_color;
}
/* User types. */
- const Color usertype_color = EDITOR_GET("text_editor/highlighting/user_type_color");
+ const Color usertype_color = EDITOR_GET("text_editor/theme/highlighting/user_type_color");
List<StringName> global_classes;
ScriptServer::get_global_class_list(&global_classes);
for (const StringName &E : global_classes) {
@@ -486,7 +482,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
const GDScriptLanguage *gdscript = GDScriptLanguage::get_singleton();
/* Core types. */
- const Color basetype_color = EDITOR_GET("text_editor/highlighting/base_type_color");
+ const Color basetype_color = EDITOR_GET("text_editor/theme/highlighting/base_type_color");
List<String> core_types;
gdscript->get_core_type_words(&core_types);
for (const String &E : core_types) {
@@ -494,8 +490,8 @@ void GDScriptSyntaxHighlighter::_update_cache() {
}
/* Reserved words. */
- const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color");
- const Color control_flow_keyword_color = EDITOR_GET("text_editor/highlighting/control_flow_keyword_color");
+ const Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color");
+ const Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color");
List<String> keyword_list;
gdscript->get_reserved_words(&keyword_list);
for (const String &E : keyword_list) {
@@ -507,7 +503,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
}
/* Comments */
- const Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color");
+ const Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
List<String> comments;
gdscript->get_comment_delimiters(&comments);
for (const String &comment : comments) {
@@ -517,7 +513,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
}
/* Strings */
- const Color string_color = EDITOR_GET("text_editor/highlighting/string_color");
+ const Color string_color = EDITOR_GET("text_editor/theme/highlighting/string_color");
List<String> strings;
gdscript->get_string_delimiters(&strings);
for (const String &string : strings) {
@@ -529,7 +525,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
const Ref<Script> script = _get_edited_resource();
if (script.is_valid()) {
/* Member types. */
- const Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color");
+ const Color member_variable_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color");
StringName instance_base = script->get_instance_base_type();
if (instance_base != StringName()) {
List<PropertyInfo> plist;
@@ -566,28 +562,28 @@ void GDScriptSyntaxHighlighter::_update_cache() {
annotation_color = Color(0.8, 0.5, 0.25);
}
- EDITOR_DEF("text_editor/highlighting/gdscript/function_definition_color", function_definition_color);
- EDITOR_DEF("text_editor/highlighting/gdscript/node_path_color", node_path_color);
- EDITOR_DEF("text_editor/highlighting/gdscript/annotation_color", annotation_color);
+ EDITOR_DEF("text_editor/theme/highlighting/gdscript/function_definition_color", function_definition_color);
+ EDITOR_DEF("text_editor/theme/highlighting/gdscript/node_path_color", node_path_color);
+ EDITOR_DEF("text_editor/theme/highlighting/gdscript/annotation_color", annotation_color);
if (text_edit_color_theme == "Default" || godot_2_theme) {
EditorSettings::get_singleton()->set_initial_value(
- "text_editor/highlighting/gdscript/function_definition_color",
+ "text_editor/theme/highlighting/gdscript/function_definition_color",
function_definition_color,
true);
EditorSettings::get_singleton()->set_initial_value(
- "text_editor/highlighting/gdscript/node_path_color",
+ "text_editor/theme/highlighting/gdscript/node_path_color",
node_path_color,
true);
EditorSettings::get_singleton()->set_initial_value(
- "text_editor/highlighting/gdscript/annotation_color",
+ "text_editor/theme/highlighting/gdscript/annotation_color",
annotation_color,
true);
}
- function_definition_color = EDITOR_GET("text_editor/highlighting/gdscript/function_definition_color");
- node_path_color = EDITOR_GET("text_editor/highlighting/gdscript/node_path_color");
- annotation_color = EDITOR_GET("text_editor/highlighting/gdscript/annotation_color");
- type_color = EDITOR_GET("text_editor/highlighting/base_type_color");
+ function_definition_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/function_definition_color");
+ node_path_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/node_path_color");
+ annotation_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/annotation_color");
+ type_color = EDITOR_GET("text_editor/theme/highlighting/base_type_color");
}
void GDScriptSyntaxHighlighter::add_color_region(const String &p_start_key, const String &p_end_key, const Color &p_color, bool p_line_only) {
diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h
index d07c182aa6..fabd64dab8 100644
--- a/modules/gdscript/editor/gdscript_highlighter.h
+++ b/modules/gdscript/editor/gdscript_highlighter.h
@@ -80,7 +80,7 @@ private:
public:
virtual void _update_cache() override;
- virtual Dictionary _get_line_syntax_highlighting(int p_line) override;
+ virtual Dictionary _get_line_syntax_highlighting_impl(int p_line) override;
virtual String _get_name() const override;
virtual Array _get_supported_languages() const override;
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 8957b00a1b..4589cf1a36 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -1644,16 +1644,11 @@ void GDScriptLanguage::init() {
List<StringName> class_list;
ClassDB::get_class_list(&class_list);
for (const StringName &n : class_list) {
- String s = String(n);
- if (s.begins_with("_")) {
- s = s.substr(1, s.length());
- }
-
- if (globals.has(s)) {
+ if (globals.has(n)) {
continue;
}
Ref<GDScriptNativeClass> nc = memnew(GDScriptNativeClass(n));
- _add_global(s, nc);
+ _add_global(n, nc);
}
//populate singletons
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index ab37e54cf1..6b7403d854 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -30,6 +30,7 @@
#include "gdscript_analyzer.h"
+#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
@@ -112,11 +113,10 @@ static GDScriptParser::DataType make_native_enum_type(const StringName &p_native
type.is_meta_type = true;
List<StringName> enum_values;
- StringName real_native_name = GDScriptParser::get_real_class_name(p_native_class);
- ClassDB::get_enum_constants(real_native_name, p_enum_name, &enum_values);
+ ClassDB::get_enum_constants(p_native_class, p_enum_name, &enum_values);
for (const StringName &E : enum_values) {
- type.enum_values[E] = ClassDB::get_integer_constant(real_native_name, E);
+ type.enum_values[E] = ClassDB::get_integer_constant(p_native_class, E);
}
return type;
@@ -229,7 +229,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class);
return err;
}
- } else if (class_exists(name) && ClassDB::can_instantiate(GDScriptParser::get_real_class_name(name))) {
+ } else if (class_exists(name) && ClassDB::can_instantiate(name)) {
base.kind = GDScriptParser::DataType::NATIVE;
base.native_type = name;
} else {
@@ -406,7 +406,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
return GDScriptParser::DataType();
}
result = ref->get_parser()->head->get_datatype();
- } else if (ClassDB::has_enum(GDScriptParser::get_real_class_name(parser->current_class->base_type.native_type), first)) {
+ } else if (ClassDB::has_enum(parser->current_class->base_type.native_type, first)) {
// Native enum in current class.
result = make_native_enum_type(parser->current_class->base_type.native_type, first);
} else {
@@ -433,8 +433,28 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
case GDScriptParser::ClassNode::Member::CONSTANT:
if (member.constant->get_datatype().is_meta_type) {
result = member.constant->get_datatype();
+ result.is_meta_type = false;
found = true;
break;
+ } else if (Ref<Script>(member.constant->initializer->reduced_value).is_valid()) {
+ Ref<GDScript> gdscript = member.constant->initializer->reduced_value;
+ if (gdscript.is_valid()) {
+ Ref<GDScriptParserRef> ref = get_parser_for(gdscript->get_path());
+ if (ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) {
+ push_error(vformat(R"(Could not parse script from "%s".)", gdscript->get_path()), p_type);
+ return GDScriptParser::DataType();
+ }
+ result = ref->get_parser()->head->get_datatype();
+ result.is_meta_type = false;
+ } else {
+ Ref<GDScript> script = member.constant->initializer->reduced_value;
+ result.kind = GDScriptParser::DataType::SCRIPT;
+ result.builtin_type = Variant::OBJECT;
+ result.script_type = script;
+ result.script_path = script->get_path();
+ result.native_type = script->get_instance_base_type();
+ }
+ break;
}
[[fallthrough]];
default:
@@ -469,7 +489,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
}
} else if (result.kind == GDScriptParser::DataType::NATIVE) {
// Only enums allowed for native.
- if (ClassDB::has_enum(GDScriptParser::get_real_class_name(result.native_type), p_type->type_chain[1]->name)) {
+ if (ClassDB::has_enum(result.native_type, p_type->type_chain[1]->name)) {
if (p_type->type_chain.size() > 2) {
push_error(R"(Enums cannot contain nested types.)", p_type->type_chain[2]);
} else {
@@ -2130,6 +2150,9 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
if (is_self && parser->current_function != nullptr && parser->current_function->is_static && !is_static) {
push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parser->current_function->identifier->name), p_call->callee);
+ } else if (!is_self && base_type.is_meta_type && !is_static) {
+ base_type.is_meta_type = false; // For `to_string()`.
+ push_error(vformat(R"*(Cannot call non-static function "%s()" on the class "%s" directly. Make an instance instead.)*", p_call->function_name, base_type.to_string()), p_call->callee);
} else if (is_self && !is_static && !lambda_stack.is_empty()) {
push_error(vformat(R"*(Cannot call non-static function "%s()" from a lambda function.)*", p_call->function_name), p_call->callee);
}
@@ -2252,7 +2275,7 @@ void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node)
result.native_type = "Node";
result.builtin_type = Variant::OBJECT;
- if (!ClassDB::is_parent_class(GDScriptParser::get_real_class_name(parser->current_class->base_type.native_type), result.native_type)) {
+ if (!ClassDB::is_parent_class(parser->current_class->base_type.native_type, result.native_type)) {
push_error(R"*(Cannot use shorthand "get_node()" notation ("$") on a class that isn't a node.)*", p_get_node);
} else if (!lambda_stack.is_empty()) {
push_error(R"*(Cannot use shorthand "get_node()" notation ("$") inside a lambda. Use a captured variable instead.)*", p_get_node);
@@ -2393,6 +2416,11 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
resolve_function_signature(member.function);
p_identifier->set_datatype(make_callable_type(member.function->info));
break;
+ case GDScriptParser::ClassNode::Member::CLASS:
+ // For out-of-order resolution:
+ resolve_class_interface(member.m_class);
+ p_identifier->set_datatype(member.m_class->get_datatype());
+ break;
default:
break; // Type already set.
}
@@ -2421,7 +2449,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
}
// Check native members.
- const StringName &native = GDScriptParser::get_real_class_name(base.native_type);
+ const StringName &native = base.native_type;
if (class_exists(native)) {
PropertyInfo prop_info;
@@ -3202,7 +3230,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo
return result;
}
-bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GDScriptParser::DataType p_base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) {
+bool GDScriptAnalyzer::get_function_signature(GDScriptParser::CallNode *p_source, GDScriptParser::DataType p_base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) {
r_static = false;
r_vararg = false;
r_default_arg_count = 0;
@@ -3221,14 +3249,16 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD
for (const MethodInfo &E : methods) {
if (E.name == p_function) {
- return function_signature_from_info(E, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
+ function_signature_from_info(E, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
+ r_static = Variant::is_builtin_method_static(p_base_type.builtin_type, function_name);
+ return true;
}
}
return false;
}
- bool is_constructor = p_base_type.is_meta_type && p_function == "new";
+ bool is_constructor = (p_base_type.is_meta_type || (p_source->callee && p_source->callee->type == GDScriptParser::Node::IDENTIFIER)) && p_function == StaticCString::create("new");
if (is_constructor) {
function_name = "_init";
r_static = true;
@@ -3258,6 +3288,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD
}
}
r_return_type = found_function->get_datatype();
+ r_return_type.is_meta_type = false;
r_return_type.is_coroutine = found_function->is_coroutine;
return true;
@@ -3303,11 +3334,13 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD
return true;
}
- StringName real_native = GDScriptParser::get_real_class_name(base_native);
-
MethodInfo info;
- if (ClassDB::get_method_info(real_native, function_name, &info)) {
- return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
+ if (ClassDB::get_method_info(base_native, function_name, &info)) {
+ bool valid = function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
+ if (valid && Engine::get_singleton()->has_singleton(base_native)) {
+ r_static = true;
+ }
+ return valid;
}
return false;
@@ -3398,24 +3431,23 @@ bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con
StringName parent = base_native;
while (parent != StringName()) {
- StringName real_class_name = GDScriptParser::get_real_class_name(parent);
- if (ClassDB::has_method(real_class_name, name, true)) {
+ if (ClassDB::has_method(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "method", parent);
return true;
- } else if (ClassDB::has_signal(real_class_name, name, true)) {
+ } else if (ClassDB::has_signal(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "signal", parent);
return true;
- } else if (ClassDB::has_property(real_class_name, name, true)) {
+ } else if (ClassDB::has_property(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "property", parent);
return true;
- } else if (ClassDB::has_integer_constant(real_class_name, name, true)) {
+ } else if (ClassDB::has_integer_constant(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "constant", parent);
return true;
- } else if (ClassDB::has_enum(real_class_name, name, true)) {
+ } else if (ClassDB::has_enum(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "enum", parent);
return true;
}
- parent = ClassDB::get_parent_class(real_class_name);
+ parent = ClassDB::get_parent_class(parent);
}
return false;
@@ -3560,16 +3592,12 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
break; // Already solved before.
}
- // Get underscore-prefixed version for some classes.
- src_native = GDScriptParser::get_real_class_name(src_native);
-
switch (p_target.kind) {
case GDScriptParser::DataType::NATIVE: {
if (p_target.is_meta_type) {
return ClassDB::is_parent_class(src_native, GDScriptNativeClass::get_class_static());
}
- StringName tgt_native = GDScriptParser::get_real_class_name(p_target.native_type);
- return ClassDB::is_parent_class(src_native, tgt_native);
+ return ClassDB::is_parent_class(src_native, p_target.native_type);
}
case GDScriptParser::DataType::SCRIPT:
if (p_target.is_meta_type) {
@@ -3618,8 +3646,7 @@ void GDScriptAnalyzer::mark_node_unsafe(const GDScriptParser::Node *p_node) {
}
bool GDScriptAnalyzer::class_exists(const StringName &p_class) const {
- StringName real_name = GDScriptParser::get_real_class_name(p_class);
- return ClassDB::class_exists(real_name) && ClassDB::is_class_exposed(real_name);
+ return ClassDB::class_exists(p_class) && ClassDB::is_class_exposed(p_class);
}
Ref<GDScriptParserRef> GDScriptAnalyzer::get_parser_for(const String &p_path) {
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 8cd3fcf837..32bf049fa1 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -99,7 +99,7 @@ class GDScriptAnalyzer {
GDScriptParser::DataType type_from_metatype(const GDScriptParser::DataType &p_meta_type) const;
GDScriptParser::DataType type_from_property(const PropertyInfo &p_property) const;
GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source);
- bool get_function_signature(GDScriptParser::Node *p_source, GDScriptParser::DataType base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg);
+ bool get_function_signature(GDScriptParser::CallNode *p_source, GDScriptParser::DataType base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg);
bool function_signature_from_info(const MethodInfo &p_info, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg);
bool validate_call_arg(const List<GDScriptParser::DataType> &p_par_types, int p_default_args_count, bool p_is_vararg, const GDScriptParser::CallNode *p_call);
bool validate_call_arg(const MethodInfo &p_method, const GDScriptParser::CallNode *p_call);
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index 1a844bf241..07f50d14dc 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -200,7 +200,9 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro
if (singleton->full_gdscript_cache.has(p_path)) {
return singleton->full_gdscript_cache[p_path];
}
+
Ref<GDScript> script = get_shallow_script(p_path);
+ ERR_FAIL_COND_V(script.is_null(), Ref<GDScript>());
r_error = script->load_source_code(p_path);
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 7c9d08b782..ddf4f281b4 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -107,7 +107,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
// Locate class by constructing the path to it and following that path
GDScriptParser::ClassNode *class_type = p_datatype.class_type;
if (class_type) {
- if (class_type->fqcn.begins_with(main_script->path) || (!main_script->name.is_empty() && class_type->fqcn.begins_with(main_script->name))) {
+ if ((!main_script->path.is_empty() && class_type->fqcn.begins_with(main_script->path)) || (!main_script->name.is_empty() && class_type->fqcn.begins_with(main_script->name))) {
// Local class.
List<StringName> names;
while (class_type->outer) {
@@ -126,8 +126,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
names.pop_back();
}
result.kind = GDScriptDataType::GDSCRIPT;
- result.script_type_ref = script;
- result.script_type = result.script_type_ref.ptr();
+ result.script_type = script.ptr();
result.native_type = script->get_instance_base_type();
} else {
result.kind = GDScriptDataType::GDSCRIPT;
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 2a93bb620b..372a726d71 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -623,11 +623,11 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio
}
static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String, ScriptCodeCompletionOption> &r_list) {
- const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
+ const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
for (int i = 0; i < p_dir->get_file_count(); i++) {
ScriptCodeCompletionOption option(p_dir->get_file_path(i), ScriptCodeCompletionOption::KIND_FILE_PATH);
- option.insert_text = quote_style + option.display + quote_style;
+ option.insert_text = option.display.quote(quote_style);
r_list.insert(option.display, option);
}
@@ -641,20 +641,20 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a
if (p_argument == 3 || p_argument == 4) {
// Slider hint.
ScriptCodeCompletionOption slider1("or_greater", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
- slider1.insert_text = p_quote_style + slider1.display + p_quote_style;
+ slider1.insert_text = slider1.display.quote(p_quote_style);
r_result.insert(slider1.display, slider1);
ScriptCodeCompletionOption slider2("or_lesser", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
- slider2.insert_text = p_quote_style + slider2.display + p_quote_style;
+ slider2.insert_text = slider2.display.quote(p_quote_style);
r_result.insert(slider2.display, slider2);
}
} else if (p_annotation->name == "@export_exp_easing") {
if (p_argument == 0 || p_argument == 1) {
// Easing hint.
ScriptCodeCompletionOption hint1("attenuation", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
- hint1.insert_text = p_quote_style + hint1.display + p_quote_style;
+ hint1.insert_text = hint1.display.quote(p_quote_style);
r_result.insert(hint1.display, hint1);
ScriptCodeCompletionOption hint2("inout", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
- hint2.insert_text = p_quote_style + hint2.display + p_quote_style;
+ hint2.insert_text = hint2.display.quote(p_quote_style);
r_result.insert(hint2.display, hint2);
}
} else if (p_annotation->name == "@export_node_path") {
@@ -912,7 +912,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
}
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName type = GDScriptParser::get_real_class_name(base_type.native_type);
+ StringName type = base_type.native_type;
if (!ClassDB::class_exists(type)) {
return;
}
@@ -1326,10 +1326,7 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
native_type.kind = GDScriptParser::DataType::NATIVE;
native_type.native_type = native_type.script_type->get_instance_base_type();
if (!ClassDB::class_exists(native_type.native_type)) {
- native_type.native_type = String("_") + native_type.native_type;
- if (!ClassDB::class_exists(native_type.native_type)) {
- native_type.kind = GDScriptParser::DataType::UNRESOLVED;
- }
+ native_type.kind = GDScriptParser::DataType::UNRESOLVED;
}
}
}
@@ -1765,9 +1762,8 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
base_type = GDScriptParser::DataType();
break;
}
- StringName real_native = GDScriptParser::get_real_class_name(base_type.native_type);
MethodInfo info;
- if (ClassDB::get_method_info(real_native, p_context.current_function->identifier->name, &info)) {
+ if (ClassDB::get_method_info(base_type.native_type, p_context.current_function->identifier->name, &info)) {
for (const PropertyInfo &E : info.arguments) {
if (E.name == p_identifier) {
r_type = _type_from_property(E);
@@ -1836,13 +1832,12 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
}
// Check ClassDB.
- StringName class_name = GDScriptParser::get_real_class_name(p_identifier);
- if (ClassDB::class_exists(class_name) && ClassDB::is_class_exposed(class_name)) {
+ if (ClassDB::class_exists(p_identifier) && ClassDB::is_class_exposed(p_identifier)) {
r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
r_type.type.kind = GDScriptParser::DataType::NATIVE;
r_type.type.native_type = p_identifier;
r_type.type.is_constant = true;
- r_type.type.is_meta_type = !Engine::get_singleton()->has_singleton(class_name);
+ r_type.type.is_meta_type = !Engine::get_singleton()->has_singleton(p_identifier);
r_type.value = Variant();
}
@@ -1951,7 +1946,7 @@ static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext &
}
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type);
+ StringName class_name = base_type.native_type;
if (!ClassDB::class_exists(class_name)) {
return false;
}
@@ -2113,11 +2108,10 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex
}
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName native = GDScriptParser::get_real_class_name(base_type.native_type);
- if (!ClassDB::class_exists(native)) {
+ if (!ClassDB::class_exists(base_type.native_type)) {
return false;
}
- MethodBind *mb = ClassDB::get_method(native, p_method);
+ MethodBind *mb = ClassDB::get_method(base_type.native_type, p_method);
if (mb) {
r_type = _type_from_property(mb->get_return_info());
return true;
@@ -2192,7 +2186,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
Variant base = p_base.value;
GDScriptParser::DataType base_type = p_base.type;
- const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
+ const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
while (base_type.is_set() && !base_type.is_variant()) {
switch (base_type.kind) {
@@ -2209,7 +2203,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
base_type = base_type.class_type->base_type;
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type);
+ StringName class_name = base_type.native_type;
if (!ClassDB::class_exists(class_name)) {
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
break;
@@ -2254,7 +2248,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
}
String name = s.get_slice("/", 1);
ScriptCodeCompletionOption option("/root/" + name, ScriptCodeCompletionOption::KIND_NODE_PATH);
- option.insert_text = quote_style + option.display + quote_style;
+ option.insert_text = option.display.quote(quote_style);
r_result.insert(option.display, option);
}
}
@@ -2270,7 +2264,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
}
String name = s.get_slice("/", 1);
ScriptCodeCompletionOption option(name, ScriptCodeCompletionOption::KIND_CONSTANT);
- option.insert_text = quote_style + option.display + quote_style;
+ option.insert_text = option.display.quote(quote_style);
r_result.insert(option.display, option);
}
}
@@ -2305,8 +2299,6 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
}
static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptParser::Node *p_call, int p_argidx, Map<String, ScriptCodeCompletionOption> &r_result, bool &r_forced, String &r_arghint) {
- const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
-
if (p_call->type == GDScriptParser::Node::PRELOAD) {
if (p_argidx == 0 && bool(EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))) {
_get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), r_result);
@@ -2382,7 +2374,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
}
::Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) {
- const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
+ const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
GDScriptParser parser;
GDScriptAnalyzer analyzer(&parser);
@@ -2594,7 +2586,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
break;
}
- StringName class_name = GDScriptParser::get_real_class_name(native_type.native_type);
+ StringName class_name = native_type.native_type;
if (!ClassDB::class_exists(class_name)) {
break;
}
@@ -2671,8 +2663,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) {
- String name = E->key();
- ScriptCodeCompletionOption option(quote_style + "/root/" + name + quote_style, ScriptCodeCompletionOption::KIND_NODE_PATH);
+ String path = "/root/" + E->key();
+ ScriptCodeCompletionOption option(path.quote(quote_style), ScriptCodeCompletionOption::KIND_NODE_PATH);
options.insert(option.display, option);
}
}
@@ -2705,10 +2697,10 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
String GDScriptLanguage::_get_indentation() const {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
- bool use_space_indentation = EDITOR_DEF("text_editor/indent/type", false);
+ bool use_space_indentation = EDITOR_DEF("text_editor/behavior/indent/type", false);
if (use_space_indentation) {
- int indent_size = EDITOR_DEF("text_editor/indent/size", 4);
+ int indent_size = EDITOR_DEF("text_editor/behavior/indent/size", 4);
String space_indent = "";
for (int i = 0; i < indent_size; i++) {
@@ -2795,6 +2787,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
if (base_type.class_type->has_member(p_symbol)) {
r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
r_result.location = base_type.class_type->get_member(p_symbol).get_line();
+ r_result.class_path = base_type.script_path;
return OK;
}
base_type = base_type.class_type->base_type;
@@ -2822,7 +2815,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type);
+ StringName class_name = base_type.native_type;
if (!ClassDB::class_exists(class_name)) {
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
break;
@@ -2874,11 +2867,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
StringName parent = ClassDB::get_parent_class(class_name);
if (parent != StringName()) {
- if (String(parent).begins_with("_")) {
- base_type.native_type = String(parent).substr(1);
- } else {
- base_type.native_type = parent;
- }
+ base_type.native_type = parent;
} else {
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
}
@@ -2932,18 +2921,11 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
::Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) {
- //before parsing, try the usual stuff
+ // Before parsing, try the usual stuff
if (ClassDB::class_exists(p_symbol)) {
r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
r_result.class_name = p_symbol;
return OK;
- } else {
- String under_prefix = "_" + p_symbol;
- if (ClassDB::class_exists(under_prefix)) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
- r_result.class_name = p_symbol;
- return OK;
- }
}
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index 9e5ef0f632..87d8c03494 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -111,11 +111,7 @@ public:
}
if (!ClassDB::is_parent_class(obj->get_class_name(), native_type)) {
- // Try with underscore prefix
- StringName underscore_native_type = "_" + native_type;
- if (!ClassDB::is_parent_class(obj->get_class_name(), underscore_native_type)) {
- return false;
- }
+ return false;
}
return true;
} break;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 466ddb4b10..af872e49e2 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -94,43 +94,8 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) {
return Variant::VARIANT_MAX;
}
-// TODO: Move this to a central location (maybe core?).
-static HashMap<StringName, StringName> underscore_map;
-static const char *underscore_classes[] = {
- "ClassDB",
- "Directory",
- "Engine",
- "File",
- "Geometry",
- "GodotSharp",
- "JSON",
- "Marshalls",
- "Mutex",
- "OS",
- "ResourceLoader",
- "ResourceSaver",
- "Semaphore",
- "Thread",
- "VisualScriptEditor",
- nullptr,
-};
-StringName GDScriptParser::get_real_class_name(const StringName &p_source) {
- if (underscore_map.is_empty()) {
- const char **class_name = underscore_classes;
- while (*class_name != nullptr) {
- underscore_map[*class_name] = String("_") + *class_name;
- class_name++;
- }
- }
- if (underscore_map.has(p_source)) {
- return underscore_map[p_source];
- }
- return p_source;
-}
-
void GDScriptParser::cleanup() {
builtin_types.clear();
- underscore_map.clear();
}
void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const {
@@ -168,7 +133,7 @@ GDScriptParser::GDScriptParser() {
register_annotation(MethodInfo("@export_flags_3d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_PHYSICS, Variant::INT>);
register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>);
// Networking.
- register_annotation(MethodInfo("@rpc", { Variant::STRING, "mode" }, { Variant::STRING, "sync" }, { Variant::STRING, "transfer_mode" }, { Variant::INT, "transfer_channel" }), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_MASTER>, 4, true);
+ register_annotation(MethodInfo("@rpc", { Variant::STRING, "mode" }, { Variant::STRING, "sync" }, { Variant::STRING, "transfer_mode" }, { Variant::INT, "transfer_channel" }), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_PUPPET>, 4, true);
// TODO: Warning annotations.
}
@@ -337,7 +302,7 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_
int tab_size = 4;
#ifdef TOOLS_ENABLED
if (EditorSettings::get_singleton()) {
- tab_size = EditorSettings::get_singleton()->get_setting("text_editor/indent/size");
+ tab_size = EditorSettings::get_singleton()->get_setting("text_editor/behavior/indent/size");
}
#endif // TOOLS_ENABLED
@@ -1152,7 +1117,6 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
}
item.custom_value = value;
}
- item.rightmost_column = previous.rightmost_column;
item.index = enum_node->values.size();
enum_node->values.push_back(item);
@@ -2480,7 +2444,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode
switch (dictionary->style) {
case DictionaryNode::LUA_TABLE:
if (key != nullptr && key->type != Node::IDENTIFIER) {
- push_error("Expected identifier as dictionary key.");
+ push_error("Expected identifier as LUA-style dictionary key.");
+ advance();
+ break;
}
if (!match(GDScriptTokenizer::Token::EQUAL)) {
if (match(GDScriptTokenizer::Token::COLON)) {
@@ -2984,7 +2950,7 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &
} else {
/* Syntax:
- @tutorial ( The Title Here ) : http://the.url/
+ @tutorial ( The Title Here ) : https://the.url/
^ open ^ close ^ colon ^ url
*/
int open_bracket_pos = begin_scan, close_bracket_pos = 0;
@@ -3361,10 +3327,10 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
variable->export_info.hint_string = Variant::get_type_name(export_type.builtin_type);
break;
case GDScriptParser::DataType::NATIVE:
- if (ClassDB::is_parent_class(get_real_class_name(export_type.native_type), "Resource")) {
+ if (ClassDB::is_parent_class(export_type.native_type, "Resource")) {
variable->export_info.type = Variant::OBJECT;
variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE;
- variable->export_info.hint_string = get_real_class_name(export_type.native_type);
+ variable->export_info.hint_string = export_type.native_type;
} else {
push_error(R"(Export type can only be built-in, a resource, or an enum.)", variable);
return false;
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 6a227a55e5..0bce8d7ddd 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -1399,7 +1399,6 @@ public:
ClassNode *get_tree() const { return head; }
bool is_tool() const { return _is_tool; }
static Variant::Type get_builtin_type(const StringName &p_type);
- static StringName get_real_class_name(const StringName &p_source);
CompletionContext get_completion_context() const { return completion_context; }
CompletionCall get_completion_call() const { return completion_call; }
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 3f14156dfa..d4a098811a 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -1440,7 +1440,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() {
GDScriptTokenizer::GDScriptTokenizer() {
#ifdef TOOLS_ENABLED
if (EditorSettings::get_singleton()) {
- tab_size = EditorSettings::get_singleton()->get_setting("text_editor/indent/size");
+ tab_size = EditorSettings::get_singleton()->get_setting("text_editor/behavior/indent/size");
}
#endif // TOOLS_ENABLED
}
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 8a261a88e3..882256b7e3 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -174,7 +174,7 @@ void (*type_init_function_table[])(Variant *) = {
&VariantInitializer<StringName>::init, // STRING_NAME.
&VariantInitializer<NodePath>::init, // NODE_PATH.
&VariantInitializer<RID>::init, // RID.
- &VariantTypeAdjust<Object *>::adjust, // OBJECT.
+ &VariantInitializer<Object *>::init, // OBJECT.
&VariantInitializer<Callable>::init, // CALLABLE.
&VariantInitializer<Signal>::init, // SIGNAL.
&VariantInitializer<Dictionary>::init, // DICTIONARY.
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index 69ddbe5d1e..03b1e3fa44 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -42,10 +42,12 @@ void GDScriptTextDocument::_bind_methods() {
ClassDB::bind_method(D_METHOD("didOpen"), &GDScriptTextDocument::didOpen);
ClassDB::bind_method(D_METHOD("didClose"), &GDScriptTextDocument::didClose);
ClassDB::bind_method(D_METHOD("didChange"), &GDScriptTextDocument::didChange);
+ ClassDB::bind_method(D_METHOD("didSave"), &GDScriptTextDocument::didSave);
ClassDB::bind_method(D_METHOD("nativeSymbol"), &GDScriptTextDocument::nativeSymbol);
ClassDB::bind_method(D_METHOD("documentSymbol"), &GDScriptTextDocument::documentSymbol);
ClassDB::bind_method(D_METHOD("completion"), &GDScriptTextDocument::completion);
ClassDB::bind_method(D_METHOD("resolve"), &GDScriptTextDocument::resolve);
+ ClassDB::bind_method(D_METHOD("rename"), &GDScriptTextDocument::rename);
ClassDB::bind_method(D_METHOD("foldingRange"), &GDScriptTextDocument::foldingRange);
ClassDB::bind_method(D_METHOD("codeLens"), &GDScriptTextDocument::codeLens);
ClassDB::bind_method(D_METHOD("documentLink"), &GDScriptTextDocument::documentLink);
@@ -79,6 +81,20 @@ void GDScriptTextDocument::didChange(const Variant &p_param) {
sync_script_content(doc.uri, doc.text);
}
+void GDScriptTextDocument::didSave(const Variant &p_param) {
+ lsp::TextDocumentItem doc = load_document_item(p_param);
+ Dictionary dict = p_param;
+ String text = dict["text"];
+
+ sync_script_content(doc.uri, text);
+
+ /*String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(doc.uri);
+
+ Ref<GDScript> script = ResourceLoader::load(path);
+ script->load_source_code(path);
+ script->reload(true);*/
+}
+
lsp::TextDocumentItem GDScriptTextDocument::load_document_item(const Variant &p_param) {
lsp::TextDocumentItem doc;
Dictionary params = p_param;
@@ -215,6 +231,14 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) {
return arr;
}
+Dictionary GDScriptTextDocument::rename(const Dictionary &p_params) {
+ lsp::TextDocumentPositionParams params;
+ params.load(p_params);
+ String new_name = p_params["newName"];
+
+ return GDScriptLanguageProtocol::get_singleton()->get_workspace()->rename(params, new_name);
+}
+
Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) {
lsp::CompletionItem item;
item.load(p_params);
@@ -267,8 +291,8 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) {
}
} else if (item.kind == lsp::CompletionItemKind::Event) {
if (params.context.triggerKind == lsp::CompletionTriggerKind::TriggerCharacter && (params.context.triggerCharacter == "(")) {
- const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
- item.insertText = quote_style + item.label + quote_style;
+ const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
+ item.insertText = item.label.quote(quote_style);
}
}
@@ -405,7 +429,15 @@ GDScriptTextDocument::~GDScriptTextDocument() {
void GDScriptTextDocument::sync_script_content(const String &p_path, const String &p_content) {
String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_path);
GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content);
+
EditorFileSystem::get_singleton()->update_file(path);
+ Error error;
+ Ref<GDScript> script = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &error);
+ if (error == OK) {
+ if (script->load_source_code(path) == OK) {
+ script->reload(true);
+ }
+ }
}
void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) {
diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h
index e2987f779c..9021c84a3f 100644
--- a/modules/gdscript/language_server/gdscript_text_document.h
+++ b/modules/gdscript/language_server/gdscript_text_document.h
@@ -45,6 +45,7 @@ protected:
void didOpen(const Variant &p_param);
void didClose(const Variant &p_param);
void didChange(const Variant &p_param);
+ void didSave(const Variant &p_param);
void sync_script_content(const String &p_path, const String &p_content);
void show_native_symbol_in_editor(const String &p_symbol_id);
@@ -61,6 +62,7 @@ public:
Array documentSymbol(const Dictionary &p_params);
Array completion(const Dictionary &p_params);
Dictionary resolve(const Dictionary &p_params);
+ Dictionary rename(const Dictionary &p_params);
Array foldingRange(const Dictionary &p_params);
Array codeLens(const Dictionary &p_params);
Array documentLink(const Dictionary &p_params);
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index e6c819b22f..1512b4bb89 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -116,6 +116,36 @@ const lsp::DocumentSymbol *GDScriptWorkspace::get_script_symbol(const String &p_
return nullptr;
}
+const lsp::DocumentSymbol *GDScriptWorkspace::get_parameter_symbol(const lsp::DocumentSymbol *p_parent, const String &symbol_identifier) {
+ for (int i = 0; i < p_parent->children.size(); ++i) {
+ const lsp::DocumentSymbol *parameter_symbol = &p_parent->children[i];
+ if (!parameter_symbol->detail.is_empty() && parameter_symbol->name == symbol_identifier) {
+ return parameter_symbol;
+ }
+ }
+
+ return nullptr;
+}
+
+const lsp::DocumentSymbol *GDScriptWorkspace::get_local_symbol(const ExtendGDScriptParser *p_parser, const String &p_symbol_identifier) {
+ const lsp::DocumentSymbol *class_symbol = &p_parser->get_symbols();
+
+ for (int i = 0; i < class_symbol->children.size(); ++i) {
+ if (class_symbol->children[i].kind == lsp::SymbolKind::Function || class_symbol->children[i].kind == lsp::SymbolKind::Class) {
+ const lsp::DocumentSymbol *function_symbol = &class_symbol->children[i];
+
+ for (int l = 0; l < function_symbol->children.size(); ++l) {
+ const lsp::DocumentSymbol *local = &function_symbol->children[l];
+ if (!local->detail.is_empty() && local->name == p_symbol_identifier) {
+ return local;
+ }
+ }
+ }
+ }
+
+ return nullptr;
+}
+
void GDScriptWorkspace::reload_all_workspace_scripts() {
List<String> paths;
list_script_files("res://", paths);
@@ -231,18 +261,13 @@ Error GDScriptWorkspace::initialize() {
class_symbol.children.push_back(symbol);
}
- Vector<DocData::PropertyDoc> properties;
- properties.append_array(class_data.properties);
- const int theme_prop_start_idx = properties.size();
- properties.append_array(class_data.theme_properties);
-
for (int i = 0; i < class_data.properties.size(); i++) {
const DocData::PropertyDoc &data = class_data.properties[i];
lsp::DocumentSymbol symbol;
symbol.name = data.name;
symbol.native_class = class_name;
symbol.kind = lsp::SymbolKind::Property;
- symbol.detail = String(i >= theme_prop_start_idx ? "<Theme> var" : "var") + " " + class_name + "." + data.name;
+ symbol.detail = "var " + class_name + "." + data.name;
if (data.enumeration.length()) {
symbol.detail += ": " + data.enumeration;
} else {
@@ -252,6 +277,17 @@ Error GDScriptWorkspace::initialize() {
class_symbol.children.push_back(symbol);
}
+ for (int i = 0; i < class_data.theme_properties.size(); i++) {
+ const DocData::ThemeItemDoc &data = class_data.theme_properties[i];
+ lsp::DocumentSymbol symbol;
+ symbol.name = data.name;
+ symbol.native_class = class_name;
+ symbol.kind = lsp::SymbolKind::Property;
+ symbol.detail = "<Theme> var " + class_name + "." + data.name + ": " + data.type;
+ symbol.documentation = data.description;
+ class_symbol.children.push_back(symbol);
+ }
+
Vector<DocData::MethodDoc> methods_signals;
methods_signals.append_array(class_data.methods);
const int signal_start_idx = methods_signals.size();
@@ -350,6 +386,50 @@ Error GDScriptWorkspace::parse_script(const String &p_path, const String &p_cont
return err;
}
+Dictionary GDScriptWorkspace::rename(const lsp::TextDocumentPositionParams &p_doc_pos, const String &new_name) {
+ Error err;
+ String path = get_file_path(p_doc_pos.textDocument.uri);
+
+ lsp::WorkspaceEdit edit;
+
+ List<String> paths;
+ list_script_files("res://", paths);
+
+ const lsp::DocumentSymbol *reference_symbol = resolve_symbol(p_doc_pos);
+ if (reference_symbol) {
+ String identifier = reference_symbol->name;
+
+ for (List<String>::Element *PE = paths.front(); PE; PE = PE->next()) {
+ PackedStringArray content = FileAccess::get_file_as_string(PE->get(), &err).split("\n");
+ for (int i = 0; i < content.size(); ++i) {
+ String line = content[i];
+
+ int character = line.find(identifier);
+ while (character > -1) {
+ lsp::TextDocumentPositionParams params;
+
+ lsp::TextDocumentIdentifier text_doc;
+ text_doc.uri = get_file_uri(PE->get());
+
+ params.textDocument = text_doc;
+ params.position.line = i;
+ params.position.character = character;
+
+ const lsp::DocumentSymbol *other_symbol = resolve_symbol(params);
+
+ if (other_symbol == reference_symbol) {
+ edit.add_change(text_doc.uri, i, character, character + identifier.length(), new_name);
+ }
+
+ character = line.find(identifier, character + 1);
+ }
+ }
+ }
+ }
+
+ return edit.to_json();
+}
+
Error GDScriptWorkspace::parse_local_script(const String &p_path) {
Error err;
String content = FileAccess::get_file_as_string(p_path, &err);
@@ -440,8 +520,31 @@ void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<S
if (const ExtendGDScriptParser *parser = get_parse_result(path)) {
Node *owner_scene_node = _get_owner_scene_node(path);
+
+ Array stack;
+ Node *current = nullptr;
+ if (owner_scene_node != nullptr) {
+ stack.push_back(owner_scene_node);
+
+ while (!stack.is_empty()) {
+ current = stack.pop_back();
+ Ref<GDScript> script = current->get_script();
+ if (script.is_valid() && script->get_path() == path) {
+ break;
+ }
+ for (int i = 0; i < current->get_child_count(); ++i) {
+ stack.push_back(current->get_child(i));
+ }
+ }
+
+ Ref<GDScript> script = current->get_script();
+ if (!script.is_valid() || script->get_path() != path) {
+ current = owner_scene_node;
+ }
+ }
+
String code = parser->get_text_for_completion(p_params.position);
- GDScriptLanguage::get_singleton()->complete_code(code, path, owner_scene_node, r_options, forced, call_hint);
+ GDScriptLanguage::get_singleton()->complete_code(code, path, current, r_options, forced, call_hint);
if (owner_scene_node) {
memdelete(owner_scene_node);
}
@@ -478,10 +581,16 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu
String target_script_path = path;
if (!ret.script.is_null()) {
target_script_path = ret.script->get_path();
+ } else if (!ret.class_path.is_empty()) {
+ target_script_path = ret.class_path;
}
if (const ExtendGDScriptParser *target_parser = get_parse_result(target_script_path)) {
symbol = target_parser->get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(ret.location));
+
+ if (symbol && symbol->kind == lsp::SymbolKind::Function && symbol->name != symbol_identifier) {
+ symbol = get_parameter_symbol(symbol, symbol_identifier);
+ }
}
} else {
@@ -493,6 +602,10 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu
}
} else {
symbol = parser->get_member_symbol(symbol_identifier);
+
+ if (!symbol) {
+ symbol = get_local_symbol(parser, symbol_identifier);
+ }
}
}
}
diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h
index 8b166a873c..9496677449 100644
--- a/modules/gdscript/language_server/gdscript_workspace.h
+++ b/modules/gdscript/language_server/gdscript_workspace.h
@@ -52,6 +52,8 @@ protected:
const lsp::DocumentSymbol *get_native_symbol(const String &p_class, const String &p_member = "") const;
const lsp::DocumentSymbol *get_script_symbol(const String &p_path) const;
+ const lsp::DocumentSymbol *get_parameter_symbol(const lsp::DocumentSymbol *p_parent, const String &symbol_identifier);
+ const lsp::DocumentSymbol *get_local_symbol(const ExtendGDScriptParser *p_parser, const String &p_symbol_identifier);
void reload_all_workspace_scripts();
@@ -90,6 +92,7 @@ public:
Dictionary generate_script_api(const String &p_path);
Error resolve_signature(const lsp::TextDocumentPositionParams &p_doc_pos, lsp::SignatureHelp &r_signature);
void did_delete_files(const Dictionary &p_params);
+ Dictionary rename(const lsp::TextDocumentPositionParams &p_doc_pos, const String &new_name);
GDScriptWorkspace();
~GDScriptWorkspace();
diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp
index 0138f132ad..9ac6c6bd4e 100644
--- a/modules/gdscript/language_server/lsp.hpp
+++ b/modules/gdscript/language_server/lsp.hpp
@@ -255,6 +255,62 @@ struct TextEdit {
};
/**
+ * The edits to be applied.
+ */
+struct WorkspaceEdit {
+ /**
+ * Holds changes to existing resources.
+ */
+ Map<String, Vector<TextEdit>> changes;
+
+ _FORCE_INLINE_ Dictionary to_json() const {
+ Dictionary dict;
+
+ Dictionary out_changes;
+ for (Map<String, Vector<TextEdit>>::Element *E = changes.front(); E; E = E->next()) {
+ Array edits;
+ for (int i = 0; i < E->get().size(); ++i) {
+ Dictionary text_edit;
+ text_edit["range"] = E->get()[i].range.to_json();
+ text_edit["newText"] = E->get()[i].newText;
+ edits.push_back(text_edit);
+ }
+ out_changes[E->key()] = edits;
+ }
+ dict["changes"] = out_changes;
+
+ return dict;
+ }
+
+ _FORCE_INLINE_ void add_change(const String &uri, const int &line, const int &start_character, const int &end_character, const String &new_text) {
+ if (Map<String, Vector<TextEdit>>::Element *E = changes.find(uri)) {
+ Vector<TextEdit> edit_list = E->value();
+ for (int i = 0; i < edit_list.size(); ++i) {
+ TextEdit edit = edit_list[i];
+ if (edit.range.start.character == start_character) {
+ return;
+ }
+ }
+ }
+
+ TextEdit new_edit;
+ new_edit.newText = new_text;
+ new_edit.range.start.line = line;
+ new_edit.range.start.character = start_character;
+ new_edit.range.end.line = line;
+ new_edit.range.end.character = end_character;
+
+ if (Map<String, Vector<TextEdit>>::Element *E = changes.find(uri)) {
+ E->value().push_back(new_edit);
+ } else {
+ Vector<TextEdit> edit_list;
+ edit_list.push_back(new_edit);
+ changes.insert(uri, edit_list);
+ }
+ }
+};
+
+/**
* Represents a reference to a command.
* Provides a title which will be used to represent a command in the UI.
* Commands are identified by a string identifier.
@@ -486,7 +542,7 @@ struct TextDocumentSyncOptions {
* If present save notifications are sent to the server. If omitted the notification should not be
* sent.
*/
- bool save = false;
+ SaveOptions save;
Dictionary to_json() {
Dictionary dict;
@@ -494,7 +550,7 @@ struct TextDocumentSyncOptions {
dict["willSave"] = willSave;
dict["openClose"] = openClose;
dict["change"] = change;
- dict["save"] = save;
+ dict["save"] = save.to_json();
return dict;
}
};
diff --git a/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.gd b/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.gd
new file mode 100644
index 0000000000..ac66b78220
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.gd
@@ -0,0 +1,3 @@
+func test():
+ print(Color.html_is_valid("00ffff"))
+ print("OK")
diff --git a/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.out b/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.out
new file mode 100644
index 0000000000..75b002aa62
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/call_static_builtin_function.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+True
+OK
diff --git a/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd b/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd
new file mode 100644
index 0000000000..fb0ace6a90
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd
@@ -0,0 +1,5 @@
+func test():
+ pass
+
+func something():
+ return "OK"
diff --git a/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.out b/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.gd b/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.gd
new file mode 100644
index 0000000000..4f4b7a4897
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.gd
@@ -0,0 +1,11 @@
+class InnerClass:
+ var val := "OK"
+ static func create_instance() -> InnerClass:
+ return new()
+
+func create_inner_instance() -> InnerClass:
+ return InnerClass.create_instance()
+
+func test():
+ var instance = create_inner_instance()
+ print(instance.val)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.out b/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.out
new file mode 100644
index 0000000000..1ccb591560
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/inner_class_as_return_type.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+OK
diff --git a/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.gd b/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.gd
new file mode 100644
index 0000000000..5f73064cc0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.gd
@@ -0,0 +1,5 @@
+const preloaded : GDScript = preload("gdscript_to_preload.gd")
+
+func test():
+ var preloaded_instance: preloaded = preloaded.new()
+ print(preloaded_instance.something())
diff --git a/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.out b/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.out
new file mode 100644
index 0000000000..1ccb591560
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+OK
diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp
index 52e9d92223..e54f055f2b 100644
--- a/modules/gdscript/tests/test_gdscript.cpp
+++ b/modules/gdscript/tests/test_gdscript.cpp
@@ -56,7 +56,7 @@ static void test_tokenizer(const String &p_code, const Vector<String> &p_lines)
int tab_size = 4;
#ifdef TOOLS_ENABLED
if (EditorSettings::get_singleton()) {
- tab_size = EditorSettings::get_singleton()->get_setting("text_editor/indent/size");
+ tab_size = EditorSettings::get_singleton()->get_setting("text_editor/behavior/indent/size");
}
#endif // TOOLS_ENABLED
String tab = String(" ").repeat(tab_size);
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index be44f66423..ff0579a11c 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -43,6 +43,7 @@
#include "gltf_texture.h"
#include "core/crypto/crypto_core.h"
+#include "core/error/error_macros.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/io/json.h"
@@ -4469,9 +4470,9 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) {
const Dictionary &spot = d["spot"];
light->inner_cone_angle = spot["innerConeAngle"];
light->outer_cone_angle = spot["outerConeAngle"];
- ERR_FAIL_COND_V_MSG(light->inner_cone_angle >= light->outer_cone_angle, ERR_PARSE_ERROR, "The inner angle must be smaller than the outer angle.");
+ ERR_CONTINUE_MSG(light->inner_cone_angle >= light->outer_cone_angle, "The inner angle must be smaller than the outer angle.");
} else if (type != "point" && type != "directional") {
- ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "Light type is unknown.");
+ ERR_CONTINUE_MSG(ERR_PARSE_ERROR, "Light type is unknown.");
}
state->lights.push_back(light);
@@ -5380,15 +5381,16 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent
// and attach it to the bone_attachment
scene_parent = bone_attachment;
}
-
- // We still have not managed to make a node
if (gltf_node->mesh >= 0) {
current_node = _generate_mesh_instance(state, scene_parent, node_index);
} else if (gltf_node->camera >= 0) {
current_node = _generate_camera(state, scene_parent, node_index);
} else if (gltf_node->light >= 0) {
current_node = _generate_light(state, scene_parent, node_index);
- } else {
+ }
+
+ // We still have not managed to make a node.
+ if (!current_node) {
current_node = _generate_spatial(state, scene_parent, node_index);
}
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index 3e8ea19045..7a826897a9 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -346,8 +346,8 @@ private:
Error _serialize_extensions(Ref<GLTFState> state) const;
public:
- // http://www.itu.int/rec/R-REC-BT.601
- // http://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.601-7-201103-I!!PDF-E.pdf
+ // https://www.itu.int/rec/R-REC-BT.601
+ // https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.601-7-201103-I!!PDF-E.pdf
static constexpr float R_BRIGHTNESS_COEFF = 0.299f;
static constexpr float G_BRIGHTNESS_COEFF = 0.587f;
static constexpr float B_BRIGHTNESS_COEFF = 0.114f;
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index 8ea7384658..c1dbe63628 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -53,18 +53,18 @@
The orientation of the cell at the given grid coordinates. [code]-1[/code] is returned if the cell is empty.
</description>
</method>
- <method name="get_collision_layer_bit" qualifiers="const">
+ <method name="get_collision_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns an individual bit on the [member collision_layer].
+ Returns whether or not the specified layer of the [member collision_layer] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="get_collision_mask_bit" qualifiers="const">
+ <method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns an individual bit on the [member collision_mask].
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="get_meshes">
@@ -119,20 +119,20 @@
<description>
</description>
</method>
- <method name="set_collision_layer_bit">
+ <method name="set_collision_layer_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- Sets an individual bit on the [member collision_layer].
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_layer], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="set_collision_mask_bit">
+ <method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- Sets an individual bit on the [member collision_mask].
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="world_to_map" qualifiers="const">
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index fea513c820..8e8b6f14ad 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -151,36 +151,40 @@ uint32_t GridMap::get_collision_mask() const {
return collision_mask;
}
-void GridMap::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
- uint32_t mask = get_collision_mask();
+void GridMap::set_collision_layer_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
+ uint32_t collision_layer = get_collision_layer();
if (p_value) {
- mask |= 1 << p_bit;
+ collision_layer |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ collision_layer &= ~(1 << (p_layer_number - 1));
}
- set_collision_mask(mask);
+ set_collision_layer(collision_layer);
}
-bool GridMap::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+bool GridMap::get_collision_layer_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_layer() & (1 << (p_layer_number - 1));
}
-void GridMap::set_collision_layer_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
- uint32_t layer = get_collision_layer();
+void GridMap::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
+ uint32_t mask = get_collision_mask();
if (p_value) {
- layer |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- layer &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
- set_collision_layer(layer);
+ set_collision_mask(mask);
}
-bool GridMap::get_collision_layer_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
- return get_collision_layer() & (1 << p_bit);
+bool GridMap::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
void GridMap::set_bake_navigation(bool p_bake_navigation) {
@@ -794,11 +798,11 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &GridMap::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &GridMap::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &GridMap::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &GridMap::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &GridMap::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &GridMap::get_collision_mask_value);
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &GridMap::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &GridMap::get_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &GridMap::set_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &GridMap::get_collision_layer_value);
ClassDB::bind_method(D_METHOD("set_bake_navigation", "bake_navigation"), &GridMap::set_bake_navigation);
ClassDB::bind_method(D_METHOD("is_baking_navigation"), &GridMap::is_baking_navigation);
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index 8cd82e1f4c..879489fc70 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -217,11 +217,11 @@ public:
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
+ void set_collision_layer_value(int p_layer_number, bool p_value);
+ bool get_collision_layer_value(int p_layer_number) const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void set_bake_navigation(bool p_bake_navigation);
bool is_baking_navigation();
diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp
index f101c43e89..2331a12d0f 100644
--- a/modules/gridmap/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/grid_map_editor_plugin.cpp
@@ -790,7 +790,7 @@ void GridMapEditor::_sbox_input(const Ref<InputEvent> &p_ie) {
if (k.is_valid() && (k->get_keycode() == KEY_UP || k->get_keycode() == KEY_DOWN || k->get_keycode() == KEY_PAGEUP || k->get_keycode() == KEY_PAGEDOWN)) {
// Forward the key input to the ItemList so it can be scrolled
- mesh_library_palette->call("_gui_input", k);
+ mesh_library_palette->gui_input(k);
search_box->accept_event();
}
}
diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h
index 29ce0f92c8..0c05dc1ebb 100644
--- a/modules/mobile_vr/mobile_vr_interface.h
+++ b/modules/mobile_vr/mobile_vr_interface.h
@@ -86,20 +86,20 @@ private:
Vector3 mag_next_max;
///@TODO a few support functions for trackers, most are math related and should likely be moved elsewhere
- float floor_decimals(float p_value, float p_decimals) {
+ float floor_decimals(const float p_value, const float p_decimals) {
float power_of_10 = pow(10.0f, p_decimals);
return floor(p_value * power_of_10) / power_of_10;
};
- Vector3 floor_decimals(const Vector3 &p_vector, float p_decimals) {
+ Vector3 floor_decimals(const Vector3 &p_vector, const float p_decimals) {
return Vector3(floor_decimals(p_vector.x, p_decimals), floor_decimals(p_vector.y, p_decimals), floor_decimals(p_vector.z, p_decimals));
};
- Vector3 low_pass(const Vector3 &p_vector, const Vector3 &p_last_vector, float p_factor) {
+ Vector3 low_pass(const Vector3 &p_vector, const Vector3 &p_last_vector, const float p_factor) {
return p_vector + (p_factor * (p_last_vector - p_vector));
};
- Vector3 scrub(const Vector3 &p_vector, const Vector3 &p_last_vector, float p_decimals, float p_factor) {
+ Vector3 scrub(const Vector3 &p_vector, const Vector3 &p_last_vector, const float p_decimals, const float p_factor) {
return low_pass(floor_decimals(p_vector, p_decimals), p_last_vector, p_factor);
};
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 520262c0eb..1f7f1390ea 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -82,6 +82,12 @@ static bool _create_project_solution_if_needed() {
CSharpLanguage *CSharpLanguage::singleton = nullptr;
+GDNativeInstanceBindingCallbacks CSharpLanguage::_instance_binding_callbacks = {
+ &_instance_binding_create_callback,
+ &_instance_binding_free_callback,
+ &_instance_binding_reference_callback
+};
+
String CSharpLanguage::get_name() const {
return "C#";
}
@@ -542,10 +548,10 @@ String CSharpLanguage::make_function(const String &, const String &, const Packe
String CSharpLanguage::_get_indentation() const {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
- bool use_space_indentation = EDITOR_DEF("text_editor/indent/type", 0);
+ bool use_space_indentation = EDITOR_DEF("text_editor/behavior/indent/type", 0);
if (use_space_indentation) {
- int indent_size = EDITOR_DEF("text_editor/indent/size", 4);
+ int indent_size = EDITOR_DEF("text_editor/behavior/indent/size", 4);
String space_indent = "";
for (int i = 0; i < indent_size; i++) {
@@ -1444,46 +1450,46 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b
return true;
}
-void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) {
- MutexLock lock(language_bind_mutex);
+Map<Object *, CSharpScriptBinding>::Element *CSharpLanguage::insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding) {
+ return script_bindings.insert(p_object, p_script_binding);
+}
+
+void *CSharpLanguage::_instance_binding_create_callback(void *, void *p_instance) {
+ CSharpLanguage *csharp_lang = CSharpLanguage::get_singleton();
- Map<Object *, CSharpScriptBinding>::Element *match = script_bindings.find(p_object);
+ MutexLock lock(csharp_lang->language_bind_mutex);
+
+ Map<Object *, CSharpScriptBinding>::Element *match = csharp_lang->script_bindings.find((Object *)p_instance);
if (match) {
return (void *)match;
}
CSharpScriptBinding script_binding;
- if (!setup_csharp_script_binding(script_binding, p_object)) {
- return nullptr;
- }
-
- return (void *)insert_script_binding(p_object, script_binding);
+ return (void *)csharp_lang->insert_script_binding((Object *)p_instance, script_binding);
}
-Map<Object *, CSharpScriptBinding>::Element *CSharpLanguage::insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding) {
- return script_bindings.insert(p_object, p_script_binding);
-}
+void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_binding) {
+ CSharpLanguage *csharp_lang = CSharpLanguage::get_singleton();
-void CSharpLanguage::free_instance_binding_data(void *p_data) {
if (GDMono::get_singleton() == nullptr) {
#ifdef DEBUG_ENABLED
- CRASH_COND(!script_bindings.is_empty());
+ CRASH_COND(!csharp_lang->script_bindings.is_empty());
#endif
// Mono runtime finalized, all the gchandle bindings were already released
return;
}
- if (finalizing) {
+ if (csharp_lang->finalizing) {
return; // inside CSharpLanguage::finish(), all the gchandle bindings are released there
}
GD_MONO_ASSERT_THREAD_ATTACHED;
{
- MutexLock lock(language_bind_mutex);
+ MutexLock lock(csharp_lang->language_bind_mutex);
- Map<Object *, CSharpScriptBinding>::Element *data = (Map<Object *, CSharpScriptBinding>::Element *)p_data;
+ Map<Object *, CSharpScriptBinding>::Element *data = (Map<Object *, CSharpScriptBinding>::Element *)p_binding;
CSharpScriptBinding &script_binding = data->value();
@@ -1497,92 +1503,110 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) {
script_binding.gchandle.release();
}
- script_bindings.erase(data);
+ csharp_lang->script_bindings.erase(data);
}
}
-void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
-#if 0
- RefCounted *rc_owner = Object::cast_to<RefCounted>(p_object);
+GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token, void *p_binding, GDNativeBool p_reference) {
+ CRASH_COND(!p_binding);
+
+ CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)p_binding)->get();
+
+ RefCounted *rc_owner = Object::cast_to<RefCounted>(script_binding.owner);
#ifdef DEBUG_ENABLED
CRASH_COND(!rc_owner);
- CRASH_COND(!p_object->has_script_instance_binding(get_language_index()));
#endif
- void *data = p_object->get_script_instance_binding(get_language_index());
- CRASH_COND(!data);
-
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
MonoGCHandleData &gchandle = script_binding.gchandle;
+ int refcount = rc_owner->reference_get_count();
+
if (!script_binding.inited) {
- return;
+ return refcount == 0;
}
- if (rc_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
- GD_MONO_SCOPE_THREAD_ATTACH;
+ if (p_reference) {
+ // Refcount incremented
+ if (refcount > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ GD_MONO_SCOPE_THREAD_ATTACH;
- // The reference count was increased after the managed side was the only one referencing our owner.
- // This means the owner is being referenced again by the unmanaged side,
- // so the owner must hold the managed side alive again to avoid it from being GCed.
+ // The reference count was increased after the managed side was the only one referencing our owner.
+ // This means the owner is being referenced again by the unmanaged side,
+ // so the owner must hold the managed side alive again to avoid it from being GCed.
+
+ MonoObject *target = gchandle.get_target();
+ if (!target) {
+ return false; // Called after the managed side was collected, so nothing to do here
+ }
- MonoObject *target = gchandle.get_target();
- if (!target) {
- return; // Called after the managed side was collected, so nothing to do here
+ // Release the current weak handle and replace it with a strong handle.
+ MonoGCHandleData strong_gchandle = MonoGCHandleData::new_strong_handle(target);
+ gchandle.release();
+ gchandle = strong_gchandle;
}
- // Release the current weak handle and replace it with a strong handle.
- MonoGCHandleData strong_gchandle = MonoGCHandleData::new_strong_handle(target);
- gchandle.release();
- gchandle = strong_gchandle;
- }
-#endif
-}
+ return false;
+ } else {
+ // Refcount decremented
+ if (refcount == 1 && !gchandle.is_released() && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ GD_MONO_SCOPE_THREAD_ATTACH;
-bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
-#if 0
- RefCounted *rc_owner = Object::cast_to<RefCounted>(p_object);
+ // If owner owner is no longer referenced by the unmanaged side,
+ // the managed instance takes responsibility of deleting the owner when GCed.
-#ifdef DEBUG_ENABLED
- CRASH_COND(!rc_owner);
- CRASH_COND(!p_object->has_script_instance_binding(get_language_index()));
-#endif
+ MonoObject *target = gchandle.get_target();
+ if (!target) {
+ return refcount == 0; // Called after the managed side was collected, so nothing to do here
+ }
- void *data = p_object->get_script_instance_binding(get_language_index());
- CRASH_COND(!data);
+ // Release the current strong handle and replace it with a weak handle.
+ MonoGCHandleData weak_gchandle = MonoGCHandleData::new_weak_handle(target);
+ gchandle.release();
+ gchandle = weak_gchandle;
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
- MonoGCHandleData &gchandle = script_binding.gchandle;
-
- int refcount = rc_owner->reference_get_count();
+ return false;
+ }
- if (!script_binding.inited) {
return refcount == 0;
}
+}
- if (refcount == 1 && !gchandle.is_released() && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
- GD_MONO_SCOPE_THREAD_ATTACH;
+void *CSharpLanguage::get_instance_binding(Object *p_object) {
+ void *binding = p_object->get_instance_binding(get_singleton(), &_instance_binding_callbacks);
- // If owner owner is no longer referenced by the unmanaged side,
- // the managed instance takes responsibility of deleting the owner when GCed.
+ // Initially this was in `_instance_binding_create_callback`. However, after the new instance
+ // binding re-write it was resulting in a deadlock in `_instance_binding_reference`, as
+ // `setup_csharp_script_binding` may call `reference()`. It was moved here outside to fix that.
- MonoObject *target = gchandle.get_target();
- if (!target) {
- return refcount == 0; // Called after the managed side was collected, so nothing to do here
- }
+ if (binding) {
+ CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)binding)->value();
- // Release the current strong handle and replace it with a weak handle.
- MonoGCHandleData weak_gchandle = MonoGCHandleData::new_weak_handle(target);
- gchandle.release();
- gchandle = weak_gchandle;
+ if (!script_binding.inited) {
+ MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex());
- return false;
+ if (!script_binding.inited) { // Another thread may have set it up
+ CSharpLanguage::get_singleton()->setup_csharp_script_binding(script_binding, p_object);
+ }
+ }
}
- return refcount == 0;
+ return binding;
+}
+
+void *CSharpLanguage::get_existing_instance_binding(Object *p_object) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(p_object->has_instance_binding(p_object));
#endif
- return false;
+ return p_object->get_instance_binding(get_singleton(), &_instance_binding_callbacks);
+}
+
+void CSharpLanguage::set_instance_binding(Object *p_object, void *p_binding) {
+ p_object->set_instance_binding(get_singleton(), p_binding, &_instance_binding_callbacks);
+}
+
+bool CSharpLanguage::has_instance_binding(Object *p_object) {
+ return p_object->has_instance_binding(get_singleton());
}
CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle) {
@@ -2260,29 +2284,16 @@ CSharpInstance::~CSharpInstance() {
// Otherwise, the unsafe reference debug checks will incorrectly detect a bug.
bool die = _unreference_owner_unsafe();
CRASH_COND(die); // `owner_keep_alive` holds a reference, so it can't die
-#if 0
- void *data = owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
-
+ void *data = CSharpLanguage::get_instance_binding(owner);
CRASH_COND(data == nullptr);
-
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
-
- if (!script_binding.inited) {
- MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex());
-
- if (!script_binding.inited) { // Other thread may have set it up
- // Already had a binding that needs to be setup
- CSharpLanguage::get_singleton()->setup_csharp_script_binding(script_binding, owner);
- CRASH_COND(!script_binding.inited);
- }
- }
+ CRASH_COND(!script_binding.inited);
#ifdef DEBUG_ENABLED
// The "instance binding" holds a reference so the refcount should be at least 2 before `scope_keep_owner_alive` goes out of scope
CRASH_COND(rc_owner->reference_get_count() <= 1);
#endif
-#endif
}
if (script.is_valid() && owner) {
@@ -3100,10 +3111,10 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
// Hold it alive. Important if we have to dispose a script instance binding before creating the CSharpInstance.
ref = Ref<RefCounted>(static_cast<RefCounted *>(p_owner));
}
-#if 0
+
// If the object had a script instance binding, dispose it before adding the CSharpInstance
- if (p_owner->has_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index())) {
- void *data = p_owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
+ if (CSharpLanguage::has_instance_binding(p_owner)) {
+ void *data = CSharpLanguage::get_existing_instance_binding(p_owner);
CRASH_COND(data == nullptr);
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
@@ -3122,7 +3133,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
script_binding.inited = false;
}
}
-#endif
+
CSharpInstance *instance = memnew(CSharpInstance(Ref<CSharpScript>(this)));
instance->base_ref_counted = p_is_ref_counted;
instance->owner = p_owner;
@@ -3192,7 +3203,7 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Callable::Cal
CSharpInstance *instance = _create_instance(p_args, p_argcount, owner, r != nullptr, r_error);
if (!instance) {
if (ref.is_null()) {
- memdelete(owner); //no owner, sorry
+ memdelete(owner); // no owner, sorry
}
return Variant();
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index da6b60aee2..4552f376d0 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -401,7 +401,18 @@ class CSharpLanguage : public ScriptLanguage {
static void _editor_init_callback();
#endif
+ static void *_instance_binding_create_callback(void *p_token, void *p_instance);
+ static void _instance_binding_free_callback(void *p_token, void *p_instance, void *p_binding);
+ static GDNativeBool _instance_binding_reference_callback(void *p_token, void *p_binding, GDNativeBool p_reference);
+
+ static GDNativeInstanceBindingCallbacks _instance_binding_callbacks;
+
public:
+ static void *get_instance_binding(Object *p_object);
+ static void *get_existing_instance_binding(Object *p_object);
+ static void set_instance_binding(Object *p_object, void *p_binding);
+ static bool has_instance_binding(Object *p_object);
+
StringNameCache string_names;
const Mutex &get_language_bind_mutex() { return language_bind_mutex; }
@@ -507,12 +518,6 @@ public:
void thread_enter() override;
void thread_exit() override;
- // Don't use these. I'm watching you
- void *alloc_instance_binding_data(Object *p_object) override;
- void free_instance_binding_data(void *p_data) override;
- void refcount_incremented_instance_binding(Object *p_object) override;
- bool refcount_decremented_instance_binding(Object *p_object) override;
-
Map<Object *, CSharpScriptBinding>::Element *insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding);
bool setup_csharp_script_binding(CSharpScriptBinding &r_script_binding, Object *p_object);
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
index c380707587..25e260beed 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
@@ -285,7 +285,7 @@ namespace GodotTools.Build
break;
}
- buildLog.CursorSetLine(line);
+ buildLog.SetCaretLine(line);
}
public void RestartBuild()
@@ -384,7 +384,7 @@ namespace GodotTools.Build
buildLog = new TextEdit
{
- Readonly = true,
+ Editable = false,
SizeFlagsVertical = (int)SizeFlags.ExpandFill,
SizeFlagsHorizontal = (int)SizeFlags.ExpandFill // Avoid being squashed by the issues list
};
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
index 897f1b2822..5f35d506de 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
@@ -73,7 +73,7 @@ namespace GodotTools.Build
GD.PushError("Failed to setup Godot NuGet Offline Packages: " + e.Message);
}
- if (!BuildManager.BuildProjectBlocking("Debug", targets: new[] {"Rebuild"}))
+ if (!BuildManager.BuildProjectBlocking("Debug", targets: new[] { "Rebuild" }))
return; // Build failed
// Notify running game for hot-reload
@@ -92,7 +92,7 @@ namespace GodotTools.Build
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
return; // No solution to build
- BuildManager.BuildProjectBlocking("Debug", targets: new[] {"Clean"});
+ BuildManager.BuildProjectBlocking("Debug", targets: new[] { "Clean" });
}
private void ViewLogToggled(bool pressed) => BuildOutputView.LogVisible = pressed;
@@ -129,10 +129,10 @@ namespace GodotTools.Build
RectMinSize = new Vector2(0, 228) * EditorScale;
SizeFlagsVertical = (int)SizeFlags.ExpandFill;
- var toolBarHBox = new HBoxContainer {SizeFlagsHorizontal = (int)SizeFlags.ExpandFill};
+ var toolBarHBox = new HBoxContainer { SizeFlagsHorizontal = (int)SizeFlags.ExpandFill };
AddChild(toolBarHBox);
- buildMenuBtn = new MenuButton {Text = "Build", Icon = GetThemeIcon("Play", "EditorIcons")};
+ buildMenuBtn = new MenuButton { Text = "Build", Icon = GetThemeIcon("Play", "EditorIcons") };
toolBarHBox.AddChild(buildMenuBtn);
var buildMenu = buildMenuBtn.GetPopup();
@@ -183,10 +183,14 @@ namespace GodotTools.Build
{
base._Notification(what);
- if (what == NotificationThemeChanged) {
- buildMenuBtn.Icon = GetThemeIcon("Play", "EditorIcons");
- errorsBtn.Icon = GetThemeIcon("StatusError", "EditorIcons");
- warningsBtn.Icon = GetThemeIcon("NodeWarning", "EditorIcons");
+ if (what == NotificationThemeChanged)
+ {
+ if (buildMenuBtn != null)
+ buildMenuBtn.Icon = GetThemeIcon("Play", "EditorIcons");
+ if (errorsBtn != null)
+ errorsBtn.Icon = GetThemeIcon("StatusError", "EditorIcons");
+ if (warningsBtn != null)
+ warningsBtn.Icon = GetThemeIcon("NodeWarning", "EditorIcons");
}
}
}
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 632f7d61cc..7fdef8ff45 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -3130,8 +3130,18 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
case Variant::CALLABLE:
+ ERR_FAIL_COND_V_MSG(r_iarg.type.cname != name_cache.type_Callable, false,
+ "Parameter of type '" + String(r_iarg.type.cname) + "' cannot have a default value of type '" + String(name_cache.type_Callable) + "'.");
+ ERR_FAIL_COND_V_MSG(!p_val.is_zero(), false,
+ "Parameter of type '" + String(r_iarg.type.cname) + "' can only have null/zero as the default value.");
+ r_iarg.default_argument = "default";
+ break;
case Variant::SIGNAL:
- CRASH_NOW_MSG("Parameter of type '" + String(r_iarg.type.cname) + "' cannot have a default value.");
+ ERR_FAIL_COND_V_MSG(r_iarg.type.cname != name_cache.type_Signal, false,
+ "Parameter of type '" + String(r_iarg.type.cname) + "' cannot have a default value of type '" + String(name_cache.type_Signal) + "'.");
+ ERR_FAIL_COND_V_MSG(!p_val.is_zero(), false,
+ "Parameter of type '" + String(r_iarg.type.cname) + "' can only have null/zero as the default value.");
+ r_iarg.default_argument = "default";
break;
default:
CRASH_NOW_MSG("Unexpected Variant type: " + itos(p_val.get_type()));
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index a649181b20..8a85a1acbd 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -536,6 +536,8 @@ class BindingsGenerator {
StringName type_Object = StaticCString::create("Object");
StringName type_RefCounted = StaticCString::create("RefCounted");
StringName type_RID = StaticCString::create("RID");
+ StringName type_Callable = StaticCString::create("Callable");
+ StringName type_Signal = StaticCString::create("Signal");
StringName type_String = StaticCString::create("String");
StringName type_StringName = StaticCString::create("StringName");
StringName type_NodePath = StaticCString::create("NodePath");
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index 8164f459ca..6692a6efec 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -241,7 +241,7 @@ MonoBoolean godot_icall_Internal_IsAssembliesReloadingNeeded() {
void godot_icall_Internal_ReloadAssemblies(MonoBoolean p_soft_reload) {
#ifdef GD_MONO_HOT_RELOAD
- _GodotSharp::get_singleton()->call_deferred(SNAME("_reload_assemblies"), (bool)p_soft_reload);
+ mono_bind::GodotSharp::get_singleton()->call_deferred(SNAME("_reload_assemblies"), (bool)p_soft_reload);
#endif
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
index 8271b43b48..968f853c2d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
@@ -207,7 +207,7 @@ namespace Godot
}
}
- public Quaternion RotationQuaternion()
+ public Quaternion GetRotationQuaternion()
{
Basis orthonormalizedBasis = Orthonormalized();
real_t det = orthonormalizedBasis.Determinant();
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
index 213fc181c1..61a34bfc87 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Collections;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Diagnostics.CodeAnalysis;
namespace Godot.Collections
{
@@ -25,6 +26,11 @@ namespace Godot.Collections
}
}
+ /// <summary>
+ /// Wrapper around Godot's Dictionary class, a dictionary of Variant
+ /// typed elements allocated in the engine in C++. Useful when
+ /// interfacing with the engine.
+ /// </summary>
public class Dictionary :
IDictionary,
IDisposable
@@ -32,11 +38,19 @@ namespace Godot.Collections
DictionarySafeHandle safeHandle;
bool disposed = false;
+ /// <summary>
+ /// Constructs a new empty <see cref="Dictionary"/>.
+ /// </summary>
public Dictionary()
{
safeHandle = new DictionarySafeHandle(godot_icall_Dictionary_Ctor());
}
+ /// <summary>
+ /// Constructs a new <see cref="Dictionary"/> from the given dictionary's elements.
+ /// </summary>
+ /// <param name="dictionary">The dictionary to construct from.</param>
+ /// <returns>A new Godot Dictionary.</returns>
public Dictionary(IDictionary dictionary) : this()
{
if (dictionary == null)
@@ -64,6 +78,9 @@ namespace Godot.Collections
return safeHandle.DangerousGetHandle();
}
+ /// <summary>
+ /// Disposes of this <see cref="Dictionary"/>.
+ /// </summary>
public void Dispose()
{
if (disposed)
@@ -78,6 +95,11 @@ namespace Godot.Collections
disposed = true;
}
+ /// <summary>
+ /// Duplicates this <see cref="Dictionary"/>.
+ /// </summary>
+ /// <param name="deep">If <see langword="true"/>, performs a deep copy.</param>
+ /// <returns>A new Godot Dictionary.</returns>
public Dictionary Duplicate(bool deep = false)
{
return new Dictionary(godot_icall_Dictionary_Duplicate(GetPtr(), deep));
@@ -85,6 +107,9 @@ namespace Godot.Collections
// IDictionary
+ /// <summary>
+ /// Gets the collection of keys in this <see cref="Dictionary"/>.
+ /// </summary>
public ICollection Keys
{
get
@@ -94,6 +119,9 @@ namespace Godot.Collections
}
}
+ /// <summary>
+ /// Gets the collection of elements in this <see cref="Dictionary"/>.
+ /// </summary>
public ICollection Values
{
get
@@ -103,47 +131,88 @@ namespace Godot.Collections
}
}
- public bool IsFixedSize => false;
+ private (Array keys, Array values, int count) GetKeyValuePairs()
+ {
+ int count = godot_icall_Dictionary_KeyValuePairs(GetPtr(), out IntPtr keysHandle, out IntPtr valuesHandle);
+ Array keys = new Array(new ArraySafeHandle(keysHandle));
+ Array values = new Array(new ArraySafeHandle(valuesHandle));
+ return (keys, values, count);
+ }
+
+ bool IDictionary.IsFixedSize => false;
- public bool IsReadOnly => false;
+ bool IDictionary.IsReadOnly => false;
+ /// <summary>
+ /// Returns the object at the given <paramref name="key"/>.
+ /// </summary>
+ /// <value>The object at the given <paramref name="key"/>.</value>
public object this[object key]
{
get => godot_icall_Dictionary_GetValue(GetPtr(), key);
set => godot_icall_Dictionary_SetValue(GetPtr(), key, value);
}
+ /// <summary>
+ /// Adds an object <paramref name="value"/> at key <paramref name="key"/>
+ /// to this <see cref="Dictionary"/>.
+ /// </summary>
+ /// <param name="key">The key at which to add the object.</param>
+ /// <param name="value">The object to add.</param>
public void Add(object key, object value) => godot_icall_Dictionary_Add(GetPtr(), key, value);
+ /// <summary>
+ /// Erases all items from this <see cref="Dictionary"/>.
+ /// </summary>
public void Clear() => godot_icall_Dictionary_Clear(GetPtr());
+ /// <summary>
+ /// Checks if this <see cref="Dictionary"/> contains the given key.
+ /// </summary>
+ /// <param name="key">The key to look for.</param>
+ /// <returns>Whether or not this dictionary contains the given key.</returns>
public bool Contains(object key) => godot_icall_Dictionary_ContainsKey(GetPtr(), key);
+ /// <summary>
+ /// Gets an enumerator for this <see cref="Dictionary"/>.
+ /// </summary>
+ /// <returns>An enumerator.</returns>
public IDictionaryEnumerator GetEnumerator() => new DictionaryEnumerator(this);
+ /// <summary>
+ /// Removes an element from this <see cref="Dictionary"/> by key.
+ /// </summary>
+ /// <param name="key">The key of the element to remove.</param>
public void Remove(object key) => godot_icall_Dictionary_RemoveKey(GetPtr(), key);
// ICollection
- public object SyncRoot => this;
+ object ICollection.SyncRoot => this;
- public bool IsSynchronized => false;
+ bool ICollection.IsSynchronized => false;
+ /// <summary>
+ /// Returns the number of elements in this <see cref="Dictionary"/>.
+ /// This is also known as the size or length of the dictionary.
+ /// </summary>
+ /// <returns>The number of elements.</returns>
public int Count => godot_icall_Dictionary_Count(GetPtr());
+ /// <summary>
+ /// Copies the elements of this <see cref="Dictionary"/> to the given
+ /// untyped C# array, starting at the given index.
+ /// </summary>
+ /// <param name="array">The array to copy to.</param>
+ /// <param name="index">The index to start at.</param>
public void CopyTo(System.Array array, int index)
{
- // TODO Can be done with single internal call
-
if (array == null)
throw new ArgumentNullException(nameof(array), "Value cannot be null.");
if (index < 0)
throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension.");
- Array keys = (Array)Keys;
- Array values = (Array)Values;
- int count = Count;
+ var (keys, values, count) = GetKeyValuePairs();
if (array.Length < (index + count))
throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
@@ -161,24 +230,39 @@ namespace Godot.Collections
private class DictionaryEnumerator : IDictionaryEnumerator
{
- Array keys;
- Array values;
- int count;
- int index = -1;
+ private readonly Dictionary dictionary;
+ private readonly int count;
+ private int index = -1;
+ private bool dirty = true;
+
+ private DictionaryEntry entry;
public DictionaryEnumerator(Dictionary dictionary)
{
- // TODO 3 internal calls, can reduce to 1
- keys = (Array)dictionary.Keys;
- values = (Array)dictionary.Values;
+ this.dictionary = dictionary;
count = dictionary.Count;
}
public object Current => Entry;
- public DictionaryEntry Entry =>
- // TODO 2 internal calls, can reduce to 1
- new DictionaryEntry(keys[index], values[index]);
+ public DictionaryEntry Entry
+ {
+ get
+ {
+ if (dirty)
+ {
+ UpdateEntry();
+ }
+ return entry;
+ }
+ }
+
+ private void UpdateEntry()
+ {
+ dirty = false;
+ godot_icall_Dictionary_KeyValuePairAt(dictionary.GetPtr(), index, out object key, out object value);
+ entry = new DictionaryEntry(key, value);
+ }
public object Key => Entry.Key;
@@ -187,15 +271,21 @@ namespace Godot.Collections
public bool MoveNext()
{
index++;
+ dirty = true;
return index < count;
}
public void Reset()
{
index = -1;
+ dirty = true;
}
}
+ /// <summary>
+ /// Converts this <see cref="Dictionary"/> to a string.
+ /// </summary>
+ /// <returns>A string representation of this dictionary.</returns>
public override string ToString()
{
return godot_icall_Dictionary_ToString(GetPtr());
@@ -226,6 +316,12 @@ namespace Godot.Collections
internal extern static int godot_icall_Dictionary_Count(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static int godot_icall_Dictionary_KeyValuePairs(IntPtr ptr, out IntPtr keys, out IntPtr values);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_Dictionary_KeyValuePairAt(IntPtr ptr, int index, out object key, out object value);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value);
[MethodImpl(MethodImplOptions.InternalCall)]
@@ -259,10 +355,18 @@ namespace Godot.Collections
internal extern static string godot_icall_Dictionary_ToString(IntPtr ptr);
}
+ /// <summary>
+ /// Typed wrapper around Godot's Dictionary class, a dictionary of Variant
+ /// typed elements allocated in the engine in C++. Useful when
+ /// interfacing with the engine. Otherwise prefer .NET collections
+ /// such as <see cref="System.Collections.Generic.Dictionary{TKey, TValue}"/>.
+ /// </summary>
+ /// <typeparam name="TKey">The type of the dictionary's keys.</typeparam>
+ /// <typeparam name="TValue">The type of the dictionary's values.</typeparam>
public class Dictionary<TKey, TValue> :
IDictionary<TKey, TValue>
{
- Dictionary objectDict;
+ private readonly Dictionary objectDict;
internal static int valTypeEncoding;
internal static IntPtr valTypeClass;
@@ -272,11 +376,19 @@ namespace Godot.Collections
Dictionary.godot_icall_Dictionary_Generic_GetValueTypeInfo(typeof(TValue), out valTypeEncoding, out valTypeClass);
}
+ /// <summary>
+ /// Constructs a new empty <see cref="Dictionary{TKey, TValue}"/>.
+ /// </summary>
public Dictionary()
{
objectDict = new Dictionary();
}
+ /// <summary>
+ /// Constructs a new <see cref="Dictionary{TKey, TValue}"/> from the given dictionary's elements.
+ /// </summary>
+ /// <param name="dictionary">The dictionary to construct from.</param>
+ /// <returns>A new Godot Dictionary.</returns>
public Dictionary(IDictionary<TKey, TValue> dictionary)
{
objectDict = new Dictionary();
@@ -294,6 +406,11 @@ namespace Godot.Collections
}
}
+ /// <summary>
+ /// Constructs a new <see cref="Dictionary{TKey, TValue}"/> from the given dictionary's elements.
+ /// </summary>
+ /// <param name="dictionary">The dictionary to construct from.</param>
+ /// <returns>A new Godot Dictionary.</returns>
public Dictionary(Dictionary dictionary)
{
objectDict = dictionary;
@@ -309,6 +426,10 @@ namespace Godot.Collections
objectDict = new Dictionary(handle);
}
+ /// <summary>
+ /// Converts this typed <see cref="Dictionary{TKey, TValue}"/> to an untyped <see cref="Dictionary"/>.
+ /// </summary>
+ /// <param name="from">The typed dictionary to convert.</param>
public static explicit operator Dictionary(Dictionary<TKey, TValue> from)
{
return from.objectDict;
@@ -319,6 +440,11 @@ namespace Godot.Collections
return objectDict.GetPtr();
}
+ /// <summary>
+ /// Duplicates this <see cref="Dictionary{TKey, TValue}"/>.
+ /// </summary>
+ /// <param name="deep">If <see langword="true"/>, performs a deep copy.</param>
+ /// <returns>A new Godot Dictionary.</returns>
public Dictionary<TKey, TValue> Duplicate(bool deep = false)
{
return new Dictionary<TKey, TValue>(objectDict.Duplicate(deep));
@@ -326,12 +452,19 @@ namespace Godot.Collections
// IDictionary<TKey, TValue>
+ /// <summary>
+ /// Returns the value at the given <paramref name="key"/>.
+ /// </summary>
+ /// <value>The value at the given <paramref name="key"/>.</value>
public TValue this[TKey key]
{
get { return (TValue)Dictionary.godot_icall_Dictionary_GetValue_Generic(objectDict.GetPtr(), key, valTypeEncoding, valTypeClass); }
set { objectDict[key] = value; }
}
+ /// <summary>
+ /// Gets the collection of keys in this <see cref="Dictionary{TKey, TValue}"/>.
+ /// </summary>
public ICollection<TKey> Keys
{
get
@@ -341,6 +474,9 @@ namespace Godot.Collections
}
}
+ /// <summary>
+ /// Gets the collection of elements in this <see cref="Dictionary{TKey, TValue}"/>.
+ /// </summary>
public ICollection<TValue> Values
{
get
@@ -350,56 +486,93 @@ namespace Godot.Collections
}
}
+ private KeyValuePair<TKey, TValue> GetKeyValuePair(int index)
+ {
+ Dictionary.godot_icall_Dictionary_KeyValuePairAt(GetPtr(), index, out object key, out object value);
+ return new KeyValuePair<TKey, TValue>((TKey)key, (TValue)value);
+ }
+
+ /// <summary>
+ /// Adds an object <paramref name="value"/> at key <paramref name="key"/>
+ /// to this <see cref="Dictionary{TKey, TValue}"/>.
+ /// </summary>
+ /// <param name="key">The key at which to add the object.</param>
+ /// <param name="value">The object to add.</param>
public void Add(TKey key, TValue value)
{
objectDict.Add(key, value);
}
+ /// <summary>
+ /// Checks if this <see cref="Dictionary{TKey, TValue}"/> contains the given key.
+ /// </summary>
+ /// <param name="key">The key to look for.</param>
+ /// <returns>Whether or not this dictionary contains the given key.</returns>
public bool ContainsKey(TKey key)
{
return objectDict.Contains(key);
}
+ /// <summary>
+ /// Removes an element from this <see cref="Dictionary{TKey, TValue}"/> by key.
+ /// </summary>
+ /// <param name="key">The key of the element to remove.</param>
public bool Remove(TKey key)
{
return Dictionary.godot_icall_Dictionary_RemoveKey(GetPtr(), key);
}
- public bool TryGetValue(TKey key, out TValue value)
+ /// <summary>
+ /// Gets the object at the given <paramref name="key"/>.
+ /// </summary>
+ /// <param name="key">The key of the element to get.</param>
+ /// <param name="value">The value at the given <paramref name="key"/>.</param>
+ /// <returns>If an object was found for the given <paramref name="key"/>.</returns>
+ public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
{
- object retValue;
- bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out retValue, valTypeEncoding, valTypeClass);
- value = found ? (TValue)retValue : default(TValue);
+ bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out object retValue, valTypeEncoding, valTypeClass);
+ value = found ? (TValue)retValue : default;
return found;
}
// ICollection<KeyValuePair<TKey, TValue>>
+ /// <summary>
+ /// Returns the number of elements in this <see cref="Dictionary{TKey, TValue}"/>.
+ /// This is also known as the size or length of the dictionary.
+ /// </summary>
+ /// <returns>The number of elements.</returns>
public int Count
{
get { return objectDict.Count; }
}
- public bool IsReadOnly
- {
- get { return objectDict.IsReadOnly; }
- }
+ bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false;
- public void Add(KeyValuePair<TKey, TValue> item)
+ void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
{
objectDict.Add(item.Key, item.Value);
}
+ /// <summary>
+ /// Erases all the items from this <see cref="Dictionary{TKey, TValue}"/>.
+ /// </summary>
public void Clear()
{
objectDict.Clear();
}
- public bool Contains(KeyValuePair<TKey, TValue> item)
+ bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
{
return objectDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value));
}
+ /// <summary>
+ /// Copies the elements of this <see cref="Dictionary{TKey, TValue}"/> to the given
+ /// untyped C# array, starting at the given index.
+ /// </summary>
+ /// <param name="array">The array to copy to.</param>
+ /// <param name="arrayIndex">The index to start at.</param>
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
if (array == null)
@@ -408,9 +581,6 @@ namespace Godot.Collections
if (arrayIndex < 0)
throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
- // TODO 3 internal calls, can reduce to 1
- Array<TKey> keys = (Array<TKey>)Keys;
- Array<TValue> values = (Array<TValue>)Values;
int count = Count;
if (array.Length < (arrayIndex + count))
@@ -418,13 +588,12 @@ namespace Godot.Collections
for (int i = 0; i < count; i++)
{
- // TODO 2 internal calls, can reduce to 1
- array[arrayIndex] = new KeyValuePair<TKey, TValue>(keys[i], values[i]);
+ array[arrayIndex] = GetKeyValuePair(i);
arrayIndex++;
}
}
- public bool Remove(KeyValuePair<TKey, TValue> item)
+ bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
{
return Dictionary.godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value);
;
@@ -432,17 +601,15 @@ namespace Godot.Collections
// IEnumerable<KeyValuePair<TKey, TValue>>
+ /// <summary>
+ /// Gets an enumerator for this <see cref="Dictionary{TKey, TValue}"/>.
+ /// </summary>
+ /// <returns>An enumerator.</returns>
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
- // TODO 3 internal calls, can reduce to 1
- Array<TKey> keys = (Array<TKey>)Keys;
- Array<TValue> values = (Array<TValue>)Values;
- int count = Count;
-
- for (int i = 0; i < count; i++)
+ for (int i = 0; i < Count; i++)
{
- // TODO 2 internal calls, can reduce to 1
- yield return new KeyValuePair<TKey, TValue>(keys[i], values[i]);
+ yield return GetKeyValuePair(i);
}
}
@@ -451,6 +618,10 @@ namespace Godot.Collections
return GetEnumerator();
}
+ /// <summary>
+ /// Converts this <see cref="Dictionary{TKey, TValue}"/> to a string.
+ /// </summary>
+ /// <returns>A string representation of this dictionary.</returns>
public override string ToString() => objectDict.ToString();
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
index a6f7a80d64..71d0593916 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
@@ -128,9 +128,9 @@ namespace Godot
return godot_icall_GD_randi_range(from, to);
}
- public static uint RandSeed(ulong seed, out ulong newSeed)
+ public static uint RandFromSeed(ref ulong seed)
{
- return godot_icall_GD_rand_seed(seed, out newSeed);
+ return godot_icall_GD_rand_seed(seed, out seed);
}
public static IEnumerable<int> Range(int end)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
index d9665cbf2b..6ce148d51e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
@@ -64,7 +64,7 @@ namespace Godot
/// <summary>
/// If the string is a path to a file, return the path to the file without the extension.
/// </summary>
- public static string BaseName(this string instance)
+ public static string GetBaseName(this string instance)
{
int index = instance.LastIndexOf('.');
@@ -339,7 +339,7 @@ namespace Godot
/// <summary>
/// If the string is a path to a file, return the extension.
/// </summary>
- public static string Extension(this string instance)
+ public static string GetExtension(this string instance)
{
int pos = instance.FindLast(".");
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
index 1b717fb4ae..afc6a65a45 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
@@ -124,11 +124,11 @@ namespace Godot
/* not sure if very "efficient" but good enough? */
Vector3 sourceScale = basis.Scale;
- Quaternion sourceRotation = basis.RotationQuaternion();
+ Quaternion sourceRotation = basis.GetRotationQuaternion();
Vector3 sourceLocation = origin;
Vector3 destinationScale = transform.basis.Scale;
- Quaternion destinationRotation = transform.basis.RotationQuaternion();
+ Quaternion destinationRotation = transform.basis.GetRotationQuaternion();
Vector3 destinationLocation = transform.origin;
var interpolated = new Transform3D();
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
index a99dff8432..6c5503a3bd 100644
--- a/modules/mono/glue/base_object_glue.cpp
+++ b/modules/mono/glue/base_object_glue.cpp
@@ -64,8 +64,8 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
return;
}
}
-#if 0
- void *data = p_ptr->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
+
+ void *data = CSharpLanguage::get_existing_instance_binding(p_ptr);
if (data) {
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
@@ -76,7 +76,6 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
}
}
}
-#endif
}
void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) {
@@ -85,7 +84,7 @@ void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoole
// This is only called with RefCounted derived classes
CRASH_COND(!Object::cast_to<RefCounted>(p_ptr));
#endif
-#if 0
+
RefCounted *rc = static_cast<RefCounted *>(p_ptr);
if (rc->get_script_instance()) {
@@ -113,7 +112,7 @@ void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoole
if (rc->unreference()) {
memdelete(rc);
} else {
- void *data = rc->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
+ void *data = CSharpLanguage::get_existing_instance_binding(rc);
if (data) {
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
@@ -125,7 +124,6 @@ void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoole
}
}
}
-#endif
}
void godot_icall_Object_ConnectEventSignals(Object *p_ptr) {
diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp
index 191f863350..86976de244 100644
--- a/modules/mono/glue/collections_glue.cpp
+++ b/modules/mono/glue/collections_glue.cpp
@@ -230,6 +230,19 @@ int32_t godot_icall_Dictionary_Count(Dictionary *ptr) {
return ptr->size();
}
+int32_t godot_icall_Dictionary_KeyValuePairs(Dictionary *ptr, Array **keys, Array **values) {
+ *keys = godot_icall_Dictionary_Keys(ptr);
+ *values = godot_icall_Dictionary_Values(ptr);
+ return godot_icall_Dictionary_Count(ptr);
+}
+
+void godot_icall_Dictionary_KeyValuePairAt(Dictionary *ptr, int index, MonoObject **key, MonoObject **value) {
+ Array *keys = godot_icall_Dictionary_Keys(ptr);
+ Array *values = godot_icall_Dictionary_Values(ptr);
+ *key = GDMonoMarshal::variant_to_mono_object(keys->get(index));
+ *value = GDMonoMarshal::variant_to_mono_object(values->get(index));
+}
+
void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) {
Variant varKey = GDMonoMarshal::mono_object_to_variant(key);
Variant *ret = ptr->getptr(varKey);
@@ -338,6 +351,8 @@ void godot_register_collections_icalls() {
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", godot_icall_Dictionary_Keys);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", godot_icall_Dictionary_Values);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", godot_icall_Dictionary_Count);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairs", godot_icall_Dictionary_KeyValuePairs);
+ GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairAt", godot_icall_Dictionary_KeyValuePairAt);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", godot_icall_Dictionary_Add);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", godot_icall_Dictionary_Clear);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", godot_icall_Dictionary_Contains);
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 299344bb93..1b1349a3a3 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -73,7 +73,7 @@
#endif
// TODO:
-// This has turn into a gigantic mess. There's too much going on here. Too much #ifdef as well.
+// This has turned into a gigantic mess. There's too much going on here. Too much #ifdef as well.
// It's just painful to read... It needs to be re-structured. Please, clean this up, future me.
GDMono *GDMono::singleton = nullptr;
@@ -1335,23 +1335,25 @@ GDMono::~GDMono() {
singleton = nullptr;
}
-_GodotSharp *_GodotSharp::singleton = nullptr;
+namespace mono_bind {
-void _GodotSharp::attach_thread() {
+GodotSharp *GodotSharp::singleton = nullptr;
+
+void GodotSharp::attach_thread() {
GDMonoUtils::attach_current_thread();
}
-void _GodotSharp::detach_thread() {
+void GodotSharp::detach_thread() {
GDMonoUtils::detach_current_thread();
}
-int32_t _GodotSharp::get_domain_id() {
+int32_t GodotSharp::get_domain_id() {
MonoDomain *domain = mono_domain_get();
ERR_FAIL_NULL_V(domain, -1);
return mono_domain_get_id(domain);
}
-int32_t _GodotSharp::get_scripts_domain_id() {
+int32_t GodotSharp::get_scripts_domain_id() {
ERR_FAIL_NULL_V_MSG(GDMono::get_singleton(),
-1, "The Mono runtime is not initialized");
MonoDomain *domain = GDMono::get_singleton()->get_scripts_domain();
@@ -1359,21 +1361,21 @@ int32_t _GodotSharp::get_scripts_domain_id() {
return mono_domain_get_id(domain);
}
-bool _GodotSharp::is_scripts_domain_loaded() {
+bool GodotSharp::is_scripts_domain_loaded() {
return GDMono::get_singleton() != nullptr &&
GDMono::get_singleton()->is_runtime_initialized() &&
GDMono::get_singleton()->get_scripts_domain() != nullptr;
}
-bool _GodotSharp::_is_domain_finalizing_for_unload(int32_t p_domain_id) {
+bool GodotSharp::_is_domain_finalizing_for_unload(int32_t p_domain_id) {
return is_domain_finalizing_for_unload(p_domain_id);
}
-bool _GodotSharp::is_domain_finalizing_for_unload(int32_t p_domain_id) {
+bool GodotSharp::is_domain_finalizing_for_unload(int32_t p_domain_id) {
return is_domain_finalizing_for_unload(mono_domain_get_by_id(p_domain_id));
}
-bool _GodotSharp::is_domain_finalizing_for_unload(MonoDomain *p_domain) {
+bool GodotSharp::is_domain_finalizing_for_unload(MonoDomain *p_domain) {
GDMono *gd_mono = GDMono::get_singleton();
ERR_FAIL_COND_V_MSG(!gd_mono || !gd_mono->is_runtime_initialized(),
@@ -1388,15 +1390,15 @@ bool _GodotSharp::is_domain_finalizing_for_unload(MonoDomain *p_domain) {
return mono_domain_is_unloading(p_domain);
}
-bool _GodotSharp::is_runtime_shutting_down() {
+bool GodotSharp::is_runtime_shutting_down() {
return mono_runtime_is_shutting_down();
}
-bool _GodotSharp::is_runtime_initialized() {
+bool GodotSharp::is_runtime_initialized() {
return GDMono::get_singleton() != nullptr && GDMono::get_singleton()->is_runtime_initialized();
}
-void _GodotSharp::_reload_assemblies(bool p_soft_reload) {
+void GodotSharp::_reload_assemblies(bool p_soft_reload) {
#ifdef GD_MONO_HOT_RELOAD
CRASH_COND(CSharpLanguage::get_singleton() == nullptr);
// This method may be called more than once with `call_deferred`, so we need to check
@@ -1407,24 +1409,26 @@ void _GodotSharp::_reload_assemblies(bool p_soft_reload) {
#endif
}
-void _GodotSharp::_bind_methods() {
- ClassDB::bind_method(D_METHOD("attach_thread"), &_GodotSharp::attach_thread);
- ClassDB::bind_method(D_METHOD("detach_thread"), &_GodotSharp::detach_thread);
+void GodotSharp::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("attach_thread"), &GodotSharp::attach_thread);
+ ClassDB::bind_method(D_METHOD("detach_thread"), &GodotSharp::detach_thread);
- ClassDB::bind_method(D_METHOD("get_domain_id"), &_GodotSharp::get_domain_id);
- ClassDB::bind_method(D_METHOD("get_scripts_domain_id"), &_GodotSharp::get_scripts_domain_id);
- ClassDB::bind_method(D_METHOD("is_scripts_domain_loaded"), &_GodotSharp::is_scripts_domain_loaded);
- ClassDB::bind_method(D_METHOD("is_domain_finalizing_for_unload", "domain_id"), &_GodotSharp::_is_domain_finalizing_for_unload);
+ ClassDB::bind_method(D_METHOD("get_domain_id"), &GodotSharp::get_domain_id);
+ ClassDB::bind_method(D_METHOD("get_scripts_domain_id"), &GodotSharp::get_scripts_domain_id);
+ ClassDB::bind_method(D_METHOD("is_scripts_domain_loaded"), &GodotSharp::is_scripts_domain_loaded);
+ ClassDB::bind_method(D_METHOD("is_domain_finalizing_for_unload", "domain_id"), &GodotSharp::_is_domain_finalizing_for_unload);
- ClassDB::bind_method(D_METHOD("is_runtime_shutting_down"), &_GodotSharp::is_runtime_shutting_down);
- ClassDB::bind_method(D_METHOD("is_runtime_initialized"), &_GodotSharp::is_runtime_initialized);
- ClassDB::bind_method(D_METHOD("_reload_assemblies"), &_GodotSharp::_reload_assemblies);
+ ClassDB::bind_method(D_METHOD("is_runtime_shutting_down"), &GodotSharp::is_runtime_shutting_down);
+ ClassDB::bind_method(D_METHOD("is_runtime_initialized"), &GodotSharp::is_runtime_initialized);
+ ClassDB::bind_method(D_METHOD("_reload_assemblies"), &GodotSharp::_reload_assemblies);
}
-_GodotSharp::_GodotSharp() {
+GodotSharp::GodotSharp() {
singleton = this;
}
-_GodotSharp::~_GodotSharp() {
+GodotSharp::~GodotSharp() {
singleton = nullptr;
}
+
+} // namespace mono_bind
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index 5accc21f8e..4170e5053f 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -293,8 +293,10 @@ public:
gdmono::ScopeExitDomainUnload __gdmono__scope__exit__domain__unload__(m_mono_domain); \
(void)__gdmono__scope__exit__domain__unload__;
-class _GodotSharp : public Object {
- GDCLASS(_GodotSharp, Object);
+namespace mono_bind {
+
+class GodotSharp : public Object {
+ GDCLASS(GodotSharp, Object);
friend class GDMono;
@@ -303,11 +305,11 @@ class _GodotSharp : public Object {
void _reload_assemblies(bool p_soft_reload);
protected:
- static _GodotSharp *singleton;
+ static GodotSharp *singleton;
static void _bind_methods();
public:
- static _GodotSharp *get_singleton() { return singleton; }
+ static GodotSharp *get_singleton() { return singleton; }
void attach_thread();
void detach_thread();
@@ -323,8 +325,10 @@ public:
bool is_runtime_shutting_down();
bool is_runtime_initialized();
- _GodotSharp();
- ~_GodotSharp();
+ GodotSharp();
+ ~GodotSharp();
};
+} // namespace mono_bind
+
#endif // GD_MONO_H
diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp
index d6545d50ec..60047545c4 100644
--- a/modules/mono/mono_gd/gd_mono_internals.cpp
+++ b/modules/mono/mono_gd/gd_mono_internals.cpp
@@ -45,7 +45,7 @@
namespace GDMonoInternals {
void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
// This method should not fail
-#if 0
+
CRASH_COND(!unmanaged);
// All mono objects created from the managed world (e.g.: 'new Player()')
@@ -89,12 +89,12 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
}
// The object was just created, no script instance binding should have been attached
- CRASH_COND(unmanaged->has_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()));
+ CRASH_COND(CSharpLanguage::has_instance_binding(unmanaged));
void *data = (void *)CSharpLanguage::get_singleton()->insert_script_binding(unmanaged, script_binding);
// Should be thread safe because the object was just created and nothing else should be referencing it
- unmanaged->set_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index(), data);
+ CSharpLanguage::set_instance_binding(unmanaged, data);
return;
}
@@ -108,7 +108,6 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(unmanaged, script.ptr(), gchandle);
unmanaged->set_script_and_instance(script, csharp_instance);
-#endif
}
void unhandled_exception(MonoException *p_exc) {
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index 9f2977bfa2..c9789bf270 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -1686,7 +1686,9 @@ Callable managed_to_callable(const M_Callable &p_managed_callable) {
Object *target = p_managed_callable.target ?
unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_callable.target)) :
nullptr;
- StringName *method_ptr = unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_callable.method_string_name));
+ StringName *method_ptr = p_managed_callable.method_string_name ?
+ unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_callable.method_string_name)) :
+ nullptr;
StringName method = method_ptr ? *method_ptr : StringName();
return Callable(target, method);
}
@@ -1732,7 +1734,9 @@ Signal managed_to_signal_info(const M_SignalInfo &p_managed_signal) {
Object *owner = p_managed_signal.owner ?
unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_signal.owner)) :
nullptr;
- StringName *name_ptr = unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_signal.name_string_name));
+ StringName *name_ptr = p_managed_signal.name_string_name ?
+ unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_signal.name_string_name)) :
+ nullptr;
StringName name = name_ptr ? *name_ptr : StringName();
return Signal(owner, name);
}
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index 080398c997..13939bd014 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -54,7 +54,6 @@
namespace GDMonoUtils {
MonoObject *unmanaged_get_managed(Object *unmanaged) {
-#if 0
if (!unmanaged) {
return nullptr;
}
@@ -69,22 +68,10 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) {
// If the owner does not have a CSharpInstance...
- void *data = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
-
+ void *data = CSharpLanguage::get_instance_binding(unmanaged);
ERR_FAIL_NULL_V(data, nullptr);
-
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value();
-
- if (!script_binding.inited) {
- MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex());
-
- if (!script_binding.inited) { // Other thread may have set it up
- // Already had a binding that needs to be setup
- CSharpLanguage::get_singleton()->setup_csharp_script_binding(script_binding, unmanaged);
-
- ERR_FAIL_COND_V(!script_binding.inited, nullptr);
- }
- }
+ ERR_FAIL_COND_V(!script_binding.inited, nullptr);
MonoGCHandleData &gchandle = script_binding.gchandle;
@@ -121,8 +108,6 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) {
}
return mono_object;
-#endif
- return nullptr;
}
void set_main_thread(MonoThread *p_thread) {
diff --git a/modules/mono/register_types.cpp b/modules/mono/register_types.cpp
index 2ba89eac55..98e83335e9 100644
--- a/modules/mono/register_types.cpp
+++ b/modules/mono/register_types.cpp
@@ -38,15 +38,15 @@ CSharpLanguage *script_language_cs = nullptr;
Ref<ResourceFormatLoaderCSharpScript> resource_loader_cs;
Ref<ResourceFormatSaverCSharpScript> resource_saver_cs;
-_GodotSharp *_godotsharp = nullptr;
+mono_bind::GodotSharp *_godotsharp = nullptr;
void register_mono_types() {
GDREGISTER_CLASS(CSharpScript);
- _godotsharp = memnew(_GodotSharp);
+ _godotsharp = memnew(mono_bind::GodotSharp);
- GDREGISTER_CLASS(_GodotSharp);
- Engine::get_singleton()->add_singleton(Engine::Singleton("GodotSharp", _GodotSharp::get_singleton()));
+ GDREGISTER_CLASS(mono_bind::GodotSharp);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("GodotSharp", mono_bind::GodotSharp::get_singleton()));
script_language_cs = memnew(CSharpLanguage);
script_language_cs->set_language_index(ScriptServer::get_language_count());
diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp
index 41cd75fd22..905d10c9d4 100644
--- a/modules/navigation/navigation_mesh_generator.cpp
+++ b/modules/navigation/navigation_mesh_generator.cpp
@@ -138,7 +138,7 @@ void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, cons
}
}
-void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask, bool p_recurse_children) {
+void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children) {
if (Object::cast_to<MeshInstance3D>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) {
MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(p_node);
Ref<Mesh> mesh = mesh_instance->get_mesh();
@@ -187,7 +187,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transfor
Ref<CapsuleMesh> capsule_mesh;
capsule_mesh.instantiate();
capsule_mesh->set_radius(capsule->get_radius());
- capsule_mesh->set_mid_height(capsule->get_height() / 2.0);
+ capsule_mesh->set_height(capsule->get_height());
mesh = capsule_mesh;
}
@@ -515,7 +515,7 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node)
Transform3D navmesh_xform = Object::cast_to<Node3D>(p_node)->get_transform().affine_inverse();
for (Node *E : parse_nodes) {
- int geometry_type = p_nav_mesh->get_parsed_geometry_type();
+ NavigationMesh::ParsedGeometryType geometry_type = p_nav_mesh->get_parsed_geometry_type();
uint32_t collision_mask = p_nav_mesh->get_collision_mask();
bool recurse_children = p_nav_mesh->get_source_geometry_mode() != NavigationMesh::SOURCE_GEOMETRY_GROUPS_EXPLICIT;
_parse_geometry(navmesh_xform, E, vertices, indices, geometry_type, collision_mask, recurse_children);
diff --git a/modules/navigation/navigation_mesh_generator.h b/modules/navigation/navigation_mesh_generator.h
index 847c7d097b..78f1329e3f 100644
--- a/modules/navigation/navigation_mesh_generator.h
+++ b/modules/navigation/navigation_mesh_generator.h
@@ -52,7 +52,7 @@ protected:
static void _add_vertex(const Vector3 &p_vec3, Vector<float> &p_verticies);
static void _add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices);
static void _add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices);
- static void _parse_geometry(Transform3D p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask, bool p_recurse_children);
+ static void _parse_geometry(Transform3D p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children);
static void _convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_nav_mesh);
static void _build_recast_navigation_mesh(
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index d06c5c2f14..1fcbb7aaca 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -15,7 +15,7 @@ def make_icu_data(target, source, env):
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
g.write("/* (C) 2016 and later: Unicode, Inc. and others. */\n")
- g.write("/* License & terms of use: http://www.unicode.org/copyright.html */\n")
+ g.write("/* License & terms of use: https://www.unicode.org/copyright.html */\n")
g.write("#ifndef _ICU_DATA_H\n")
g.write("#define _ICU_DATA_H\n")
g.write('#include "unicode/utypes.h"\n')
diff --git a/modules/text_server_adv/bitmap_font_adv.cpp b/modules/text_server_adv/bitmap_font_adv.cpp
index df7b42eac6..1731fb6223 100644
--- a/modules/text_server_adv/bitmap_font_adv.cpp
+++ b/modules/text_server_adv/bitmap_font_adv.cpp
@@ -225,7 +225,7 @@ hb_font_t *hb_bmp_font_create(BitmapFontDataAdvanced *p_face, int p_size, hb_des
Error BitmapFontDataAdvanced::load_from_file(const String &p_filename, int p_base_size) {
_THREAD_SAFE_METHOD_
//fnt format used by angelcode bmfont
- //http://www.angelcode.com/products/bmfont/
+ //https://www.angelcode.com/products/bmfont/
FileAccess *f = FileAccess::open(p_filename, FileAccess::READ);
ERR_FAIL_COND_V_MSG(!f, ERR_FILE_NOT_FOUND, "Can't open font: " + p_filename + ".");
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index fa4888f843..9ecb0de5b8 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -977,6 +977,7 @@ void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *
p_shaped->sort_valid = false;
p_shaped->line_breaks_valid = false;
p_shaped->justification_ops_valid = false;
+ p_shaped->text_trimmed = false;
p_shaped->ascent = 0.f;
p_shaped->descent = 0.f;
p_shaped->width = 0.f;
@@ -984,6 +985,7 @@ void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *
p_shaped->uthk = 0.f;
p_shaped->glyphs.clear();
p_shaped->glyphs_logical.clear();
+ p_shaped->overrun_trim_data = TrimData();
p_shaped->utf16 = Char16String();
if (p_shaped->script_iter != nullptr) {
memdelete(p_shaped->script_iter);
@@ -1161,7 +1163,7 @@ bool TextServerAdvanced::shaped_text_add_string(RID p_shaped, const String &p_te
return true;
}
-bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) {
+bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
_THREAD_SAFE_METHOD_
ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -1191,7 +1193,7 @@ bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, con
return true;
}
-bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align) {
+bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
_THREAD_SAFE_METHOD_
ShapedTextData *sd = shaped_owner.getornull(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -1222,34 +1224,10 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->objects[key].rect.position.x = sd->width;
sd->width += sd->objects[key].rect.size.x;
- switch (sd->objects[key].inline_align) {
- case VALIGN_TOP: {
- sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y);
- } break;
- case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2));
- sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2));
- } break;
- case VALIGN_BOTTOM: {
- sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y);
- } break;
- }
sd->glyphs.write[i].advance = sd->objects[key].rect.size.x;
} else {
sd->objects[key].rect.position.y = sd->width;
sd->width += sd->objects[key].rect.size.y;
- switch (sd->objects[key].inline_align) {
- case VALIGN_TOP: {
- sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x);
- } break;
- case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2));
- sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2));
- } break;
- case VALIGN_BOTTOM: {
- sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x);
- } break;
- }
sd->glyphs.write[i].advance = sd->objects[key].rect.size.y;
}
} else {
@@ -1279,35 +1257,71 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
}
// Align embedded objects to baseline.
+ float full_ascent = sd->ascent;
+ float full_descent = sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
if ((E->get().pos >= sd->start) && (E->get().pos < sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.y = 0;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.y = sd->descent - E->get().rect.size.y;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.y = sd->descent;
} break;
}
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
+ } break;
+ }
+ full_ascent = MAX(full_ascent, -E->get().rect.position.y);
+ full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.x = 0;
+ } break;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.x = sd->descent;
+ } break;
+ }
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x / 2;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.x = sd->descent - E->get().rect.size.x;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
} break;
}
+ full_ascent = MAX(full_ascent, -E->get().rect.position.x);
+ full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
}
+ sd->ascent = full_ascent;
+ sd->descent = full_descent;
}
return true;
}
@@ -1363,7 +1377,7 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
ERR_FAIL_COND_V_MSG((start < 0 || end - start > new_sd->utf16.length()), RID(), "Invalid BiDi override range.");
- //Create temporary line bidi & shape
+ // Create temporary line bidi & shape.
UBiDi *bidi_iter = ubidi_openSized(end - start, 0, &err);
ERR_FAIL_COND_V_MSG(U_FAILURE(err), RID(), u_errorName(err));
ubidi_setLine(sd->bidi_iter[ov], start, end, bidi_iter, &err);
@@ -1404,33 +1418,9 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
new_sd->objects[key].rect.position.x = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.x;
- switch (new_sd->objects[key].inline_align) {
- case VALIGN_TOP: {
- new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y);
- } break;
- case VALIGN_CENTER: {
- new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2));
- new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2));
- } break;
- case VALIGN_BOTTOM: {
- new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y);
- } break;
- }
} else {
new_sd->objects[key].rect.position.y = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.y;
- switch (new_sd->objects[key].inline_align) {
- case VALIGN_TOP: {
- new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x);
- } break;
- case VALIGN_CENTER: {
- new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2));
- new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2));
- } break;
- case VALIGN_BOTTOM: {
- new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x);
- } break;
- }
}
} else {
if (prev_rid != gl.font_rid) {
@@ -1464,37 +1454,72 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
}
// Align embedded objects to baseline.
+ float full_ascent = new_sd->ascent;
+ float full_descent = new_sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = new_sd->objects.front(); E; E = E->next()) {
if ((E->get().pos >= new_sd->start) && (E->get().pos < new_sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -new_sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.y = (-new_sd->ascent + new_sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.y = 0;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.y = new_sd->descent - E->get().rect.size.y;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.y = new_sd->descent;
} break;
}
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
+ } break;
+ }
+ full_ascent = MAX(full_ascent, -E->get().rect.position.y);
+ full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -new_sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.x = (-new_sd->ascent + new_sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.x = 0;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.x = new_sd->descent - E->get().rect.size.x;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.x = new_sd->descent;
} break;
}
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
+ } break;
+ }
+ full_ascent = MAX(full_ascent, -E->get().rect.position.x);
+ full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
}
+ new_sd->ascent = full_ascent;
+ new_sd->descent = full_descent;
}
-
new_sd->valid = true;
return shaped_owner.make_rid(new_sd);
@@ -1518,6 +1543,7 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
const_cast<TextServerAdvanced *>(this)->shaped_text_update_justification_ops(p_shaped);
}
+ sd->fit_width_minimum_reached = false;
int start_pos = 0;
int end_pos = sd->glyphs.size() - 1;
@@ -1546,14 +1572,26 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
}
}
+ float justification_width;
+ if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) == JUSTIFICATION_CONSTRAIN_ELLIPSIS) {
+ if (sd->overrun_trim_data.trim_pos >= 0) {
+ start_pos = sd->overrun_trim_data.trim_pos;
+ justification_width = sd->width_trimmed;
+ } else {
+ return sd->width;
+ }
+ } else {
+ justification_width = sd->width;
+ }
+
if ((p_jst_flags & JUSTIFICATION_TRIM_EDGE_SPACES) == JUSTIFICATION_TRIM_EDGE_SPACES) {
while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
- sd->width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat;
+ justification_width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat;
sd->glyphs.write[start_pos].advance = 0;
start_pos += sd->glyphs[start_pos].count;
}
while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
- sd->width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat;
+ justification_width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat;
sd->glyphs.write[end_pos].advance = 0;
end_pos -= sd->glyphs[end_pos].count;
}
@@ -1574,7 +1612,7 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
}
if ((elongation_count > 0) && ((p_jst_flags & JUSTIFICATION_KASHIDA) == JUSTIFICATION_KASHIDA)) {
- float delta_width_per_kashida = (p_width - sd->width) / elongation_count;
+ float delta_width_per_kashida = (p_width - justification_width) / elongation_count;
for (int i = start_pos; i <= end_pos; i++) {
Glyph &gl = sd->glyphs.write[i];
if (gl.count > 0) {
@@ -1582,34 +1620,50 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
int count = delta_width_per_kashida / gl.advance;
int prev_count = gl.repeat;
if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
- gl.repeat = count;
- } else {
- gl.repeat = count + 1;
+ gl.repeat = MAX(count, 0);
}
- sd->width += (gl.repeat - prev_count) * gl.advance;
+ justification_width += (gl.repeat - prev_count) * gl.advance;
}
}
}
}
-
+ float adv_remain = 0;
if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) {
- float delta_width_per_space = (p_width - sd->width) / space_count;
+ float delta_width_per_space = (p_width - justification_width) / space_count;
for (int i = start_pos; i <= end_pos; i++) {
Glyph &gl = sd->glyphs.write[i];
if (gl.count > 0) {
if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
float old_adv = gl.advance;
+ float new_advance;
if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
- gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.f));
+ new_advance = MAX(gl.advance + delta_width_per_space, 0.f);
} else {
- gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size));
+ new_advance = MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size);
+ }
+ gl.advance = new_advance;
+ adv_remain += (new_advance - gl.advance);
+ if (adv_remain >= 1.0) {
+ gl.advance++;
+ adv_remain -= 1.0;
+ } else if (adv_remain <= -1.0) {
+ gl.advance = MAX(gl.advance - 1, 0);
+ adv_remain -= 1.0;
}
- sd->width += (gl.advance - old_adv);
+ justification_width += (gl.advance - old_adv);
}
}
}
}
+ if (Math::floor(p_width) < Math::floor(justification_width)) {
+ sd->fit_width_minimum_reached = true;
+ }
+
+ if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) != JUSTIFICATION_CONSTRAIN_ELLIPSIS) {
+ sd->width = justification_width;
+ }
+
return sd->width;
}
@@ -1662,7 +1716,7 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<float
return 0.f;
}
-void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_clip_flags) {
+void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_trim_flags) {
_THREAD_SAFE_METHOD_
ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped_line);
ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid.");
@@ -1670,13 +1724,22 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
shaped_text_shape(p_shaped_line);
}
- bool add_ellipsis = (p_clip_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS;
- bool cut_per_word = (p_clip_flags & OVERRUN_TRIM_WORD_ONLY) == OVERRUN_TRIM_WORD_ONLY;
- bool enforce_ellipsis = (p_clip_flags & OVERRUN_ENFORCE_ELLIPSIS) == OVERRUN_ENFORCE_ELLIPSIS;
+ sd->overrun_trim_data.ellipsis_glyph_buf.clear();
+
+ bool add_ellipsis = (p_trim_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS;
+ bool cut_per_word = (p_trim_flags & OVERRUN_TRIM_WORD_ONLY) == OVERRUN_TRIM_WORD_ONLY;
+ bool enforce_ellipsis = (p_trim_flags & OVERRUN_ENFORCE_ELLIPSIS) == OVERRUN_ENFORCE_ELLIPSIS;
+ bool justification_aware = (p_trim_flags & OVERRUN_JUSTIFICATION_AWARE) == OVERRUN_JUSTIFICATION_AWARE;
Glyph *sd_glyphs = sd->glyphs.ptrw();
- if ((p_clip_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIMMING || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {
+ if ((p_trim_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIMMING || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {
+ sd->overrun_trim_data.trim_pos = -1;
+ sd->overrun_trim_data.ellipsis_pos = -1;
+ return;
+ }
+
+ if (justification_aware && !sd->fit_width_minimum_reached) {
return;
}
@@ -1688,9 +1751,9 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
uint32_t whitespace_gl_idx = font_get_glyph_index(last_gl_font_rid, ' ');
Vector2 whitespace_adv = font_get_glyph_advance(last_gl_font_rid, whitespace_gl_idx, last_gl_font_size);
- int ellipsis_advance = 0;
+ int ellipsis_width = 0;
if (add_ellipsis) {
- ellipsis_advance = 3 * dot_adv.x + font_get_spacing_glyph(last_gl_font_rid) + (cut_per_word ? whitespace_adv.x : 0);
+ ellipsis_width = 3 * dot_adv.x + font_get_spacing_glyph(last_gl_font_rid) + (cut_per_word ? whitespace_adv.x : 0);
}
int ell_min_characters = 6;
@@ -1710,12 +1773,12 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
for (int i = glyphs_from; i != glyphs_to; i += glyphs_delta) {
if (!is_rtl) {
- width -= sd_glyphs[i].advance;
+ width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
}
if (sd_glyphs[i].count > 0) {
bool above_min_char_treshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters;
- if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_advance : 0) <= p_width) {
+ if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {
if (cut_per_word && above_min_char_treshold) {
if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
last_valid_cut = i;
@@ -1728,7 +1791,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
if (found) {
trim_pos = last_valid_cut;
- if (above_min_char_treshold && width - ellipsis_advance <= p_width) {
+ if (add_ellipsis && (above_min_char_treshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {
ellipsis_pos = trim_pos;
}
break;
@@ -1736,18 +1799,21 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
}
}
if (is_rtl) {
- width -= sd_glyphs[i].advance;
+ width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
}
}
+ sd->overrun_trim_data.trim_pos = trim_pos;
+ sd->overrun_trim_data.ellipsis_pos = ellipsis_pos;
+ if (trim_pos == 0 && enforce_ellipsis && add_ellipsis) {
+ sd->overrun_trim_data.ellipsis_pos = 0;
+ }
+
if ((trim_pos >= 0 && sd->width > p_width) || enforce_ellipsis) {
- int added_glyphs = 0;
if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) {
// Insert an additional space when cutting word bound for aesthetics.
if (cut_per_word && (ellipsis_pos > 0)) {
TextServer::Glyph gl;
- gl.start = sd_glyphs[ellipsis_pos].start;
- gl.end = sd_glyphs[ellipsis_pos].end;
gl.count = 1;
gl.advance = whitespace_adv.x;
gl.index = whitespace_gl_idx;
@@ -1755,68 +1821,33 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
gl.font_size = last_gl_font_size;
gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);
- // Optimized glyph insertion by replacing a glyph whenever possible.
- int glyph_idx = trim_pos + ((is_rtl) ? (-added_glyphs - 1) : added_glyphs);
- if (is_rtl) {
- if (glyph_idx < 0) {
- sd->glyphs.insert(0, gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- } else {
- if (glyph_idx > (sd_size - 1)) {
- sd->glyphs.append(gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- }
- added_glyphs++;
+ sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
}
// Add ellipsis dots.
- for (int d = 0; d < 3; d++) {
- TextServer::Glyph gl;
- gl.start = sd_glyphs[ellipsis_pos].start;
- gl.end = sd_glyphs[ellipsis_pos].end;
- gl.count = 1;
- gl.advance = dot_adv.x;
- gl.index = dot_gl_idx;
- gl.font_rid = last_gl_font_rid;
- gl.font_size = last_gl_font_size;
- gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);
-
- // Optimized glyph insertion by replacing a glyph whenever possible.
- int glyph_idx = trim_pos + ((is_rtl) ? (-added_glyphs - 1) : added_glyphs);
- if (is_rtl) {
- if (glyph_idx < 0) {
- sd->glyphs.insert(0, gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- } else {
- if (glyph_idx > (sd_size - 1)) {
- sd->glyphs.append(gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- }
- added_glyphs++;
- }
+ TextServer::Glyph gl;
+ gl.count = 1;
+ gl.repeat = 3;
+ gl.advance = dot_adv.x;
+ gl.index = dot_gl_idx;
+ gl.font_rid = last_gl_font_rid;
+ gl.font_size = last_gl_font_size;
+ gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);
+
+ sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
}
- // Cut the remaining glyphs off.
- if (!is_rtl) {
- sd->glyphs.resize(trim_pos + added_glyphs);
- } else {
- if (trim_pos - added_glyphs >= 0) {
- sd->glyphs = sd->glyphs.subarray(trim_pos - added_glyphs, sd->glyphs.size() - 1);
- }
- }
-
- // Update to correct width.
- sd->width = width + ((ellipsis_pos != -1) ? ellipsis_advance : 0);
+ sd->text_trimmed = true;
+ sd->width_trimmed = width + ((ellipsis_pos != -1) ? ellipsis_width : 0);
}
}
+TextServer::TrimData TextServerAdvanced::shaped_text_get_trim_data(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V_MSG(!sd, TrimData(), "ShapedTextDataAdvanced invalid.");
+ return sd->overrun_trim_data;
+}
+
bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
_THREAD_SAFE_METHOD_
ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
@@ -1843,7 +1874,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
int r_end = sd->spans[i].end;
UBreakIterator *bi = ubrk_open(UBRK_LINE, language.ascii().get_data(), data + _convert_pos_inv(sd, r_start), _convert_pos_inv(sd, r_end - r_start), &err);
if (U_FAILURE(err)) {
- //No data loaded - use fallback.
+ // No data loaded - use fallback.
for (int j = r_start; j < r_end; j++) {
char32_t c = sd->text[j - sd->start];
if (is_whitespace(c)) {
@@ -1907,7 +1938,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
gl.font_rid = sd_glyphs[i].font_rid;
gl.font_size = sd_glyphs[i].font_size;
gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL;
- sd->glyphs.insert(i + sd_glyphs[i].count, gl); // insert after
+ sd->glyphs.insert(i + sd_glyphs[i].count, gl); // Insert after.
// Update write pointer and size.
sd_size = sd->glyphs.size();
@@ -2027,7 +2058,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
UErrorCode err = U_ZERO_ERROR;
UBreakIterator *bi = ubrk_open(UBRK_WORD, "", data, data_size, &err);
if (U_FAILURE(err)) {
- // No data - use fallback
+ // No data - use fallback.
int limit = 0;
for (int i = 0; i < sd->text.length(); i++) {
if (is_whitespace(data[i])) {
@@ -2100,7 +2131,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
gl.font_rid = sd->glyphs[i].font_rid;
gl.font_size = sd->glyphs[i].font_size;
gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_VIRTUAL;
- sd->glyphs.insert(i + sd->glyphs[i].count, gl); // insert after
+ sd->glyphs.insert(i + sd->glyphs[i].count, gl); // Insert after.
i += sd->glyphs[i].count;
continue;
}
@@ -2166,7 +2197,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
int fs = p_sd->spans[p_span].font_size;
if (fd == nullptr) {
- // Add fallback glyphs
+ // Add fallback glyphs.
for (int i = p_start; i < p_end; i++) {
if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) {
TextServer::Glyph gl;
@@ -2309,7 +2340,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
w[last_cluster_index].flags |= GRAPHEME_IS_VALID;
}
- //Fallback.
+ // Fallback.
int failed_subrun_start = p_end + 1;
int failed_subrun_end = p_start;
@@ -2473,33 +2504,9 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->objects[span.embedded_key].rect.position.x = sd->width;
sd->width += sd->objects[span.embedded_key].rect.size.x;
- switch (sd->objects[span.embedded_key].inline_align) {
- case VALIGN_TOP: {
- sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y);
- } break;
- case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
- sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
- } break;
- case VALIGN_BOTTOM: {
- sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y);
- } break;
- }
} else {
sd->objects[span.embedded_key].rect.position.y = sd->width;
sd->width += sd->objects[span.embedded_key].rect.size.y;
- switch (sd->objects[span.embedded_key].inline_align) {
- case VALIGN_TOP: {
- sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x);
- } break;
- case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
- sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
- } break;
- case VALIGN_BOTTOM: {
- sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x);
- } break;
- }
}
Glyph gl;
gl.start = span.start;
@@ -2539,34 +2546,69 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
}
// Align embedded objects to baseline.
+ float full_ascent = sd->ascent;
+ float full_descent = sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.y = 0;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.y = sd->descent - E->get().rect.size.y;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.y = sd->descent;
} break;
}
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
+ } break;
+ }
+ full_ascent = MAX(full_ascent, -E->get().rect.position.y);
+ full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.x = 0;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.x = sd->descent - E->get().rect.size.x;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.x = sd->descent;
} break;
}
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
+ } break;
+ }
+ full_ascent = MAX(full_ascent, -E->get().rect.position.x);
+ full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
-
+ sd->ascent = full_ascent;
+ sd->descent = full_descent;
sd->valid = true;
return sd->valid;
}
@@ -2643,9 +2685,9 @@ Size2 TextServerAdvanced::shaped_text_get_size(RID p_shaped) const {
const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
}
if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) {
- return Size2(sd->width, sd->ascent + sd->descent);
+ return Size2((sd->text_trimmed ? sd->width_trimmed : sd->width), sd->ascent + sd->descent);
} else {
- return Size2(sd->ascent + sd->descent, sd->width);
+ return Size2(sd->ascent + sd->descent, (sd->text_trimmed ? sd->width_trimmed : sd->width));
}
}
@@ -2676,7 +2718,7 @@ float TextServerAdvanced::shaped_text_get_width(RID p_shaped) const {
if (!sd->valid) {
const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
}
- return sd->width;
+ return (sd->text_trimmed ? sd->width_trimmed : sd->width);
}
float TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) const {
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 3c4f840bfd..d19ba41a1a 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -216,8 +216,8 @@ public:
virtual bool shaped_text_get_preserve_control(RID p_shaped) const override;
virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override;
- virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) override;
- virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) override;
+ virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override;
+ virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override;
virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
virtual RID shaped_text_get_parent(RID p_shaped) const override;
@@ -229,7 +229,8 @@ public:
virtual bool shaped_text_update_breaks(RID p_shaped) override;
virtual bool shaped_text_update_justification_ops(RID p_shaped) override;
- virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_clip_flags) override;
+ virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_trim_flags) override;
+ virtual TrimData shaped_text_get_trim_data(RID p_shaped) const override;
virtual bool shaped_text_is_ready(RID p_shaped) const override;
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 004cbc2bb3..110194c373 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -570,7 +570,7 @@ void TextServerFallback::shaped_text_set_orientation(RID p_shaped, TextServer::O
}
void TextServerFallback::shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) {
- //No BiDi support, ignore.
+ // No BiDi support, ignore.
}
TextServer::Orientation TextServerFallback::shaped_text_get_orientation(RID p_shaped) const {
@@ -661,7 +661,7 @@ bool TextServerFallback::shaped_text_add_string(RID p_shaped, const String &p_te
return true;
}
-bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) {
+bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
_THREAD_SAFE_METHOD_
ShapedTextData *sd = shaped_owner.getornull(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -691,7 +691,7 @@ bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, con
return true;
}
-bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align) {
+bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
_THREAD_SAFE_METHOD_
ShapedTextData *sd = shaped_owner.getornull(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -724,34 +724,10 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->objects[key].rect.position.x = sd->width;
sd->width += sd->objects[key].rect.size.x;
- switch (sd->objects[key].inline_align) {
- case VALIGN_TOP: {
- sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y);
- } break;
- case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2));
- sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2));
- } break;
- case VALIGN_BOTTOM: {
- sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y);
- } break;
- }
sd->glyphs.write[i].advance = sd->objects[key].rect.size.x;
} else {
sd->objects[key].rect.position.y = sd->width;
sd->width += sd->objects[key].rect.size.y;
- switch (sd->objects[key].inline_align) {
- case VALIGN_TOP: {
- sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x);
- } break;
- case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2));
- sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2));
- } break;
- case VALIGN_BOTTOM: {
- sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x);
- } break;
- }
sd->glyphs.write[i].advance = sd->objects[key].rect.size.y;
}
} else {
@@ -784,35 +760,71 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
}
// Align embedded objects to baseline.
+ float full_ascent = sd->ascent;
+ float full_descent = sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
if ((E->get().pos >= sd->start) && (E->get().pos < sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.y = 0;
+ } break;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.y = sd->descent;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.y = sd->descent - E->get().rect.size.y;
+ }
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
} break;
}
+ full_ascent = MAX(full_ascent, -E->get().rect.position.y);
+ full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.x = 0;
+ } break;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.x = sd->descent;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.x = sd->descent - E->get().rect.size.x;
+ }
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
} break;
}
+ full_ascent = MAX(full_ascent, -E->get().rect.position.x);
+ full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
}
+ sd->ascent = full_ascent;
+ sd->descent = full_descent;
}
return true;
}
@@ -869,33 +881,9 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
new_sd->objects[key].rect.position.x = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.x;
- switch (new_sd->objects[key].inline_align) {
- case VALIGN_TOP: {
- new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y);
- } break;
- case VALIGN_CENTER: {
- new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2));
- new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2));
- } break;
- case VALIGN_BOTTOM: {
- new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y);
- } break;
- }
} else {
new_sd->objects[key].rect.position.y = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.y;
- switch (new_sd->objects[key].inline_align) {
- case VALIGN_TOP: {
- new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x);
- } break;
- case VALIGN_CENTER: {
- new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2));
- new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2));
- } break;
- case VALIGN_BOTTOM: {
- new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x);
- } break;
- }
}
} else {
const FontDataFallback *fd = font_owner.getornull(gl.font_rid);
@@ -923,35 +911,72 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
}
}
+ // Align embedded objects to baseline.
+ float full_ascent = new_sd->ascent;
+ float full_descent = new_sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = new_sd->objects.front(); E; E = E->next()) {
if ((E->get().pos >= new_sd->start) && (E->get().pos < new_sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -new_sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.y = (-new_sd->ascent + new_sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.y = 0;
+ } break;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.y = new_sd->descent;
+ } break;
+ }
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y / 2;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.y = new_sd->descent - E->get().rect.size.y;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
} break;
}
+ full_ascent = MAX(full_ascent, -E->get().rect.position.y);
+ full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -new_sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.x = (-new_sd->ascent + new_sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.x = 0;
+ } break;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.x = new_sd->descent;
+ } break;
+ }
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x / 2;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.x = new_sd->descent - E->get().rect.size.x;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
} break;
}
+ full_ascent = MAX(full_ascent, -E->get().rect.position.x);
+ full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
}
+ new_sd->ascent = full_ascent;
+ new_sd->descent = full_descent;
}
new_sd->valid = true;
@@ -1148,7 +1173,7 @@ bool TextServerFallback::shaped_text_update_justification_ops(RID p_shaped) {
return true;
}
-void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_clip_flags) {
+void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_trim_flags) {
_THREAD_SAFE_METHOD_
ShapedTextData *sd = shaped_owner.getornull(p_shaped_line);
ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid.");
@@ -1156,13 +1181,22 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
shaped_text_shape(p_shaped_line);
}
- bool add_ellipsis = (p_clip_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS;
- bool cut_per_word = (p_clip_flags & OVERRUN_TRIM_WORD_ONLY) == OVERRUN_TRIM_WORD_ONLY;
- bool enforce_ellipsis = (p_clip_flags & OVERRUN_ENFORCE_ELLIPSIS) == OVERRUN_ENFORCE_ELLIPSIS;
+ sd->overrun_trim_data.ellipsis_glyph_buf.clear();
+
+ bool add_ellipsis = (p_trim_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS;
+ bool cut_per_word = (p_trim_flags & OVERRUN_TRIM_WORD_ONLY) == OVERRUN_TRIM_WORD_ONLY;
+ bool enforce_ellipsis = (p_trim_flags & OVERRUN_ENFORCE_ELLIPSIS) == OVERRUN_ENFORCE_ELLIPSIS;
+ bool justification_aware = (p_trim_flags & OVERRUN_JUSTIFICATION_AWARE) == OVERRUN_JUSTIFICATION_AWARE;
Glyph *sd_glyphs = sd->glyphs.ptrw();
- if ((p_clip_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIMMING || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {
+ if ((p_trim_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIMMING || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {
+ sd->overrun_trim_data.trim_pos = -1;
+ sd->overrun_trim_data.ellipsis_pos = -1;
+ return;
+ }
+
+ if (justification_aware && !sd->fit_width_minimum_reached) {
return;
}
@@ -1174,34 +1208,27 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
uint32_t whitespace_gl_idx = font_get_glyph_index(last_gl_font_rid, ' ');
Vector2 whitespace_adv = font_get_glyph_advance(last_gl_font_rid, whitespace_gl_idx, last_gl_font_size);
- int ellipsis_advance = 0;
+ int ellipsis_width = 0;
if (add_ellipsis) {
- ellipsis_advance = 3 * dot_adv.x + font_get_spacing_glyph(last_gl_font_rid) + (cut_per_word ? whitespace_adv.x : 0);
+ ellipsis_width = 3 * dot_adv.x + font_get_spacing_glyph(last_gl_font_rid) + (cut_per_word ? whitespace_adv.x : 0);
}
int ell_min_characters = 6;
float width = sd->width;
- bool is_rtl = sd->direction == DIRECTION_RTL || (sd->direction == DIRECTION_AUTO && sd->para_direction == DIRECTION_RTL);
-
- int trim_pos = (is_rtl) ? sd_size : 0;
+ int trim_pos = 0;
int ellipsis_pos = (enforce_ellipsis) ? 0 : -1;
int last_valid_cut = 0;
bool found = false;
- int glyphs_from = (is_rtl) ? 0 : sd_size - 1;
- int glyphs_to = (is_rtl) ? sd_size - 1 : -1;
- int glyphs_delta = (is_rtl) ? +1 : -1;
+ for (int i = sd_size - 1; i != -1; i--) {
+ width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
- for (int i = glyphs_from; i != glyphs_to; i += glyphs_delta) {
- if (!is_rtl) {
- width -= sd_glyphs[i].advance;
- }
if (sd_glyphs[i].count > 0) {
- bool above_min_char_treshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters;
+ bool above_min_char_treshold = (i >= ell_min_characters);
- if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_advance : 0) <= p_width) {
+ if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {
if (cut_per_word && above_min_char_treshold) {
if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
last_valid_cut = i;
@@ -1214,95 +1241,60 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
if (found) {
trim_pos = last_valid_cut;
- if (above_min_char_treshold && width - ellipsis_advance <= p_width) {
+ if (add_ellipsis && (above_min_char_treshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {
ellipsis_pos = trim_pos;
}
break;
}
}
}
- if (is_rtl) {
- width -= sd_glyphs[i].advance;
- }
+ }
+
+ sd->overrun_trim_data.trim_pos = trim_pos;
+ sd->overrun_trim_data.ellipsis_pos = ellipsis_pos;
+ if (trim_pos == 0 && enforce_ellipsis && add_ellipsis) {
+ sd->overrun_trim_data.ellipsis_pos = 0;
}
if ((trim_pos >= 0 && sd->width > p_width) || enforce_ellipsis) {
- int added_glyphs = 0;
if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) {
// Insert an additional space when cutting word bound for aesthetics.
if (cut_per_word && (ellipsis_pos > 0)) {
TextServer::Glyph gl;
- gl.start = sd_glyphs[ellipsis_pos].start;
- gl.end = sd_glyphs[ellipsis_pos].end;
gl.count = 1;
gl.advance = whitespace_adv.x;
gl.index = whitespace_gl_idx;
gl.font_rid = last_gl_font_rid;
gl.font_size = last_gl_font_size;
- gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);
+ gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL;
- // Optimized glyph insertion by replacing a glyph whenever possible.
- int glyph_idx = trim_pos + ((is_rtl) ? -added_glyphs : added_glyphs);
- if (is_rtl) {
- if (glyph_idx < 0) {
- sd->glyphs.insert(0, gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- } else {
- if (glyph_idx > (sd_size - 1)) {
- sd->glyphs.append(gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- }
- added_glyphs++;
+ sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
}
// Add ellipsis dots.
- for (int d = 0; d < 3; d++) {
- TextServer::Glyph gl;
- gl.start = sd_glyphs[ellipsis_pos].start;
- gl.end = sd_glyphs[ellipsis_pos].end;
- gl.count = 1;
- gl.advance = dot_adv.x;
- gl.index = dot_gl_idx;
- gl.font_rid = last_gl_font_rid;
- gl.font_size = last_gl_font_size;
- gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);
-
- // Optimized glyph insertion by replacing a glyph whenever possible.
- int glyph_idx = trim_pos + ((is_rtl) ? -added_glyphs : added_glyphs);
- if (is_rtl) {
- if (glyph_idx < 0) {
- sd->glyphs.insert(0, gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- } else {
- if (glyph_idx > (sd_size - 1)) {
- sd->glyphs.append(gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- }
- added_glyphs++;
- }
- }
-
- // Cut the remaining glyphs off.
- if (!is_rtl) {
- sd->glyphs.resize(trim_pos + added_glyphs);
- } else {
- for (int ridx = 0; ridx <= trim_pos - added_glyphs; ridx++) {
- sd->glyphs.remove(0);
- }
+ TextServer::Glyph gl;
+ gl.count = 1;
+ gl.repeat = 3;
+ gl.advance = dot_adv.x;
+ gl.index = dot_gl_idx;
+ gl.font_rid = last_gl_font_rid;
+ gl.font_size = last_gl_font_size;
+ gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL;
+
+ sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
}
- // Update to correct width.
- sd->width = width + ((ellipsis_pos != -1) ? ellipsis_advance : 0);
+ sd->text_trimmed = true;
+ sd->width_trimmed = width + ((ellipsis_pos != -1) ? ellipsis_width : 0);
}
}
+TextServer::TrimData TextServerFallback::shaped_text_get_trim_data(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V_MSG(!sd, TrimData(), "ShapedTextDataAdvanced invalid.");
+ return sd->overrun_trim_data;
+}
+
bool TextServerFallback::shaped_text_shape(RID p_shaped) {
_THREAD_SAFE_METHOD_
ShapedTextData *sd = shaped_owner.getornull(p_shaped);
@@ -1336,33 +1328,9 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->objects[span.embedded_key].rect.position.x = sd->width;
sd->width += sd->objects[span.embedded_key].rect.size.x;
- switch (sd->objects[span.embedded_key].inline_align) {
- case VALIGN_TOP: {
- sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y);
- } break;
- case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
- sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
- } break;
- case VALIGN_BOTTOM: {
- sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y);
- } break;
- }
} else {
sd->objects[span.embedded_key].rect.position.y = sd->width;
sd->width += sd->objects[span.embedded_key].rect.size.y;
- switch (sd->objects[span.embedded_key].inline_align) {
- case VALIGN_TOP: {
- sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x);
- } break;
- case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
- sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
- } break;
- case VALIGN_BOTTOM: {
- sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x);
- } break;
- }
}
Glyph gl;
gl.start = span.start;
@@ -1456,34 +1424,69 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
}
// Align embedded objects to baseline.
+ float full_ascent = sd->ascent;
+ float full_descent = sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.y = 0;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.y = sd->descent - E->get().rect.size.y;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.y = sd->descent;
} break;
}
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
+ } break;
+ }
+ full_ascent = MAX(full_ascent, -E->get().rect.position.y);
+ full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.x = 0;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.x = sd->descent - E->get().rect.size.x;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.x = sd->descent;
} break;
}
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
+ } break;
+ }
+ full_ascent = MAX(full_ascent, -E->get().rect.position.x);
+ full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
-
+ sd->ascent = full_ascent;
+ sd->descent = full_descent;
sd->valid = true;
return sd->valid;
}
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index b70c8f4ec0..d4cab2409a 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -165,8 +165,8 @@ public:
virtual bool shaped_text_get_preserve_control(RID p_shaped) const override;
virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override;
- virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) override;
- virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) override;
+ virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override;
+ virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override;
virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
virtual RID shaped_text_get_parent(RID p_shaped) const override;
@@ -178,7 +178,8 @@ public:
virtual bool shaped_text_update_breaks(RID p_shaped) override;
virtual bool shaped_text_update_justification_ops(RID p_shaped) override;
- virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_clip_flags) override;
+ virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_trim_flags) override;
+ virtual TrimData shaped_text_get_trim_data(RID p_shaped) const override;
virtual bool shaped_text_is_ready(RID p_shaped) const override;
diff --git a/modules/vhacd/register_types.cpp b/modules/vhacd/register_types.cpp
index 3d7aaee921..2b48e94604 100644
--- a/modules/vhacd/register_types.cpp
+++ b/modules/vhacd/register_types.cpp
@@ -33,7 +33,7 @@
#include "thirdparty/vhacd/public/VHACD.h"
static Vector<Vector<Face3>> convex_decompose(const Vector<Face3> &p_faces, int p_max_convex_hulls = -1) {
- Vector<float> vertices;
+ Vector<real_t> vertices;
vertices.resize(p_faces.size() * 9);
Vector<uint32_t> indices;
indices.resize(p_faces.size() * 3);
diff --git a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml b/modules/visual_script/doc_classes/VisualScriptCustomNode.xml
index 8aa34f8cae..b574576856 100644
--- a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml
+++ b/modules/visual_script/doc_classes/VisualScriptCustomNode.xml
@@ -9,118 +9,118 @@
<tutorials>
</tutorials>
<methods>
- <method name="_get_caption" qualifiers="virtual">
+ <method name="_get_caption" qualifiers="virtual const">
<return type="String" />
<description>
Return the node's title.
</description>
</method>
- <method name="_get_category" qualifiers="virtual">
+ <method name="_get_category" qualifiers="virtual const">
<return type="String" />
<description>
Return the node's category.
</description>
</method>
- <method name="_get_input_value_port_count" qualifiers="virtual">
+ <method name="_get_input_value_port_count" qualifiers="virtual const">
<return type="int" />
<description>
Return the count of input value ports.
</description>
</method>
- <method name="_get_input_value_port_hint" qualifiers="virtual">
+ <method name="_get_input_value_port_hint" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="idx" type="int" />
+ <argument index="0" name="input_idx" type="int" />
<description>
Return the specified input port's hint. See the [enum @GlobalScope.PropertyHint] hints.
</description>
</method>
- <method name="_get_input_value_port_hint_string" qualifiers="virtual">
+ <method name="_get_input_value_port_hint_string" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <argument index="0" name="input_idx" type="int" />
<description>
Return the specified input port's hint string.
</description>
</method>
- <method name="_get_input_value_port_name" qualifiers="virtual">
+ <method name="_get_input_value_port_name" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <argument index="0" name="input_idx" type="int" />
<description>
Return the specified input port's name.
</description>
</method>
- <method name="_get_input_value_port_type" qualifiers="virtual">
+ <method name="_get_input_value_port_type" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="idx" type="int" />
+ <argument index="0" name="input_idx" type="int" />
<description>
Return the specified input port's type. See the [enum Variant.Type] values.
</description>
</method>
- <method name="_get_output_sequence_port_count" qualifiers="virtual">
+ <method name="_get_output_sequence_port_count" qualifiers="virtual const">
<return type="int" />
<description>
Return the amount of output [b]sequence[/b] ports.
</description>
</method>
- <method name="_get_output_sequence_port_text" qualifiers="virtual">
+ <method name="_get_output_sequence_port_text" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <argument index="0" name="seq_idx" type="int" />
<description>
Return the specified [b]sequence[/b] output's name.
</description>
</method>
- <method name="_get_output_value_port_count" qualifiers="virtual">
+ <method name="_get_output_value_port_count" qualifiers="virtual const">
<return type="int" />
<description>
Return the amount of output value ports.
</description>
</method>
- <method name="_get_output_value_port_hint" qualifiers="virtual">
+ <method name="_get_output_value_port_hint" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="idx" type="int" />
+ <argument index="0" name="output_idx" type="int" />
<description>
Return the specified output port's hint. See the [enum @GlobalScope.PropertyHint] hints.
</description>
</method>
- <method name="_get_output_value_port_hint_string" qualifiers="virtual">
+ <method name="_get_output_value_port_hint_string" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <argument index="0" name="output_idx" type="int" />
<description>
Return the specified output port's hint string.
</description>
</method>
- <method name="_get_output_value_port_name" qualifiers="virtual">
+ <method name="_get_output_value_port_name" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <argument index="0" name="output_idx" type="int" />
<description>
Return the specified output port's name.
</description>
</method>
- <method name="_get_output_value_port_type" qualifiers="virtual">
+ <method name="_get_output_value_port_type" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="idx" type="int" />
+ <argument index="0" name="output_idx" type="int" />
<description>
Return the specified output port's type. See the [enum Variant.Type] values.
</description>
</method>
- <method name="_get_text" qualifiers="virtual">
+ <method name="_get_text" qualifiers="virtual const">
<return type="String" />
<description>
Return the custom node's text, which is shown right next to the input [b]sequence[/b] port (if there is none, on the place that is usually taken by it).
</description>
</method>
- <method name="_get_working_memory_size" qualifiers="virtual">
+ <method name="_get_working_memory_size" qualifiers="virtual const">
<return type="int" />
<description>
Return the size of the custom node's working memory. See [method _step] for more details.
</description>
</method>
- <method name="_has_input_sequence_port" qualifiers="virtual">
+ <method name="_has_input_sequence_port" qualifiers="virtual const">
<return type="bool" />
<description>
Return whether the custom node has an input [b]sequence[/b] port.
</description>
</method>
- <method name="_step" qualifiers="virtual">
+ <method name="_step" qualifiers="virtual const">
<return type="Variant" />
<argument index="0" name="inputs" type="Array" />
<argument index="1" name="outputs" type="Array" />
diff --git a/modules/visual_script/doc_classes/VisualScriptSubCall.xml b/modules/visual_script/doc_classes/VisualScriptSubCall.xml
index 374e7d0f35..f54887b09c 100644
--- a/modules/visual_script/doc_classes/VisualScriptSubCall.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSubCall.xml
@@ -9,13 +9,6 @@
<tutorials>
</tutorials>
<methods>
- <method name="_subcall" qualifiers="virtual">
- <return type="Variant" />
- <argument index="0" name="arguments" type="Variant" />
- <description>
- Called by this node.
- </description>
- </method>
</methods>
<constants>
</constants>
diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp
index f20ef046a3..fce98eb8a0 100644
--- a/modules/visual_script/register_types.cpp
+++ b/modules/visual_script/register_types.cpp
@@ -43,7 +43,7 @@
VisualScriptLanguage *visual_script_language = nullptr;
#ifdef TOOLS_ENABLED
-static _VisualScriptEditor *vs_editor_singleton = nullptr;
+static vs_bind::VisualScriptEditor *vs_editor_singleton = nullptr;
#endif
void register_visual_script_types() {
@@ -114,10 +114,10 @@ void register_visual_script_types() {
#ifdef TOOLS_ENABLED
ClassDB::set_current_api(ClassDB::API_EDITOR);
- GDREGISTER_CLASS(_VisualScriptEditor);
+ GDREGISTER_CLASS(vs_bind::VisualScriptEditor);
ClassDB::set_current_api(ClassDB::API_CORE);
- vs_editor_singleton = memnew(_VisualScriptEditor);
- Engine::get_singleton()->add_singleton(Engine::Singleton("VisualScriptEditor", _VisualScriptEditor::get_singleton()));
+ vs_editor_singleton = memnew(vs_bind::VisualScriptEditor);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("VisualScriptEditor", vs_bind::VisualScriptEditor::get_singleton()));
VisualScriptEditor::register_editor();
#endif
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index 86793af77f..142419f90a 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -1845,26 +1845,6 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
max_input_args = 0;
max_output_args = 0;
- if (Object::cast_to<Node>(p_owner)) {
- // Turn on these if they exist and base is a node.
- Node *node = Object::cast_to<Node>(p_owner);
- if (p_script->functions.has("_process")) {
- node->set_process(true);
- }
- if (p_script->functions.has("_physics_process")) {
- node->set_physics_process(true);
- }
- if (p_script->functions.has("_input")) {
- node->set_process_input(true);
- }
- if (p_script->functions.has("_unhandled_input")) {
- node->set_process_unhandled_input(true);
- }
- if (p_script->functions.has("_unhandled_key_input")) {
- node->set_process_unhandled_key_input(true);
- }
- }
-
// Setup variables.
{
List<StringName> keys;
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index a802e8022d..ded716cf18 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -1816,7 +1816,7 @@ void VisualScriptEditor::_generic_search(String p_base_type, Vector2 pos, bool n
}
}
-void VisualScriptEditor::_input(const Ref<InputEvent> &p_event) {
+void VisualScriptEditor::input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
// GUI input for VS Editor Plugin
@@ -2323,10 +2323,6 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
pset.instantiate();
pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE);
pset->set_base_type(obj->get_class());
- /*if (use_value) {
- pset->set_use_builtin_value(true);
- pset->set_builtin_value(d["value"]);
- }*/
vnode = pset;
} else {
Ref<VisualScriptPropertyGet> pget;
@@ -2903,9 +2899,8 @@ void VisualScriptEditor::_graph_connected(const String &p_from, int p_from_slot,
if (!converted) {
undo_redo->add_do_method(script.ptr(), "data_connect", p_from.to_int(), from_port, p_to.to_int(), to_port);
undo_redo->add_undo_method(script.ptr(), "data_disconnect", p_from.to_int(), from_port, p_to.to_int(), to_port);
- }
- // Update nodes in graph
- if (!converted) {
+
+ // Update nodes in graph
undo_redo->add_do_method(this, "_update_graph", p_from.to_int());
undo_redo->add_do_method(this, "_update_graph", p_to.to_int());
undo_redo->add_undo_method(this, "_update_graph", p_from.to_int());
@@ -4251,8 +4246,6 @@ void VisualScriptEditor::_bind_methods() {
ClassDB::bind_method("_can_drop_data_fw", &VisualScriptEditor::can_drop_data_fw);
ClassDB::bind_method("_drop_data_fw", &VisualScriptEditor::drop_data_fw);
- ClassDB::bind_method("_input", &VisualScriptEditor::_input);
-
ClassDB::bind_method("_update_graph_connections", &VisualScriptEditor::_update_graph_connections);
ClassDB::bind_method("_update_members", &VisualScriptEditor::_update_members);
@@ -4526,44 +4519,49 @@ void VisualScriptEditor::register_editor() {
EditorNode::add_plugin_init_callback(register_editor_callback);
}
-Ref<VisualScriptNode> _VisualScriptEditor::create_node_custom(const String &p_name) {
+void VisualScriptEditor::validate() {
+}
+
+namespace vs_bind {
+
+Ref<VisualScriptNode> VisualScriptEditor::create_node_custom(const String &p_name) {
Ref<VisualScriptCustomNode> node;
node.instantiate();
node->set_script(singleton->custom_nodes[p_name]);
return node;
}
-_VisualScriptEditor *_VisualScriptEditor::singleton = nullptr;
-Map<String, REF> _VisualScriptEditor::custom_nodes;
+VisualScriptEditor *VisualScriptEditor::singleton = nullptr;
+Map<String, REF> VisualScriptEditor::custom_nodes;
-_VisualScriptEditor::_VisualScriptEditor() {
+VisualScriptEditor::VisualScriptEditor() {
singleton = this;
}
-_VisualScriptEditor::~_VisualScriptEditor() {
+VisualScriptEditor::~VisualScriptEditor() {
custom_nodes.clear();
}
-void _VisualScriptEditor::add_custom_node(const String &p_name, const String &p_category, const Ref<Script> &p_script) {
+void VisualScriptEditor::add_custom_node(const String &p_name, const String &p_category, const Ref<Script> &p_script) {
String node_name = "custom/" + p_category + "/" + p_name;
custom_nodes.insert(node_name, p_script);
- VisualScriptLanguage::singleton->add_register_func(node_name, &_VisualScriptEditor::create_node_custom);
+ VisualScriptLanguage::singleton->add_register_func(node_name, &VisualScriptEditor::create_node_custom);
emit_signal(SNAME("custom_nodes_updated"));
}
-void _VisualScriptEditor::remove_custom_node(const String &p_name, const String &p_category) {
+void VisualScriptEditor::remove_custom_node(const String &p_name, const String &p_category) {
String node_name = "custom/" + p_category + "/" + p_name;
custom_nodes.erase(node_name);
VisualScriptLanguage::singleton->remove_register_func(node_name);
emit_signal(SNAME("custom_nodes_updated"));
}
-void _VisualScriptEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_custom_node", "name", "category", "script"), &_VisualScriptEditor::add_custom_node);
- ClassDB::bind_method(D_METHOD("remove_custom_node", "name", "category"), &_VisualScriptEditor::remove_custom_node);
+void VisualScriptEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("add_custom_node", "name", "category", "script"), &VisualScriptEditor::add_custom_node);
+ ClassDB::bind_method(D_METHOD("remove_custom_node", "name", "category"), &VisualScriptEditor::remove_custom_node);
ADD_SIGNAL(MethodInfo("custom_nodes_updated"));
}
-void VisualScriptEditor::validate() {
-}
+} // namespace vs_bind
+
#endif
diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h
index 3b7ed3dba6..4fa8ffca67 100644
--- a/modules/visual_script/visual_script_editor.h
+++ b/modules/visual_script/visual_script_editor.h
@@ -43,13 +43,12 @@ class VisualScriptEditorVariableEdit;
#ifdef TOOLS_ENABLED
+// TODO: Maybe this class should be refactored.
+// See https://github.com/godotengine/godot/issues/51913
class VisualScriptEditor : public ScriptEditorBase {
- GDCLASS(VisualScriptEditor, ScriptEditorBase);
-
enum {
TYPE_SEQUENCE = 1000,
INDEX_BASE_SEQUENCE = 1024
-
};
enum {
@@ -60,7 +59,7 @@ class VisualScriptEditor : public ScriptEditorBase {
EDIT_CUT_NODES,
EDIT_PASTE_NODES,
EDIT_CREATE_FUNCTION,
- REFRESH_GRAPH
+ REFRESH_GRAPH,
};
enum PortAction {
@@ -71,7 +70,6 @@ class VisualScriptEditor : public ScriptEditorBase {
enum MemberAction {
MEMBER_EDIT,
MEMBER_REMOVE
-
};
enum MemberType {
@@ -236,7 +234,7 @@ class VisualScriptEditor : public ScriptEditorBase {
void _generic_search(String p_base_type = "", Vector2 pos = Vector2(), bool node_centered = false);
- void _input(const Ref<InputEvent> &p_event);
+ virtual void input(const Ref<InputEvent> &p_event) override;
void _graph_gui_input(const Ref<InputEvent> &p_event);
void _members_gui_input(const Ref<InputEvent> &p_event);
void _fn_name_box_input(const Ref<InputEvent> &p_event);
@@ -332,28 +330,33 @@ public:
~VisualScriptEditor();
};
+namespace vs_bind {
+
// Singleton
-class _VisualScriptEditor : public Object {
- GDCLASS(_VisualScriptEditor, Object);
+class VisualScriptEditor : public Object {
+ GDCLASS(VisualScriptEditor, Object);
friend class VisualScriptLanguage;
protected:
static void _bind_methods();
- static _VisualScriptEditor *singleton;
+ static VisualScriptEditor *singleton;
static Map<String, REF> custom_nodes;
static Ref<VisualScriptNode> create_node_custom(const String &p_name);
public:
- static _VisualScriptEditor *get_singleton() { return singleton; }
+ static VisualScriptEditor *get_singleton() { return singleton; }
void add_custom_node(const String &p_name, const String &p_category, const Ref<Script> &p_script);
void remove_custom_node(const String &p_name, const String &p_category);
- _VisualScriptEditor();
- ~_VisualScriptEditor();
+ VisualScriptEditor();
+ ~VisualScriptEditor();
};
+
+} // namespace vs_bind
+
#endif
#endif // VISUALSCRIPT_EDITOR_H
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index c517d89aa5..c9e426fa6c 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -2825,36 +2825,41 @@ VisualScriptSelf::VisualScriptSelf() {
//////////////////////////////////////////
int VisualScriptCustomNode::get_output_sequence_port_count() const {
- if (get_script_instance() && get_script_instance()->has_method("_get_output_sequence_port_count")) {
- return get_script_instance()->call("_get_output_sequence_port_count");
+ int ret;
+ if (GDVIRTUAL_CALL(_get_output_sequence_port_count, ret)) {
+ return ret;
}
return 0;
}
bool VisualScriptCustomNode::has_input_sequence_port() const {
- if (get_script_instance() && get_script_instance()->has_method("_has_input_sequence_port")) {
- return get_script_instance()->call("_has_input_sequence_port");
+ bool ret;
+ if (GDVIRTUAL_CALL(_has_input_sequence_port, ret)) {
+ return ret;
}
return false;
}
int VisualScriptCustomNode::get_input_value_port_count() const {
- if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_count")) {
- return get_script_instance()->call("_get_input_value_port_count");
+ int ret;
+ if (GDVIRTUAL_CALL(_get_input_value_port_count, ret)) {
+ return ret;
}
return 0;
}
int VisualScriptCustomNode::get_output_value_port_count() const {
- if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_count")) {
- return get_script_instance()->call("_get_output_value_port_count");
+ int ret;
+ if (GDVIRTUAL_CALL(_get_output_value_port_count, ret)) {
+ return ret;
}
return 0;
}
String VisualScriptCustomNode::get_output_sequence_port_text(int p_port) const {
- if (get_script_instance() && get_script_instance()->has_method("_get_output_sequence_port_text")) {
- return get_script_instance()->call("_get_output_sequence_port_text", p_port);
+ String ret;
+ if (GDVIRTUAL_CALL(_get_output_sequence_port_text, p_port, ret)) {
+ return ret;
}
return String();
@@ -2862,34 +2867,61 @@ String VisualScriptCustomNode::get_output_sequence_port_text(int p_port) const {
PropertyInfo VisualScriptCustomNode::get_input_value_port_info(int p_idx) const {
PropertyInfo info;
- if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_type")) {
- info.type = Variant::Type(int(get_script_instance()->call("_get_input_value_port_type", p_idx)));
+ {
+ int type;
+ if (GDVIRTUAL_CALL(_get_input_value_port_type, p_idx, type)) {
+ info.type = Variant::Type(type);
+ }
}
- if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_name")) {
- info.name = get_script_instance()->call("_get_input_value_port_name", p_idx);
+ {
+ String name;
+ if (GDVIRTUAL_CALL(_get_input_value_port_name, p_idx, name)) {
+ info.name = name;
+ }
}
- if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_hint")) {
- info.hint = PropertyHint(int(get_script_instance()->call("_get_input_value_port_hint", p_idx)));
+ {
+ int hint;
+ if (GDVIRTUAL_CALL(_get_input_value_port_hint, p_idx, hint)) {
+ info.hint = PropertyHint(hint);
+ }
}
- if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_hint_string")) {
- info.hint_string = get_script_instance()->call("_get_input_value_port_hint_string", p_idx);
+
+ {
+ String hint_string;
+ if (GDVIRTUAL_CALL(_get_input_value_port_hint_string, p_idx, hint_string)) {
+ info.hint_string = hint_string;
+ }
}
+
return info;
}
PropertyInfo VisualScriptCustomNode::get_output_value_port_info(int p_idx) const {
PropertyInfo info;
- if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_type")) {
- info.type = Variant::Type(int(get_script_instance()->call("_get_output_value_port_type", p_idx)));
+ {
+ int type;
+ if (GDVIRTUAL_CALL(_get_output_value_port_type, p_idx, type)) {
+ info.type = Variant::Type(type);
+ }
}
- if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_name")) {
- info.name = get_script_instance()->call("_get_output_value_port_name", p_idx);
+ {
+ String name;
+ if (GDVIRTUAL_CALL(_get_output_value_port_name, p_idx, name)) {
+ info.name = name;
+ }
}
- if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_hint")) {
- info.hint = PropertyHint(int(get_script_instance()->call("_get_output_value_port_hint", p_idx)));
+ {
+ int hint;
+ if (GDVIRTUAL_CALL(_get_output_value_port_hint, p_idx, hint)) {
+ info.hint = PropertyHint(hint);
+ }
}
- if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_hint_string")) {
- info.hint_string = get_script_instance()->call("_get_output_value_port_hint_string", p_idx);
+
+ {
+ String hint_string;
+ if (GDVIRTUAL_CALL(_get_output_value_port_hint_string, p_idx, hint_string)) {
+ info.hint_string = hint_string;
+ }
}
return info;
}
@@ -2911,22 +2943,25 @@ VisualScriptCustomNode::TypeGuess VisualScriptCustomNode::guess_output_type(Type
}
String VisualScriptCustomNode::get_caption() const {
- if (get_script_instance() && get_script_instance()->has_method("_get_caption")) {
- return get_script_instance()->call("_get_caption");
+ String ret;
+ if (GDVIRTUAL_CALL(_get_caption, ret)) {
+ return ret;
}
return "CustomNode";
}
String VisualScriptCustomNode::get_text() const {
- if (get_script_instance() && get_script_instance()->has_method("_get_text")) {
- return get_script_instance()->call("_get_text");
+ String ret;
+ if (GDVIRTUAL_CALL(_get_text, ret)) {
+ return ret;
}
return "";
}
String VisualScriptCustomNode::get_category() const {
- if (get_script_instance() && get_script_instance()->has_method("_get_category")) {
- return get_script_instance()->call("_get_category");
+ String ret;
+ if (GDVIRTUAL_CALL(_get_category, ret)) {
+ return ret;
}
return "Custom";
}
@@ -2941,14 +2976,7 @@ public:
virtual int get_working_memory_size() const { return work_mem_size; }
virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
- if (node->get_script_instance()) {
-#ifdef DEBUG_ENABLED
- if (!node->get_script_instance()->has_method(VisualScriptLanguage::singleton->_step)) {
- r_error_str = RTR("Custom node has no _step() method, can't process graph.");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return 0;
- }
-#endif
+ if (GDVIRTUAL_IS_OVERRIDEN_PTR(node, _step)) {
Array in_values;
Array out_values;
Array work_mem;
@@ -2969,7 +2997,8 @@ public:
int ret_out;
- Variant ret = node->get_script_instance()->call(VisualScriptLanguage::singleton->_step, in_values, out_values, p_start_mode, work_mem);
+ Variant ret;
+ GDVIRTUAL_CALL_PTR(node, _step, in_values, out_values, p_start_mode, work_mem, ret);
if (ret.get_type() == Variant::STRING) {
r_error_str = ret;
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
@@ -2995,6 +3024,9 @@ public:
}
return ret_out;
+ } else {
+ r_error_str = RTR("Custom node has no _step() method, can't process graph.");
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
}
return 0;
@@ -3008,11 +3040,8 @@ VisualScriptNodeInstance *VisualScriptCustomNode::instantiate(VisualScriptInstan
instance->in_count = get_input_value_port_count();
instance->out_count = get_output_value_port_count();
- if (get_script_instance() && get_script_instance()->has_method("_get_working_memory_size")) {
- instance->work_mem_size = get_script_instance()->call("_get_working_memory_size");
- } else {
- instance->work_mem_size = 0;
- }
+ instance->work_mem_size = 0;
+ GDVIRTUAL_CALL(_get_working_memory_size, instance->work_mem_size);
return instance;
}
@@ -3022,32 +3051,29 @@ void VisualScriptCustomNode::_script_changed() {
}
void VisualScriptCustomNode::_bind_methods() {
- BIND_VMETHOD(MethodInfo(Variant::INT, "_get_output_sequence_port_count"));
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "_has_input_sequence_port"));
-
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_output_sequence_port_text", PropertyInfo(Variant::INT, "idx")));
- BIND_VMETHOD(MethodInfo(Variant::INT, "_get_input_value_port_count"));
- BIND_VMETHOD(MethodInfo(Variant::INT, "_get_output_value_port_count"));
+ GDVIRTUAL_BIND(_get_output_sequence_port_count);
+ GDVIRTUAL_BIND(_has_input_sequence_port);
+ GDVIRTUAL_BIND(_get_output_sequence_port_text, "seq_idx");
- BIND_VMETHOD(MethodInfo(Variant::INT, "_get_input_value_port_type", PropertyInfo(Variant::INT, "idx")));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_input_value_port_name", PropertyInfo(Variant::INT, "idx")));
- BIND_VMETHOD(MethodInfo(Variant::INT, "_get_input_value_port_hint", PropertyInfo(Variant::INT, "idx")));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_input_value_port_hint_string", PropertyInfo(Variant::INT, "idx")));
+ GDVIRTUAL_BIND(_get_input_value_port_count);
+ GDVIRTUAL_BIND(_get_input_value_port_type, "input_idx");
+ GDVIRTUAL_BIND(_get_input_value_port_name, "input_idx");
+ GDVIRTUAL_BIND(_get_input_value_port_hint, "input_idx");
+ GDVIRTUAL_BIND(_get_input_value_port_hint_string, "input_idx");
- BIND_VMETHOD(MethodInfo(Variant::INT, "_get_output_value_port_type", PropertyInfo(Variant::INT, "idx")));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_output_value_port_name", PropertyInfo(Variant::INT, "idx")));
- BIND_VMETHOD(MethodInfo(Variant::INT, "_get_output_value_port_hint", PropertyInfo(Variant::INT, "idx")));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_output_value_port_hint_string", PropertyInfo(Variant::INT, "idx")));
+ GDVIRTUAL_BIND(_get_output_value_port_count);
+ GDVIRTUAL_BIND(_get_output_value_port_type, "output_idx");
+ GDVIRTUAL_BIND(_get_output_value_port_name, "output_idx");
+ GDVIRTUAL_BIND(_get_output_value_port_hint, "output_idx");
+ GDVIRTUAL_BIND(_get_output_value_port_hint_string, "output_idx");
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_caption"));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_text"));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_category"));
+ GDVIRTUAL_BIND(_get_caption);
+ GDVIRTUAL_BIND(_get_text);
+ GDVIRTUAL_BIND(_get_category);
- BIND_VMETHOD(MethodInfo(Variant::INT, "_get_working_memory_size"));
+ GDVIRTUAL_BIND(_get_working_memory_size);
- MethodInfo stepmi(Variant::NIL, "_step", PropertyInfo(Variant::ARRAY, "inputs"), PropertyInfo(Variant::ARRAY, "outputs"), PropertyInfo(Variant::INT, "start_mode"), PropertyInfo(Variant::ARRAY, "working_mem"));
- stepmi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- BIND_VMETHOD(stepmi);
+ GDVIRTUAL_BIND(_step, "inputs", "outputs", "start_mode", "working_mem");
BIND_ENUM_CONSTANT(START_MODE_BEGIN_SEQUENCE);
BIND_ENUM_CONSTANT(START_MODE_CONTINUE_SEQUENCE);
@@ -3170,9 +3196,7 @@ VisualScriptNodeInstance *VisualScriptSubCall::instantiate(VisualScriptInstance
}
void VisualScriptSubCall::_bind_methods() {
- MethodInfo scmi(Variant::NIL, "_subcall", PropertyInfo(Variant::NIL, "arguments"));
- scmi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- BIND_VMETHOD(scmi);
+ // Since this is script only, registering virtual function is no longer valid. Will have to go in docs.
}
VisualScriptSubCall::VisualScriptSubCall() {
diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h
index 2390e5c7bc..35d9b0b4fe 100644
--- a/modules/visual_script/visual_script_nodes.h
+++ b/modules/visual_script/visual_script_nodes.h
@@ -31,6 +31,8 @@
#ifndef VISUAL_SCRIPT_NODES_H
#define VISUAL_SCRIPT_NODES_H
+#include "core/object/gdvirtual.gen.inc"
+#include "core/object/script_language.h"
#include "visual_script.h"
class VisualScriptFunction : public VisualScriptNode {
@@ -757,6 +759,30 @@ class VisualScriptCustomNode : public VisualScriptNode {
protected:
static void _bind_methods();
+ friend class VisualScriptNodeInstanceCustomNode;
+ GDVIRTUAL0RC(int, _get_output_sequence_port_count)
+ GDVIRTUAL0RC(bool, _has_input_sequence_port)
+ GDVIRTUAL1RC(String, _get_output_sequence_port_text, int)
+
+ GDVIRTUAL0RC(int, _get_input_value_port_count)
+ GDVIRTUAL1RC(int, _get_input_value_port_type, int)
+ GDVIRTUAL1RC(String, _get_input_value_port_name, int)
+ GDVIRTUAL1RC(int, _get_input_value_port_hint, int)
+ GDVIRTUAL1RC(String, _get_input_value_port_hint_string, int)
+
+ GDVIRTUAL0RC(int, _get_output_value_port_count)
+ GDVIRTUAL1RC(int, _get_output_value_port_type, int)
+ GDVIRTUAL1RC(String, _get_output_value_port_name, int)
+ GDVIRTUAL1RC(int, _get_output_value_port_hint, int)
+ GDVIRTUAL1RC(String, _get_output_value_port_hint_string, int)
+
+ GDVIRTUAL0RC(String, _get_caption)
+ GDVIRTUAL0RC(String, _get_text)
+ GDVIRTUAL0RC(String, _get_category)
+
+ GDVIRTUAL0RC(int, _get_working_memory_size)
+
+ GDVIRTUAL4RC(Variant, _step, Array, Array, int, Array)
public:
enum StartMode { //replicated for step
diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp
index 8bf1c6cbfa..d8b88d6cd3 100644
--- a/modules/visual_script/visual_script_property_selector.cpp
+++ b/modules/visual_script/visual_script_property_selector.cpp
@@ -55,7 +55,7 @@ void VisualScriptPropertySelector::_sbox_input(const Ref<InputEvent> &p_ie) {
case KEY_DOWN:
case KEY_PAGEUP:
case KEY_PAGEDOWN: {
- search_options->call("_gui_input", k);
+ search_options->gui_input(k);
search_box->accept_event();
TreeItem *root = search_options->get_root();
@@ -74,6 +74,8 @@ void VisualScriptPropertySelector::_sbox_input(const Ref<InputEvent> &p_ie) {
current->select(0);
} break;
+ default:
+ break;
}
}
}
diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp
index 9fa49b8a1d..cded1e587c 100644
--- a/modules/visual_script/visual_script_yield_nodes.cpp
+++ b/modules/visual_script/visual_script_yield_nodes.cpp
@@ -93,7 +93,7 @@ String VisualScriptYield::get_text() const {
class VisualScriptNodeInstanceYield : public VisualScriptNodeInstance {
public:
VisualScriptYield::YieldMode mode;
- float wait_time;
+ double wait_time;
virtual int get_working_memory_size() const { return 1; } //yield needs at least 1
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
@@ -159,7 +159,7 @@ VisualScriptYield::YieldMode VisualScriptYield::get_yield_mode() {
return yield_mode;
}
-void VisualScriptYield::set_wait_time(float p_time) {
+void VisualScriptYield::set_wait_time(double p_time) {
if (wait_time == p_time) {
return;
}
@@ -167,7 +167,7 @@ void VisualScriptYield::set_wait_time(float p_time) {
ports_changed_notify();
}
-float VisualScriptYield::get_wait_time() {
+double VisualScriptYield::get_wait_time() {
return wait_time;
}
diff --git a/modules/visual_script/visual_script_yield_nodes.h b/modules/visual_script/visual_script_yield_nodes.h
index fa596173a6..6005ff30b0 100644
--- a/modules/visual_script/visual_script_yield_nodes.h
+++ b/modules/visual_script/visual_script_yield_nodes.h
@@ -47,7 +47,7 @@ public:
private:
YieldMode yield_mode;
- float wait_time;
+ double wait_time;
protected:
virtual void _validate_property(PropertyInfo &property) const override;
@@ -73,8 +73,8 @@ public:
void set_yield_mode(YieldMode p_mode);
YieldMode get_yield_mode();
- void set_wait_time(float p_time);
- float get_wait_time();
+ void set_wait_time(double p_time);
+ double get_wait_time();
virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp
index 69822f6ff3..d7263dcf43 100644
--- a/modules/websocket/emws_peer.cpp
+++ b/modules/websocket/emws_peer.cpp
@@ -54,7 +54,7 @@ Error EMWSPeer::read_msg(const uint8_t *p_data, uint32_t p_size, bool p_is_strin
}
Error EMWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
- ERR_FAIL_COND_V(_out_buf_size && (godot_js_websocket_buffered_amount(peer_sock) >= (1ULL << _out_buf_size)), ERR_OUT_OF_MEMORY);
+ ERR_FAIL_COND_V(_out_buf_size && ((uint64_t)godot_js_websocket_buffered_amount(peer_sock) >= (1ULL << _out_buf_size)), ERR_OUT_OF_MEMORY);
int is_bin = write_mode == WebSocketPeer::WRITE_MODE_BINARY ? 1 : 0;