diff options
Diffstat (limited to 'modules')
26 files changed, 594 insertions, 306 deletions
diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp index b3dfc2eecf..873c9c31b7 100644 --- a/modules/bullet/collision_object_bullet.cpp +++ b/modules/bullet/collision_object_bullet.cpp @@ -49,7 +49,9 @@ CollisionObjectBullet::ShapeWrapper::~ShapeWrapper() {} void CollisionObjectBullet::ShapeWrapper::set_transform(const Transform &p_transform) { + G_TO_B(p_transform.get_basis().get_scale(), scale); G_TO_B(p_transform, transform); + UNSCALE_BT_BASIS(transform); } void CollisionObjectBullet::ShapeWrapper::set_transform(const btTransform &p_transform) { transform = p_transform; @@ -235,7 +237,7 @@ void RigidCollisionObjectBullet::set_shape_transform(int p_index, const Transfor ERR_FAIL_INDEX(p_index, get_shape_count()); shapes[p_index].set_transform(p_transform); - on_shapes_changed(); + on_shape_changed(shapes[p_index].shape); } void RigidCollisionObjectBullet::remove_shape(ShapeBullet *p_shape) { @@ -320,7 +322,7 @@ void RigidCollisionObjectBullet::on_shapes_changed() { shpWrapper = &shapes[i]; if (shpWrapper->active) { if (!shpWrapper->bt_shape) { - shpWrapper->bt_shape = shpWrapper->shape->create_bt_shape(); + shpWrapper->bt_shape = shpWrapper->shape->create_bt_shape(shpWrapper->scale); } compoundShape->addChildShape(shpWrapper->transform, shpWrapper->bt_shape); } else { diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h index a9b8aee019..506976eabf 100644 --- a/modules/bullet/collision_object_bullet.h +++ b/modules/bullet/collision_object_bullet.h @@ -72,6 +72,7 @@ public: ShapeBullet *shape; btCollisionShape *bt_shape; btTransform transform; + btVector3 scale; bool active; ShapeWrapper() : @@ -102,6 +103,7 @@ public: shape = otherShape.shape; bt_shape = otherShape.bt_shape; transform = otherShape.transform; + scale = otherShape.scale; active = otherShape.active; } diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 0e293a38a6..f2115a5d50 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -204,7 +204,7 @@ void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() { const CollisionObjectBullet::ShapeWrapper *shape_wrapper; - btVector3 owner_body_scale(owner->get_bt_body_scale()); + btVector3 owner_scale(owner->get_bt_body_scale()); for (int i = shapes_count - 1; 0 <= i; --i) { shape_wrapper = &shapes_wrappers[i]; @@ -213,14 +213,14 @@ void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() { } shapes[i].transform = shape_wrapper->transform; - shapes[i].transform.getOrigin() *= owner_body_scale; + shapes[i].transform.getOrigin() *= owner_scale; switch (shape_wrapper->shape->get_type()) { case PhysicsServer::SHAPE_SPHERE: case PhysicsServer::SHAPE_BOX: case PhysicsServer::SHAPE_CAPSULE: case PhysicsServer::SHAPE_CONVEX_POLYGON: case PhysicsServer::SHAPE_RAY: { - shapes[i].shape = static_cast<btConvexShape *>(shape_wrapper->shape->create_bt_shape(owner_body_scale, safe_margin)); + shapes[i].shape = static_cast<btConvexShape *>(shape_wrapper->shape->create_bt_shape(owner_scale * shape_wrapper->scale, safe_margin)); } break; default: WARN_PRINT("This shape is not supported to be kinematic!"); diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp index ee1cc418bc..27eac4e6ee 100644 --- a/modules/bullet/shape_bullet.cpp +++ b/modules/bullet/shape_bullet.cpp @@ -48,11 +48,6 @@ ShapeBullet::ShapeBullet() {} ShapeBullet::~ShapeBullet() {} -btCollisionShape *ShapeBullet::create_bt_shape() { - btVector3 s(1, 1, 1); - return create_bt_shape(s); -} - btCollisionShape *ShapeBullet::create_bt_shape(const Vector3 &p_implicit_scale, real_t p_margin) { btVector3 s; G_TO_B(p_implicit_scale, s); @@ -82,7 +77,7 @@ void ShapeBullet::add_owner(ShapeOwnerBullet *p_owner) { void ShapeBullet::remove_owner(ShapeOwnerBullet *p_owner, bool p_permanentlyFromThisBody) { Map<ShapeOwnerBullet *, int>::Element *E = owners.find(p_owner); - ERR_FAIL_COND(!E); + if (!E) return; E->get()--; if (p_permanentlyFromThisBody || 0 >= E->get()) { owners.erase(E); diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h index 12fa9754bd..4a03c0f014 100644 --- a/modules/bullet/shape_bullet.h +++ b/modules/bullet/shape_bullet.h @@ -62,7 +62,6 @@ public: ShapeBullet(); virtual ~ShapeBullet(); - btCollisionShape *create_bt_shape(); btCollisionShape *create_bt_shape(const Vector3 &p_implicit_scale, real_t p_margin = 0); virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0) = 0; diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index 83dd055760..d60d8ba0e2 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -857,31 +857,31 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f btVector3 recover_initial_position(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_safe_position, RECOVERING_MOVEMENT_SCALE, recover_initial_position)) { - - // Add recover position to "From" and "To" transforms - body_safe_position.getOrigin() += recover_initial_position; - } else { + if (!recover_from_penetration(p_body, body_safe_position, RECOVERING_MOVEMENT_SCALE, recover_initial_position)) { break; } } + + // Add recover movement in order to make it safe + body_safe_position.getOrigin() += recover_initial_position; } #endif - btVector3 recovered_motion; - G_TO_B(p_motion, recovered_motion); - const int shape_count(p_body->get_shape_count()); + btVector3 motion; + G_TO_B(p_motion, motion); { /// phase two - sweep test, from a secure position without margin + const int shape_count(p_body->get_shape_count()); + #if debug_test_motion -//Vector3 sup_line; -//B_TO_G(body_safe_position.getOrigin(), sup_line); -//motionVec->clear(); -//motionVec->begin(Mesh::PRIMITIVE_LINES, NULL); -//motionVec->add_vertex(sup_line); -//motionVec->add_vertex(sup_line + p_motion * 10); -//motionVec->end(); + Vector3 sup_line; + B_TO_G(body_safe_position.getOrigin(), sup_line); + motionVec->clear(); + motionVec->begin(Mesh::PRIMITIVE_LINES, NULL); + motionVec->add_vertex(sup_line); + motionVec->add_vertex(sup_line + p_motion * 10); + motionVec->end(); #endif for (int shIndex = 0; shIndex < shape_count; ++shIndex) { @@ -898,7 +898,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f btTransform shape_world_from = body_safe_position * p_body->get_kinematic_utilities()->shapes[shIndex].transform; btTransform shape_world_to(shape_world_from); - shape_world_to.getOrigin() += recovered_motion; + shape_world_to.getOrigin() += motion; GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, IGNORE_AREAS_TRUE); btResult.m_collisionFilterGroup = p_body->get_collision_layer(); @@ -909,27 +909,30 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f if (btResult.hasHit()) { /// 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 - recovered_motion *= btResult.m_closestHitFraction; + motion *= btResult.m_closestHitFraction; } } + + body_safe_position.getOrigin() += motion; } bool has_penetration = false; { /// Phase three - Recover + contact test with margin + btVector3 delta_recover_movement(0, 0, 0); RecoverResult r_recover_result; bool l_has_penetration; real_t l_penetration_distance = 1e20; for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) { - l_has_penetration = recover_from_penetration(p_body, body_safe_position, RECOVERING_MOVEMENT_SCALE, recovered_motion, &r_recover_result); + l_has_penetration = recover_from_penetration(p_body, body_safe_position, RECOVERING_MOVEMENT_SCALE, delta_recover_movement, &r_recover_result); if (r_result) { #if PERFORM_INITIAL_UNSTACK - B_TO_G(recovered_motion + recover_initial_position, r_result->motion); + B_TO_G(motion + delta_recover_movement + recover_initial_position, r_result->motion); #else - B_TO_G(recovered_motion, r_result->motion); + B_TO_G(motion + delta_recover_movement, r_result->motion); #endif if (l_has_penetration) { has_penetration = true; @@ -942,7 +945,8 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f const btRigidBody *btRigid = static_cast<const btRigidBody *>(r_recover_result.other_collision_object); CollisionObjectBullet *collisionObject = static_cast<CollisionObjectBullet *>(btRigid->getUserPointer()); - r_result->remainder = p_motion - r_result->motion; // is the remaining movements + B_TO_G(motion, r_result->remainder); // is the remaining movements + r_result->remainder = p_motion - r_result->remainder; B_TO_G(r_recover_result.pointWorld, r_result->collision_point); B_TO_G(r_recover_result.normal, r_result->collision_normal); B_TO_G(btRigid->getVelocityInLocalPoint(r_recover_result.pointWorld - btRigid->getWorldTransform().getOrigin()), r_result->collider_velocity); // It calculates velocity at point and assign it using special function Bullet_to_Godot @@ -961,17 +965,14 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f //} #if debug_test_motion -//Vector3 sup_line2; -//B_TO_G(recovered_motion, sup_line2); -////Vector3 sup_pos; -////B_TO_G( pt.getPositionWorldOnB(), sup_pos); -//normalLine->clear(); -//normalLine->begin(Mesh::PRIMITIVE_LINES, NULL); -//normalLine->add_vertex(r_result->collision_point); -//normalLine->add_vertex(r_result->collision_point + r_result->collision_normal * 10); -//normalLine->end(); + Vector3 sup_line2; + B_TO_G(motion, sup_line2); + normalLine->clear(); + normalLine->begin(Mesh::PRIMITIVE_LINES, NULL); + normalLine->add_vertex(r_result->collision_point); + normalLine->add_vertex(r_result->collision_point + r_result->collision_normal * 10); + normalLine->end(); #endif - } else { r_result->remainder = Vector3(); } @@ -1019,7 +1020,7 @@ public: } }; -bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, btVector3 &r_recover_position, RecoverResult *r_recover_result) { +bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) { RecoverPenetrationBroadPhaseCallback recover_broad_result(p_body->get_bt_collision_object(), p_body->get_collision_layer(), p_body->get_collision_mask()); @@ -1043,7 +1044,7 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran body_shape_position = p_body_position * kin_shape.transform; body_shape_position_recovered = body_shape_position; - body_shape_position_recovered.getOrigin() += r_recover_position; + body_shape_position_recovered.getOrigin() += r_delta_recover_movement; kin_shape.shape->getAabb(body_shape_position_recovered, minAabb, maxAabb); dynamicsWorld->getBroadphase()->aabbTest(minAabb, maxAabb, recover_broad_result); @@ -1060,24 +1061,24 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran for (int x = cs->getNumChildShapes() - 1; 0 <= x; --x) { if (cs->getChildShape(x)->isConvex()) { - if (RFP_convex_convex_test(kin_shape.shape, static_cast<const btConvexShape *>(cs->getChildShape(x)), otherObject, x, body_shape_position_recovered, otherObject->getWorldTransform() * cs->getChildTransform(x), p_recover_movement_scale, r_recover_position, r_recover_result)) { + if (RFP_convex_convex_test(kin_shape.shape, static_cast<const btConvexShape *>(cs->getChildShape(x)), otherObject, x, body_shape_position, otherObject->getWorldTransform() * cs->getChildTransform(x), p_recover_movement_scale, r_delta_recover_movement, r_recover_result)) { penetration = true; } } else { - if (RFP_convex_world_test(kin_shape.shape, cs->getChildShape(x), p_body->get_bt_collision_object(), otherObject, kinIndex, x, body_shape_position_recovered, otherObject->getWorldTransform() * cs->getChildTransform(x), p_recover_movement_scale, r_recover_position, r_recover_result)) { + if (RFP_convex_world_test(kin_shape.shape, cs->getChildShape(x), p_body->get_bt_collision_object(), otherObject, kinIndex, x, body_shape_position, otherObject->getWorldTransform() * cs->getChildTransform(x), p_recover_movement_scale, r_delta_recover_movement, r_recover_result)) { penetration = true; } } } } else if (otherObject->getCollisionShape()->isConvex()) { /// Execute GJK test against object shape - if (RFP_convex_convex_test(kin_shape.shape, static_cast<const btConvexShape *>(otherObject->getCollisionShape()), otherObject, 0, body_shape_position_recovered, otherObject->getWorldTransform(), p_recover_movement_scale, r_recover_position, r_recover_result)) { + if (RFP_convex_convex_test(kin_shape.shape, static_cast<const btConvexShape *>(otherObject->getCollisionShape()), otherObject, 0, body_shape_position, otherObject->getWorldTransform(), p_recover_movement_scale, r_delta_recover_movement, r_recover_result)) { penetration = true; } } else { - if (RFP_convex_world_test(kin_shape.shape, otherObject->getCollisionShape(), p_body->get_bt_collision_object(), otherObject, kinIndex, 0, body_shape_position_recovered, otherObject->getWorldTransform(), p_recover_movement_scale, r_recover_position, r_recover_result)) { + if (RFP_convex_world_test(kin_shape.shape, otherObject->getCollisionShape(), p_body->get_bt_collision_object(), otherObject, kinIndex, 0, body_shape_position, otherObject->getWorldTransform(), p_recover_movement_scale, r_delta_recover_movement, r_recover_result)) { penetration = true; } @@ -1085,26 +1086,15 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran } } -#if debug_test_motion - Vector3 pos; - B_TO_G(p_body_position.getOrigin(), pos); - Vector3 sup_line; - B_TO_G(sum_recover_normals, sup_line); - motionVec->clear(); - motionVec->begin(Mesh::PRIMITIVE_LINES, NULL); - motionVec->add_vertex(pos); - motionVec->add_vertex(pos + (sup_line * 10)); - motionVec->end(); -#endif - return penetration; } -bool SpaceBullet::RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_recover_position, RecoverResult *r_recover_result) { +bool SpaceBullet::RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, 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) { // Initialize GJK input btGjkPairDetector::ClosestPointInput gjk_input; gjk_input.m_transformA = p_transformA; + gjk_input.m_transformA.getOrigin() += r_delta_recover_movement; gjk_input.m_transformB = p_transformB; // Perform GJK test @@ -1113,7 +1103,7 @@ bool SpaceBullet::RFP_convex_convex_test(const btConvexShape *p_shapeA, const bt gjk_pair_detector.getClosestPoints(gjk_input, result, 0); if (0 > result.m_distance) { // Has penetration - r_recover_position += result.m_normalOnBInWorld * (result.m_distance * -1 * p_recover_movement_scale); + r_delta_recover_movement += result.m_normalOnBInWorld * (result.m_distance * -1 * p_recover_movement_scale); if (r_recover_result) { if (result.m_distance < r_recover_result->penetration_distance) { @@ -1130,11 +1120,14 @@ bool SpaceBullet::RFP_convex_convex_test(const btConvexShape *p_shapeA, const bt return false; } -bool SpaceBullet::RFP_convex_world_test(const btConvexShape *p_shapeA, const btCollisionShape *p_shapeB, btCollisionObject *p_objectA, 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_recover_position, RecoverResult *r_recover_result) { +bool SpaceBullet::RFP_convex_world_test(const btConvexShape *p_shapeA, const btCollisionShape *p_shapeB, btCollisionObject *p_objectA, 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) { /// Contact test - btCollisionObjectWrapper obA(NULL, p_shapeA, p_objectA, p_transformA, -1, p_shapeId_A); + btTransform tA(p_transformA); + tA.getOrigin() += r_delta_recover_movement; + + btCollisionObjectWrapper obA(NULL, p_shapeA, p_objectA, tA, -1, p_shapeId_A); btCollisionObjectWrapper obB(NULL, p_shapeB, p_objectB, p_transformB, -1, p_shapeId_B); btCollisionAlgorithm *algorithm = dispatcher->findAlgorithm(&obA, &obB, NULL, BT_CLOSEST_POINT_ALGORITHMS); @@ -1147,7 +1140,7 @@ bool SpaceBullet::RFP_convex_world_test(const btConvexShape *p_shapeA, const btC dispatcher->freeCollisionAlgorithm(algorithm); if (contactPointResult.hasHit()) { - r_recover_position += contactPointResult.m_pointNormalWorld * (contactPointResult.m_penetration_distance * -1 * p_recover_movement_scale); + r_delta_recover_movement += contactPointResult.m_pointNormalWorld * (contactPointResult.m_penetration_distance * -1 * p_recover_movement_scale); if (r_recover_result) { if (contactPointResult.m_penetration_distance < r_recover_result->penetration_distance) { diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h index 8d31ab765b..0aeb407dcc 100644 --- a/modules/bullet/space_bullet.h +++ b/modules/bullet/space_bullet.h @@ -191,15 +191,20 @@ private: RecoverResult() : hasPenetration(false), - penetration_distance(1e20) {} + normal(0, 0, 0), + pointWorld(0, 0, 0), + penetration_distance(1e20), + other_compound_shape_index(0), + other_collision_object(NULL), + local_shape_most_recovered(0) {} }; - bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_from, btScalar p_recover_movement_scale, btVector3 &r_recover_position, RecoverResult *r_recover_result = NULL); + bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_from, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL); /// 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_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_movement_scale, btVector3 &r_recover_position, RecoverResult *r_recover_result = NULL); + bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL); /// This is an API that recover a kinematic object from penetration /// Using this we leave Bullet to select the best algorithm, For example GJK in case we have Convex Convex, or a Bullet accelerated algorithm - bool RFP_convex_world_test(const btConvexShape *p_shapeA, const btCollisionShape *p_shapeB, btCollisionObject *p_objectA, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_movement_scale, btVector3 &r_recover_position, RecoverResult *r_recover_result = NULL); + bool RFP_convex_world_test(const btConvexShape *p_shapeA, const btCollisionShape *p_shapeB, btCollisionObject *p_objectA, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL); }; #endif diff --git a/modules/gdnative/gdnative/string.cpp b/modules/gdnative/gdnative/string.cpp index 350dc540f7..9ce2b1406d 100644 --- a/modules/gdnative/gdnative/string.cpp +++ b/modules/gdnative/gdnative/string.cpp @@ -40,6 +40,24 @@ extern "C" { #endif +godot_int GDAPI godot_char_string_length(const godot_char_string *p_cs) { + const CharString *cs = (const CharString *)p_cs; + + return cs->length(); +} + +const char GDAPI *godot_char_string_get_data(const godot_char_string *p_cs) { + const CharString *cs = (const CharString *)p_cs; + + return cs->get_data(); +} + +void GDAPI godot_char_string_destroy(godot_char_string *p_cs) { + CharString *cs = (CharString *)p_cs; + + cs->~CharString(); +} + void GDAPI godot_string_new(godot_string *r_dest) { String *dest = (String *)r_dest; memnew_placement(dest, String); @@ -51,35 +69,11 @@ void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src memnew_placement(dest, String(*src)); } -void GDAPI godot_string_new_data(godot_string *r_dest, const char *p_contents, const int p_size) { - String *dest = (String *)r_dest; - memnew_placement(dest, String(String::utf8(p_contents, p_size))); -} - -void GDAPI godot_string_new_unicode_data(godot_string *r_dest, const wchar_t *p_contents, const int p_size) { +void GDAPI godot_string_new_with_wide_string(godot_string *r_dest, const wchar_t *p_contents, const int p_size) { String *dest = (String *)r_dest; memnew_placement(dest, String(p_contents, p_size)); } -void GDAPI godot_string_get_data(const godot_string *p_self, char *p_dest, int *p_size) { - String *self = (String *)p_self; - - if (p_size) { - // we have a length pointer, that means we either want to know - // the length or want to write *p_size bytes into a buffer - - CharString utf8_string = self->utf8(); - - int len = utf8_string.length(); - - if (p_dest) { - memcpy(p_dest, utf8_string.get_data(), *p_size); - } else { - *p_size = len; - } - } -} - wchar_t GDAPI *godot_string_operator_index(godot_string *p_self, const godot_int p_idx) { String *self = (String *)p_self; return &(self->operator[](p_idx)); @@ -90,7 +84,7 @@ wchar_t GDAPI godot_string_operator_index_const(const godot_string *p_self, cons return self->operator[](p_idx); } -const wchar_t GDAPI *godot_string_unicode_str(const godot_string *p_self) { +const wchar_t GDAPI *godot_string_wide_str(const godot_string *p_self) { const String *self = (const String *)p_self; return self->c_str(); } @@ -130,6 +124,26 @@ godot_int GDAPI godot_string_length(const godot_string *p_self) { /* Helpers */ +signed char GDAPI godot_string_casecmp_to(const godot_string *p_self, const godot_string *p_str) { + const String *self = (const String *)p_self; + const String *str = (const String *)p_str; + + return self->casecmp_to(*str); +} + +signed char GDAPI godot_string_nocasecmp_to(const godot_string *p_self, const godot_string *p_str) { + const String *self = (const String *)p_self; + const String *str = (const String *)p_str; + + return self->nocasecmp_to(*str); +} +signed char GDAPI godot_string_naturalnocasecmp_to(const godot_string *p_self, const godot_string *p_str) { + const String *self = (const String *)p_self; + const String *str = (const String *)p_str; + + return self->naturalnocasecmp_to(*str); +} + godot_bool GDAPI godot_string_begins_with(const godot_string *p_self, const godot_string *p_string) { const String *self = (const String *)p_self; const String *string = (const String *)p_string; @@ -534,7 +548,7 @@ godot_string GDAPI godot_string_capitalize(const godot_string *p_self) { memnew_placement(&result, String(self->capitalize())); return result; -}; +} godot_string GDAPI godot_string_camelcase_to_underscore(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -542,7 +556,7 @@ godot_string GDAPI godot_string_camelcase_to_underscore(const godot_string *p_se memnew_placement(&result, String(self->camelcase_to_underscore(false))); return result; -}; +} godot_string GDAPI godot_string_camelcase_to_underscore_lowercased(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -550,45 +564,45 @@ godot_string GDAPI godot_string_camelcase_to_underscore_lowercased(const godot_s memnew_placement(&result, String(self->camelcase_to_underscore())); return result; -}; +} double GDAPI godot_string_char_to_double(const char *p_what) { return String::to_double(p_what); -}; +} godot_int GDAPI godot_string_char_to_int(const char *p_what) { return String::to_int(p_what); -}; +} int64_t GDAPI godot_string_wchar_to_int(const wchar_t *p_str) { return String::to_int(p_str); -}; +} godot_int GDAPI godot_string_char_to_int_with_len(const char *p_what, godot_int p_len) { return String::to_int(p_what, p_len); -}; +} int64_t GDAPI godot_string_char_to_int64_with_len(const wchar_t *p_str, int p_len) { return String::to_int(p_str, p_len); -}; +} int64_t GDAPI godot_string_hex_to_int64(const godot_string *p_self) { const String *self = (const String *)p_self; return self->hex_to_int64(false); -}; +} int64_t GDAPI godot_string_hex_to_int64_with_prefix(const godot_string *p_self) { const String *self = (const String *)p_self; return self->hex_to_int64(); -}; +} int64_t GDAPI godot_string_to_int64(const godot_string *p_self) { const String *self = (const String *)p_self; return self->to_int64(); -}; +} double GDAPI godot_string_unicode_char_to_double(const wchar_t *p_str, const wchar_t **r_end) { return String::to_double(p_str, r_end); @@ -601,7 +615,7 @@ godot_string GDAPI godot_string_get_slice(const godot_string *p_self, godot_stri memnew_placement(&result, String(self->get_slice(*splitter, p_slice))); return result; -}; +} godot_string GDAPI godot_string_get_slicec(const godot_string *p_self, wchar_t p_splitter, godot_int p_slice) { const String *self = (const String *)p_self; @@ -609,7 +623,7 @@ godot_string GDAPI godot_string_get_slicec(const godot_string *p_self, wchar_t p memnew_placement(&result, String(self->get_slicec(p_splitter, p_slice))); return result; -}; +} godot_array GDAPI godot_string_split(const godot_string *p_self, const godot_string *p_splitter) { const String *self = (const String *)p_self; @@ -625,7 +639,7 @@ godot_array GDAPI godot_string_split(const godot_string *p_self, const godot_str } return result; -}; +} godot_array GDAPI godot_string_split_allow_empty(const godot_string *p_self, const godot_string *p_splitter) { const String *self = (const String *)p_self; @@ -641,7 +655,7 @@ godot_array GDAPI godot_string_split_allow_empty(const godot_string *p_self, con } return result; -}; +} godot_array GDAPI godot_string_split_floats(const godot_string *p_self, const godot_string *p_splitter) { const String *self = (const String *)p_self; @@ -657,7 +671,7 @@ godot_array GDAPI godot_string_split_floats(const godot_string *p_self, const go } return result; -}; +} godot_array GDAPI godot_string_split_floats_allows_empty(const godot_string *p_self, const godot_string *p_splitter) { const String *self = (const String *)p_self; @@ -673,7 +687,7 @@ godot_array GDAPI godot_string_split_floats_allows_empty(const godot_string *p_s } return result; -}; +} godot_array GDAPI godot_string_split_floats_mk(const godot_string *p_self, const godot_array *p_splitters) { const String *self = (const String *)p_self; @@ -696,7 +710,7 @@ godot_array GDAPI godot_string_split_floats_mk(const godot_string *p_self, const } return result; -}; +} godot_array GDAPI godot_string_split_floats_mk_allows_empty(const godot_string *p_self, const godot_array *p_splitters) { const String *self = (const String *)p_self; @@ -719,7 +733,7 @@ godot_array GDAPI godot_string_split_floats_mk_allows_empty(const godot_string * } return result; -}; +} godot_array GDAPI godot_string_split_ints(const godot_string *p_self, const godot_string *p_splitter) { const String *self = (const String *)p_self; @@ -735,7 +749,7 @@ godot_array GDAPI godot_string_split_ints(const godot_string *p_self, const godo } return result; -}; +} godot_array GDAPI godot_string_split_ints_allows_empty(const godot_string *p_self, const godot_string *p_splitter) { const String *self = (const String *)p_self; @@ -751,7 +765,7 @@ godot_array GDAPI godot_string_split_ints_allows_empty(const godot_string *p_sel } return result; -}; +} godot_array GDAPI godot_string_split_ints_mk(const godot_string *p_self, const godot_array *p_splitters) { const String *self = (const String *)p_self; @@ -774,7 +788,7 @@ godot_array GDAPI godot_string_split_ints_mk(const godot_string *p_self, const g } return result; -}; +} godot_array GDAPI godot_string_split_ints_mk_allows_empty(const godot_string *p_self, const godot_array *p_splitters) { const String *self = (const String *)p_self; @@ -797,7 +811,7 @@ godot_array GDAPI godot_string_split_ints_mk_allows_empty(const godot_string *p_ } return result; -}; +} godot_array GDAPI godot_string_split_spaces(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -812,22 +826,22 @@ godot_array GDAPI godot_string_split_spaces(const godot_string *p_self) { } return result; -}; +} godot_int GDAPI godot_string_get_slice_count(const godot_string *p_self, godot_string p_splitter) { const String *self = (const String *)p_self; String *splitter = (String *)&p_splitter; return self->get_slice_count(*splitter); -}; +} wchar_t GDAPI godot_string_char_lowercase(wchar_t p_char) { return String::char_lowercase(p_char); -}; +} wchar_t GDAPI godot_string_char_uppercase(wchar_t p_char) { return String::char_uppercase(p_char); -}; +} godot_string GDAPI godot_string_to_lower(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -835,7 +849,7 @@ godot_string GDAPI godot_string_to_lower(const godot_string *p_self) { memnew_placement(&result, String(self->to_lower())); return result; -}; +} godot_string GDAPI godot_string_to_upper(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -843,7 +857,7 @@ godot_string GDAPI godot_string_to_upper(const godot_string *p_self) { memnew_placement(&result, String(self->to_upper())); return result; -}; +} godot_string GDAPI godot_string_get_basename(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -851,7 +865,7 @@ godot_string GDAPI godot_string_get_basename(const godot_string *p_self) { memnew_placement(&result, String(self->get_basename())); return result; -}; +} godot_string GDAPI godot_string_get_extension(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -859,7 +873,7 @@ godot_string GDAPI godot_string_get_extension(const godot_string *p_self) { memnew_placement(&result, String(self->get_extension())); return result; -}; +} godot_string GDAPI godot_string_left(const godot_string *p_self, godot_int p_pos) { const String *self = (const String *)p_self; @@ -867,13 +881,13 @@ godot_string GDAPI godot_string_left(const godot_string *p_self, godot_int p_pos memnew_placement(&result, String(self->left(p_pos))); return result; -}; +} wchar_t GDAPI godot_string_ord_at(const godot_string *p_self, godot_int p_idx) { const String *self = (const String *)p_self; return self->ord_at(p_idx); -}; +} godot_string GDAPI godot_string_plus_file(const godot_string *p_self, const godot_string *p_file) { const String *self = (const String *)p_self; @@ -882,7 +896,7 @@ godot_string GDAPI godot_string_plus_file(const godot_string *p_self, const godo memnew_placement(&result, String(self->plus_file(*file))); return result; -}; +} godot_string GDAPI godot_string_right(const godot_string *p_self, godot_int p_pos) { const String *self = (const String *)p_self; @@ -890,7 +904,7 @@ godot_string GDAPI godot_string_right(const godot_string *p_self, godot_int p_po memnew_placement(&result, String(self->right(p_pos))); return result; -}; +} godot_string GDAPI godot_string_strip_edges(const godot_string *p_self, godot_bool p_left, godot_bool p_right) { const String *self = (const String *)p_self; @@ -898,7 +912,7 @@ godot_string GDAPI godot_string_strip_edges(const godot_string *p_self, godot_bo memnew_placement(&result, String(self->strip_edges(p_left, p_right))); return result; -}; +} godot_string GDAPI godot_string_strip_escapes(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -906,94 +920,96 @@ godot_string GDAPI godot_string_strip_escapes(const godot_string *p_self) { memnew_placement(&result, String(self->strip_escapes())); return result; -}; +} void GDAPI godot_string_erase(godot_string *p_self, godot_int p_pos, godot_int p_chars) { String *self = (String *)p_self; return self->erase(p_pos, p_chars); -}; +} -void GDAPI godot_string_ascii(godot_string *p_self, char *result) { - String *self = (String *)p_self; - Vector<char> return_value = self->ascii(); +godot_char_string GDAPI godot_string_ascii(const godot_string *p_self) { + const String *self = (const String *)p_self; + godot_char_string result; - for (int i = 0; i < return_value.size(); i++) { - result[i] = return_value[i]; - } + memnew_placement(&result, String(self->ascii())); + + return result; } -void GDAPI godot_string_ascii_extended(godot_string *p_self, char *result) { - String *self = (String *)p_self; - Vector<char> return_value = self->ascii(true); +godot_char_string GDAPI godot_string_ascii_extended(const godot_string *p_self) { + const String *self = (const String *)p_self; - for (int i = 0; i < return_value.size(); i++) { - result[i] = return_value[i]; - } + godot_char_string result; + + memnew_placement(&result, String(self->ascii(true))); + + return result; } -void GDAPI godot_string_utf8(godot_string *p_self, char *result) { - String *self = (String *)p_self; - Vector<char> return_value = self->utf8(); +godot_char_string GDAPI godot_string_utf8(const godot_string *p_self) { + const String *self = (const String *)p_self; - for (int i = 0; i < return_value.size(); i++) { - result[i] = return_value[i]; - } + godot_char_string result; + + memnew_placement(&result, String(self->utf8())); + + return result; } godot_bool GDAPI godot_string_parse_utf8(godot_string *p_self, const char *p_utf8) { String *self = (String *)p_self; return self->parse_utf8(p_utf8); -}; +} godot_bool GDAPI godot_string_parse_utf8_with_len(godot_string *p_self, const char *p_utf8, godot_int p_len) { String *self = (String *)p_self; return self->parse_utf8(p_utf8, p_len); -}; +} godot_string GDAPI godot_string_chars_to_utf8(const char *p_utf8) { godot_string result; memnew_placement(&result, String(String::utf8(p_utf8))); return result; -}; +} godot_string GDAPI godot_string_chars_to_utf8_with_len(const char *p_utf8, godot_int p_len) { godot_string result; memnew_placement(&result, String(String::utf8(p_utf8, p_len))); return result; -}; +} uint32_t GDAPI godot_string_hash(const godot_string *p_self) { const String *self = (const String *)p_self; return self->hash(); -}; +} uint64_t GDAPI godot_string_hash64(const godot_string *p_self) { const String *self = (const String *)p_self; return self->hash64(); -}; +} uint32_t GDAPI godot_string_hash_chars(const char *p_cstr) { return String::hash(p_cstr); -}; +} uint32_t GDAPI godot_string_hash_chars_with_len(const char *p_cstr, godot_int p_len) { return String::hash(p_cstr, p_len); -}; +} uint32_t GDAPI godot_string_hash_utf8_chars(const wchar_t *p_str) { return String::hash(p_str); -}; +} uint32_t GDAPI godot_string_hash_utf8_chars_with_len(const wchar_t *p_str, godot_int p_len) { return String::hash(p_str, p_len); -}; +} godot_pool_byte_array GDAPI godot_string_md5_buffer(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1010,7 +1026,7 @@ godot_pool_byte_array GDAPI godot_string_md5_buffer(const godot_string *p_self) } return result; -}; +} godot_string GDAPI godot_string_md5_text(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1018,7 +1034,7 @@ godot_string GDAPI godot_string_md5_text(const godot_string *p_self) { memnew_placement(&result, String(self->md5_text())); return result; -}; +} godot_pool_byte_array GDAPI godot_string_sha256_buffer(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1035,7 +1051,7 @@ godot_pool_byte_array GDAPI godot_string_sha256_buffer(const godot_string *p_sel } return result; -}; +} godot_string GDAPI godot_string_sha256_text(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1043,13 +1059,13 @@ godot_string GDAPI godot_string_sha256_text(const godot_string *p_self) { memnew_placement(&result, String(self->sha256_text())); return result; -}; +} godot_bool godot_string_empty(const godot_string *p_self) { const String *self = (const String *)p_self; return self->empty(); -}; +} // path functions godot_string GDAPI godot_string_get_base_dir(const godot_string *p_self) { @@ -1059,7 +1075,7 @@ godot_string GDAPI godot_string_get_base_dir(const godot_string *p_self) { memnew_placement(&result, String(return_value)); return result; -}; +} godot_string GDAPI godot_string_get_file(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1068,7 +1084,7 @@ godot_string GDAPI godot_string_get_file(const godot_string *p_self) { memnew_placement(&result, String(return_value)); return result; -}; +} godot_string GDAPI godot_string_humanize_size(size_t p_size) { godot_string result; @@ -1076,25 +1092,25 @@ godot_string GDAPI godot_string_humanize_size(size_t p_size) { memnew_placement(&result, String(return_value)); return result; -}; +} godot_bool GDAPI godot_string_is_abs_path(const godot_string *p_self) { const String *self = (const String *)p_self; return self->is_abs_path(); -}; +} godot_bool GDAPI godot_string_is_rel_path(const godot_string *p_self) { const String *self = (const String *)p_self; return self->is_rel_path(); -}; +} godot_bool GDAPI godot_string_is_resource_file(const godot_string *p_self) { const String *self = (const String *)p_self; return self->is_resource_file(); -}; +} godot_string GDAPI godot_string_path_to(const godot_string *p_self, const godot_string *p_path) { const String *self = (const String *)p_self; @@ -1104,7 +1120,7 @@ godot_string GDAPI godot_string_path_to(const godot_string *p_self, const godot_ memnew_placement(&result, String(return_value)); return result; -}; +} godot_string GDAPI godot_string_path_to_file(const godot_string *p_self, const godot_string *p_path) { const String *self = (const String *)p_self; @@ -1114,7 +1130,7 @@ godot_string GDAPI godot_string_path_to_file(const godot_string *p_self, const g memnew_placement(&result, String(return_value)); return result; -}; +} godot_string GDAPI godot_string_simplify_path(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1123,7 +1139,7 @@ godot_string GDAPI godot_string_simplify_path(const godot_string *p_self) { memnew_placement(&result, String(return_value)); return result; -}; +} godot_string GDAPI godot_string_c_escape(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1132,7 +1148,7 @@ godot_string GDAPI godot_string_c_escape(const godot_string *p_self) { memnew_placement(&result, String(return_value)); return result; -}; +} godot_string GDAPI godot_string_c_escape_multiline(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1141,7 +1157,7 @@ godot_string GDAPI godot_string_c_escape_multiline(const godot_string *p_self) { memnew_placement(&result, String(return_value)); return result; -}; +} godot_string GDAPI godot_string_c_unescape(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1150,7 +1166,7 @@ godot_string GDAPI godot_string_c_unescape(const godot_string *p_self) { memnew_placement(&result, String(return_value)); return result; -}; +} godot_string GDAPI godot_string_http_escape(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1159,7 +1175,7 @@ godot_string GDAPI godot_string_http_escape(const godot_string *p_self) { memnew_placement(&result, String(return_value)); return result; -}; +} godot_string GDAPI godot_string_http_unescape(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1168,7 +1184,7 @@ godot_string GDAPI godot_string_http_unescape(const godot_string *p_self) { memnew_placement(&result, String(return_value)); return result; -}; +} godot_string GDAPI godot_string_json_escape(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1177,7 +1193,7 @@ godot_string GDAPI godot_string_json_escape(const godot_string *p_self) { memnew_placement(&result, String(return_value)); return result; -}; +} godot_string GDAPI godot_string_word_wrap(const godot_string *p_self, godot_int p_chars_per_line) { const String *self = (const String *)p_self; @@ -1186,7 +1202,7 @@ godot_string GDAPI godot_string_word_wrap(const godot_string *p_self, godot_int memnew_placement(&result, String(return_value)); return result; -}; +} godot_string GDAPI godot_string_xml_escape(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1195,7 +1211,7 @@ godot_string GDAPI godot_string_xml_escape(const godot_string *p_self) { memnew_placement(&result, String(return_value)); return result; -}; +} godot_string GDAPI godot_string_xml_escape_with_quotes(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1204,7 +1220,7 @@ godot_string GDAPI godot_string_xml_escape_with_quotes(const godot_string *p_sel memnew_placement(&result, String(return_value)); return result; -}; +} godot_string GDAPI godot_string_xml_unescape(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1213,7 +1229,7 @@ godot_string GDAPI godot_string_xml_unescape(const godot_string *p_self) { memnew_placement(&result, String(return_value)); return result; -}; +} godot_string GDAPI godot_string_percent_decode(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1222,7 +1238,7 @@ godot_string GDAPI godot_string_percent_decode(const godot_string *p_self) { memnew_placement(&result, String(return_value)); return result; -}; +} godot_string GDAPI godot_string_percent_encode(const godot_string *p_self) { const String *self = (const String *)p_self; @@ -1231,43 +1247,43 @@ godot_string GDAPI godot_string_percent_encode(const godot_string *p_self) { memnew_placement(&result, String(return_value)); return result; -}; +} godot_bool GDAPI godot_string_is_valid_float(const godot_string *p_self) { const String *self = (const String *)p_self; return self->is_valid_float(); -}; +} godot_bool GDAPI godot_string_is_valid_hex_number(const godot_string *p_self, godot_bool p_with_prefix) { const String *self = (const String *)p_self; return self->is_valid_hex_number(p_with_prefix); -}; +} godot_bool GDAPI godot_string_is_valid_html_color(const godot_string *p_self) { const String *self = (const String *)p_self; return self->is_valid_html_color(); -}; +} godot_bool GDAPI godot_string_is_valid_identifier(const godot_string *p_self) { const String *self = (const String *)p_self; return self->is_valid_identifier(); -}; +} godot_bool GDAPI godot_string_is_valid_integer(const godot_string *p_self) { const String *self = (const String *)p_self; return self->is_valid_integer(); -}; +} godot_bool GDAPI godot_string_is_valid_ip_address(const godot_string *p_self) { const String *self = (const String *)p_self; return self->is_valid_ip_address(); -}; +} #ifdef __cplusplus } diff --git a/modules/gdnative/gdnative/transform.cpp b/modules/gdnative/gdnative/transform.cpp index 9bd8c99612..715f2e3c08 100644 --- a/modules/gdnative/gdnative/transform.cpp +++ b/modules/gdnative/gdnative/transform.cpp @@ -63,7 +63,7 @@ godot_basis GDAPI godot_transform_get_basis(const godot_transform *p_self) { return dest; } -void GDAPI godot_transform_set_basis(godot_transform *p_self, godot_basis *p_v) { +void GDAPI godot_transform_set_basis(godot_transform *p_self, const godot_basis *p_v) { Transform *self = (Transform *)p_self; const Basis *v = (const Basis *)p_v; self->basis = *v; @@ -76,7 +76,7 @@ godot_vector3 GDAPI godot_transform_get_origin(const godot_transform *p_self) { return dest; } -void GDAPI godot_transform_set_origin(godot_transform *p_self, godot_vector3 *p_v) { +void GDAPI godot_transform_set_origin(godot_transform *p_self, const godot_vector3 *p_v) { Transform *self = (Transform *)p_self; const Vector3 *v = (const Vector3 *)p_v; self->origin = *v; diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index 06c6e9f410..6e3cf16758 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -3516,7 +3516,7 @@ "return_type": "void", "arguments": [ ["godot_transform *", "p_self"], - ["godot_basis *", "p_v"] + ["const godot_basis *", "p_v"] ] }, { @@ -3531,7 +3531,7 @@ "return_type": "void", "arguments": [ ["godot_transform *", "p_self"], - ["godot_vector3 *", "p_v"] + ["const godot_vector3 *", "p_v"] ] }, { @@ -4324,45 +4324,48 @@ ] }, { - "name": "godot_string_new", - "return_type": "void", + "name": "godot_char_string_length", + "return_type": "godot_int", "arguments": [ - ["godot_string *", "r_dest"] + ["const godot_char_string *", "p_cs"] ] }, { - "name": "godot_string_new_copy", + "name": "godot_char_string_get_data", + "return_type": "const char *", + "arguments": [ + ["const godot_char_string *", "p_cs"] + ] + }, + { + "name": "godot_char_string_destroy", "return_type": "void", "arguments": [ - ["godot_string *", "r_dest"], - ["const godot_string *", "p_src"] + ["godot_char_string *", "p_cs"] ] }, { - "name": "godot_string_new_data", + "name": "godot_string_new", "return_type": "void", "arguments": [ - ["godot_string *", "r_dest"], - ["const char *", "p_contents"], - ["const int", "p_size"] + ["godot_string *", "r_dest"] ] }, { - "name": "godot_string_new_unicode_data", + "name": "godot_string_new_copy", "return_type": "void", "arguments": [ ["godot_string *", "r_dest"], - ["const wchar_t *", "p_contents"], - ["const int", "p_size"] + ["const godot_string *", "p_src"] ] }, { - "name": "godot_string_get_data", + "name": "godot_string_new_with_wide_string", "return_type": "void", "arguments": [ - ["const godot_string *", "p_self"], - ["char *", "p_dest"], - ["int *", "p_size"] + ["godot_string *", "r_dest"], + ["const wchar_t *", "p_contents"], + ["const int", "p_size"] ] }, { @@ -4382,7 +4385,7 @@ ] }, { - "name": "godot_string_unicode_str", + "name": "godot_string_wide_str", "return_type": "const wchar_t *", "arguments": [ ["const godot_string *", "p_self"] @@ -4420,6 +4423,30 @@ ] }, { + "name": "godot_string_casecmp_to", + "return_type": "signed char", + "arguments": [ + ["const godot_string *", "p_self"], + ["const godot_string *", "p_str"] + ] + }, + { + "name": "godot_string_nocasecmp_to", + "return_type": "signed char", + "arguments": [ + ["const godot_string *", "p_self"], + ["const godot_string *", "p_str"] + ] + }, + { + "name": "godot_string_naturalnocasecmp_to", + "return_type": "signed char", + "arguments": [ + ["const godot_string *", "p_self"], + ["const godot_string *", "p_str"] + ] + }, + { "name": "godot_string_begins_with", "return_type": "godot_bool", "arguments": [ @@ -5125,26 +5152,23 @@ }, { "name": "godot_string_ascii", - "return_type": "void", + "return_type": "godot_char_string", "arguments": [ - ["godot_string *", "p_self"], - ["char *", "result"] + ["const godot_string *", "p_self"] ] }, { "name": "godot_string_ascii_extended", - "return_type": "void", + "return_type": "godot_char_string", "arguments": [ - ["godot_string *", "p_self"], - ["char *", "result"] + ["const godot_string *", "p_self"] ] }, { "name": "godot_string_utf8", - "return_type": "void", + "return_type": "godot_char_string", "arguments": [ - ["godot_string *", "p_self"], - ["char *", "result"] + ["const godot_string *", "p_self"] ] }, { diff --git a/modules/gdnative/include/gdnative/string.h b/modules/gdnative/include/gdnative/string.h index 080c0aa171..73245160c1 100644 --- a/modules/gdnative/include/gdnative/string.h +++ b/modules/gdnative/include/gdnative/string.h @@ -38,13 +38,24 @@ extern "C" { #include <stdint.h> #include <wchar.h> +typedef wchar_t godot_char_type; + #define GODOT_STRING_SIZE sizeof(void *) +#define GODOT_CHAR_STRING_SIZE sizeof(void *) #ifndef GODOT_CORE_API_GODOT_STRING_TYPE_DEFINED #define GODOT_CORE_API_GODOT_STRING_TYPE_DEFINED typedef struct { uint8_t _dont_touch_that[GODOT_STRING_SIZE]; } godot_string; + +#endif + +#ifndef GODOT_CORE_API_GODOT_CHAR_STRING_TYPE_DEFINED +#define GODOT_CORE_API_GODOT_CHAR_STRING_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_CHAR_STRING_SIZE]; +} godot_char_string; #endif // reduce extern "C" nesting for VS2013 @@ -60,16 +71,17 @@ typedef struct { extern "C" { #endif +godot_int GDAPI godot_char_string_length(const godot_char_string *p_cs); +const char GDAPI *godot_char_string_get_data(const godot_char_string *p_cs); +void GDAPI godot_char_string_destroy(godot_char_string *p_cs); + void GDAPI godot_string_new(godot_string *r_dest); void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src); -void GDAPI godot_string_new_data(godot_string *r_dest, const char *p_contents, const int p_size); -void GDAPI godot_string_new_unicode_data(godot_string *r_dest, const wchar_t *p_contents, const int p_size); - -void GDAPI godot_string_get_data(const godot_string *p_self, char *p_dest, int *p_size); +void GDAPI godot_string_new_with_wide_string(godot_string *r_dest, const wchar_t *p_contents, const int p_size); wchar_t GDAPI *godot_string_operator_index(godot_string *p_self, const godot_int p_idx); wchar_t GDAPI godot_string_operator_index_const(const godot_string *p_self, const godot_int p_idx); -const wchar_t GDAPI *godot_string_unicode_str(const godot_string *p_self); +const wchar_t GDAPI *godot_string_wide_str(const godot_string *p_self); godot_bool GDAPI godot_string_operator_equal(const godot_string *p_self, const godot_string *p_b); godot_bool GDAPI godot_string_operator_less(const godot_string *p_self, const godot_string *p_b); @@ -81,6 +93,10 @@ godot_int GDAPI godot_string_length(const godot_string *p_self); /* Helpers */ +signed char GDAPI godot_string_casecmp_to(const godot_string *p_self, const godot_string *p_str); +signed char GDAPI godot_string_nocasecmp_to(const godot_string *p_self, const godot_string *p_str); +signed char GDAPI godot_string_naturalnocasecmp_to(const godot_string *p_self, const godot_string *p_str); + godot_bool GDAPI godot_string_begins_with(const godot_string *p_self, const godot_string *p_string); godot_bool GDAPI godot_string_begins_with_char_array(const godot_string *p_self, const char *p_char_array); godot_array GDAPI godot_string_bigrams(const godot_string *p_self); @@ -177,9 +193,9 @@ godot_string GDAPI godot_string_strip_escapes(const godot_string *p_self); void GDAPI godot_string_erase(godot_string *p_self, godot_int p_pos, godot_int p_chars); -void GDAPI godot_string_ascii(godot_string *p_self, char *result); -void GDAPI godot_string_ascii_extended(godot_string *p_self, char *result); -void GDAPI godot_string_utf8(godot_string *p_self, char *result); +godot_char_string GDAPI godot_string_ascii(const godot_string *p_self); +godot_char_string GDAPI godot_string_ascii_extended(const godot_string *p_self); +godot_char_string GDAPI godot_string_utf8(const godot_string *p_self); godot_bool GDAPI godot_string_parse_utf8(godot_string *p_self, const char *p_utf8); godot_bool GDAPI godot_string_parse_utf8_with_len(godot_string *p_self, const char *p_utf8, godot_int p_len); godot_string GDAPI godot_string_chars_to_utf8(const char *p_utf8); diff --git a/modules/gdnative/include/gdnative/transform.h b/modules/gdnative/include/gdnative/transform.h index 10a242b205..a646da146a 100644 --- a/modules/gdnative/include/gdnative/transform.h +++ b/modules/gdnative/include/gdnative/transform.h @@ -64,10 +64,10 @@ void GDAPI godot_transform_new_with_axis_origin(godot_transform *r_dest, const g void GDAPI godot_transform_new(godot_transform *r_dest, const godot_basis *p_basis, const godot_vector3 *p_origin); godot_basis GDAPI godot_transform_get_basis(const godot_transform *p_self); -void GDAPI godot_transform_set_basis(godot_transform *p_self, godot_basis *p_v); +void GDAPI godot_transform_set_basis(godot_transform *p_self, const godot_basis *p_v); godot_vector3 GDAPI godot_transform_get_origin(const godot_transform *p_self); -void GDAPI godot_transform_set_origin(godot_transform *p_self, godot_vector3 *p_v); +void GDAPI godot_transform_set_origin(godot_transform *p_self, const godot_vector3 *p_v); godot_string GDAPI godot_transform_as_string(const godot_transform *p_self); diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp index 2405afc677..8101ebc6f3 100644 --- a/modules/gdnative/pluginscript/pluginscript_language.cpp +++ b/modules/gdnative/pluginscript/pluginscript_language.cpp @@ -45,7 +45,11 @@ void PluginScriptLanguage::init() { } String PluginScriptLanguage::get_type() const { - return String(_desc.type); + // We should use _desc.type here, however the returned type is used to + // query ClassDB which would complain given the type is not registered + // from his point of view... + // To solve this we just use a more generic (but present in ClassDB) type. + return String("PluginScript"); } String PluginScriptLanguage::get_extension() const { @@ -168,7 +172,7 @@ Error PluginScriptLanguage::complete_code(const String &p_code, const String &p_ for (int i = 0; i < options.size(); i++) { r_options->push_back(String(options[i])); } - Error err = *(Error *)tmp; + Error err = *(Error *)&tmp; return err; } return ERR_UNAVAILABLE; diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index b5bbaa6dc9..9566e3b32e 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -349,7 +349,9 @@ public: csi.resize(_debug_call_stack_pos); for (int i = 0; i < _debug_call_stack_pos; i++) { csi[_debug_call_stack_pos - i - 1].line = _call_stack[i].line ? *_call_stack[i].line : 0; - csi[_debug_call_stack_pos - i - 1].script = Ref<GDScript>(_call_stack[i].function->get_script()); + if (_call_stack[i].function) + csi[_debug_call_stack_pos - i - 1].func = _call_stack[i].function->get_name(); + csi[_debug_call_stack_pos - i - 1].file = _call_stack[i].function->get_script()->get_path(); } return csi; } diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 949c636050..db2d0a9780 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -445,6 +445,72 @@ String CSharpLanguage::_get_indentation() const { return "\t"; } +Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() { + + // Printing an error here will result in endless recursion, so we must be careful + + if (!gdmono->is_runtime_initialized() && GDMono::get_singleton()->get_api_assembly()) + return Vector<StackInfo>(); + + MonoObject *stack_trace = mono_object_new(mono_domain_get(), CACHED_CLASS(System_Diagnostics_StackTrace)->get_mono_ptr()); + + MonoBoolean need_file_info = true; + void *ctor_args[1] = { &need_file_info }; + + CACHED_METHOD(System_Diagnostics_StackTrace, ctor_bool)->invoke_raw(stack_trace, ctor_args); + + Vector<StackInfo> si; + si = stack_trace_get_info(stack_trace); + + return si; +} + +Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObject *p_stack_trace) { + + // Printing an error here could result in endless recursion, so we must be careful + + MonoObject *exc = NULL; + + GDMonoUtils::StackTrace_GetFrames st_get_frames = CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames); + MonoArray *frames = st_get_frames(p_stack_trace, &exc); + + if (exc) { + GDMonoUtils::print_unhandled_exception(exc, true /* fail silently to avoid endless recursion */); + return Vector<StackInfo>(); + } + + int frame_count = mono_array_length(frames); + + if (frame_count <= 0) + return Vector<StackInfo>(); + + GDMonoUtils::DebugUtils_StackFrameInfo get_sf_info = CACHED_METHOD_THUNK(DebuggingUtils, GetStackFrameInfo); + + Vector<StackInfo> si; + si.resize(frame_count); + + for (int i = 0; i < frame_count; i++) { + StackInfo &sif = si[i]; + MonoObject *frame = mono_array_get(frames, MonoObject *, i); + + MonoString *file_name; + int file_line_num; + MonoString *method_decl; + get_sf_info(frame, &file_name, &file_line_num, &method_decl, &exc); + + if (exc) { + GDMonoUtils::print_unhandled_exception(exc, true /* fail silently to avoid endless recursion */); + return Vector<StackInfo>(); + } + + sif.file = GDMonoMarshal::mono_string_to_godot(file_name); + sif.line = file_line_num; + sif.func = GDMonoMarshal::mono_string_to_godot(method_decl); + } + + return si; +} + void CSharpLanguage::frame() { const Ref<MonoGCHandle> &task_scheduler_handle = GDMonoUtils::mono_cache.task_scheduler_handle; @@ -1049,7 +1115,7 @@ bool CSharpInstance::has_method(const StringName &p_method) const { GDMonoClass *top = script->script_class; while (top && top != script->native) { - if (top->has_method(p_method)) { + if (top->has_fetched_method_unknown_params(p_method)) { return true; } @@ -1227,7 +1293,7 @@ ScriptInstance::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) GDMonoClass *top = script->script_class; while (top && top != script->native) { - GDMonoMethod *method = top->get_method(p_method); + GDMonoMethod *method = top->get_fetched_method_unknown_params(p_method); if (method && !method->is_static()) return _member_get_rpc_mode(method); @@ -1848,7 +1914,7 @@ void CSharpScript::set_source_code(const String &p_code) { bool CSharpScript::has_method(const StringName &p_method) const { - return script_class->has_method(p_method); + return script_class->has_fetched_method_unknown_params(p_method); } Error CSharpScript::reload(bool p_keep_state) { diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 171601f3d8..3ce8a9b64e 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -303,7 +303,7 @@ public: /* TODO */ virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {} /* TODO */ virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {} /* TODO */ virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { return ""; } - /* TODO */ virtual Vector<StackInfo> debug_get_current_stack_info() { return Vector<StackInfo>(); } + virtual Vector<StackInfo> debug_get_current_stack_info(); /* PROFILING FUNCTIONS */ /* TODO */ virtual void profiling_start() {} @@ -335,6 +335,8 @@ public: virtual void *alloc_instance_binding_data(Object *p_object); virtual void free_instance_binding_data(void *p_data); + Vector<StackInfo> stack_trace_get_info(MonoObject *p_stack_trace); + CSharpLanguage(); ~CSharpLanguage(); }; diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 2205ac4e98..800e3b723b 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -448,14 +448,14 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo compile_items.push_back(output_file); } - for (Map<StringName, TypeInterface>::Element *E = obj_types.front(); E; E = E->next()) { - const TypeInterface &itype = E->get(); + for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) { + const TypeInterface &itype = E.get(); if (itype.api_type == ClassDB::API_EDITOR) continue; - String output_file = path_join(obj_type_dir, E->get().proxy_name + ".cs"); - Error err = _generate_cs_type(E->get(), output_file); + String output_file = path_join(obj_type_dir, itype.proxy_name + ".cs"); + Error err = _generate_cs_type(itype, output_file); if (err == ERR_SKIP) continue; @@ -580,14 +580,14 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir, if (!solution.set_path(p_output_dir)) return ERR_FILE_NOT_FOUND; - for (Map<StringName, TypeInterface>::Element *E = obj_types.front(); E; E = E->next()) { - const TypeInterface &itype = E->get(); + for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) { + const TypeInterface &itype = E.get(); if (itype.api_type != ClassDB::API_EDITOR) continue; - String output_file = path_join(obj_type_dir, E->get().proxy_name + ".cs"); - Error err = _generate_cs_type(E->get(), output_file); + String output_file = path_join(obj_type_dir, itype.proxy_name + ".cs"); + Error err = _generate_cs_type(itype, output_file); if (err == ERR_SKIP) continue; @@ -945,7 +945,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str return ERR_BUG; } - Map<StringName, TypeInterface>::Element *object_itype = obj_types.find("Object"); + OrderedHashMap<StringName, TypeInterface>::Element object_itype = obj_types.find("Object"); if (!object_itype) { ERR_PRINT("BUG: Object type interface not found!"); @@ -953,7 +953,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str } output.push_back(MEMBER_BEGIN "public " CS_CLASS_SIGNALAWAITER " ToSignal("); - output.push_back(object_itype->get().cs_type); + output.push_back(object_itype.get().cs_type); output.push_back(" source, string signal)\n" OPEN_BLOCK_L2 "return new " CS_CLASS_SIGNALAWAITER "(source, signal, this);\n" CLOSE_BLOCK_L2); } @@ -999,9 +999,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte // Search it in base types too const TypeInterface *current_type = &p_itype; while (!setter && current_type->base_name != StringName()) { - Map<StringName, TypeInterface>::Element *base_match = obj_types.find(current_type->base_name); - ERR_FAIL_NULL_V(base_match, ERR_BUG); - current_type = &base_match->get(); + OrderedHashMap<StringName, TypeInterface>::Element base_match = obj_types.find(current_type->base_name); + ERR_FAIL_COND_V(!base_match, ERR_BUG); + current_type = &base_match.get(); setter = current_type->find_method_by_name(p_iprop.setter); } @@ -1010,9 +1010,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte // Search it in base types too current_type = &p_itype; while (!getter && current_type->base_name != StringName()) { - Map<StringName, TypeInterface>::Element *base_match = obj_types.find(current_type->base_name); - ERR_FAIL_NULL_V(base_match, ERR_BUG); - current_type = &base_match->get(); + OrderedHashMap<StringName, TypeInterface>::Element base_match = obj_types.find(current_type->base_name); + ERR_FAIL_COND_V(!base_match, ERR_BUG); + current_type = &base_match.get(); getter = current_type->find_method_by_name(p_iprop.getter); } @@ -1324,8 +1324,8 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) { generated_icall_funcs.clear(); - for (Map<StringName, TypeInterface>::Element *type_elem = obj_types.front(); type_elem; type_elem = type_elem->next()) { - const TypeInterface &itype = type_elem->get(); + for (OrderedHashMap<StringName, TypeInterface>::Element type_elem = obj_types.front(); type_elem; type_elem = type_elem.next()) { + const TypeInterface &itype = type_elem.get(); List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls; @@ -1631,20 +1631,20 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_null(const StringName &p_cname) { - const Map<StringName, TypeInterface>::Element *match = builtin_types.find(p_cname); + const Map<StringName, TypeInterface>::Element *builtin_type_match = builtin_types.find(p_cname); - if (match) - return &match->get(); + if (builtin_type_match) + return &builtin_type_match->get(); - match = obj_types.find(p_cname); + const OrderedHashMap<StringName, TypeInterface>::Element obj_type_match = obj_types.find(p_cname); - if (match) - return &match->get(); + if (obj_type_match) + return &obj_type_match.get(); - match = enum_types.find(p_cname); + const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(p_cname); - if (match) - return &match->get(); + if (enum_match) + return &enum_match->get(); return NULL; } @@ -2484,8 +2484,8 @@ void BindingsGenerator::initialize() { _generate_header_icalls(); - for (Map<StringName, TypeInterface>::Element *E = obj_types.front(); E; E = E->next()) - _generate_method_icalls(E->get()); + for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) + _generate_method_icalls(E.get()); _generate_method_icalls(builtin_types["NodePath"]); _generate_method_icalls(builtin_types["RID"]); diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index 717a6b7a6b..8929b45cce 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -429,10 +429,11 @@ class BindingsGenerator { static bool verbose_output; + OrderedHashMap<StringName, TypeInterface> obj_types; + Map<StringName, TypeInterface> placeholder_types; Map<StringName, TypeInterface> builtin_types; Map<StringName, TypeInterface> enum_types; - Map<StringName, TypeInterface> obj_types; List<EnumInterface> global_enums; List<ConstantInterface> global_constants; diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp index da0a7b4fbd..9e48da68c1 100644 --- a/modules/mono/editor/godotsharp_editor.cpp +++ b/modules/mono/editor/godotsharp_editor.cpp @@ -151,7 +151,7 @@ Error GodotSharpEditor::open_in_external_editor(const Ref<Script> &p_script, int if (p_line >= 0) { args.push_back("-g"); - args.push_back(script_path + ":" + itos(p_line) + ":" + itos(p_col)); + args.push_back(script_path + ":" + itos(p_line + 1) + ":" + itos(p_col)); } else { args.push_back(script_path); } @@ -170,6 +170,11 @@ Error GodotSharpEditor::open_in_external_editor(const Ref<Script> &p_script, int monodevel_instance = memnew(MonoDevelopInstance(GodotSharpDirs::get_project_sln_path())); String script_path = ProjectSettings::get_singleton()->globalize_path(p_script->get_path()); + + if (p_line >= 0) { + script_path += ";" + itos(p_line + 1) + ";" + itos(p_col); + } + monodevel_instance->execute(script_path); } break; default: diff --git a/modules/mono/glue/cs_files/Color.cs b/modules/mono/glue/cs_files/Color.cs index db0e1fb744..f9e31e9703 100644 --- a/modules/mono/glue/cs_files/Color.cs +++ b/modules/mono/glue/cs_files/Color.cs @@ -336,7 +336,7 @@ namespace Godot this.r = (rgba & 0xFF) / 255.0f; } - private static float _parse_col(string str, int ofs) + private static int _parse_col(string str, int ofs) { int ig = 0; @@ -415,17 +415,17 @@ namespace Godot if (alpha) { - if ((int)_parse_col(color, 0) < 0) + if (_parse_col(color, 0) < 0) return false; } int from = alpha ? 2 : 0; - if ((int)_parse_col(color, from + 0) < 0) + if (_parse_col(color, from + 0) < 0) return false; - if ((int)_parse_col(color, from + 2) < 0) + if (_parse_col(color, from + 2) < 0) return false; - if ((int)_parse_col(color, from + 4) < 0) + if (_parse_col(color, from + 4) < 0) return false; return true; @@ -467,10 +467,10 @@ namespace Godot if (alpha) { - a = _parse_col(rgba, 0); + a = _parse_col(rgba, 0) / 255f; if (a < 0) - throw new ArgumentOutOfRangeException("Invalid color code. Alpha is " + a + " but zero or greater is expected: " + rgba); + throw new ArgumentOutOfRangeException("Invalid color code. Alpha part is not valid hexadecimal: " + rgba); } else { @@ -479,20 +479,20 @@ namespace Godot int from = alpha ? 2 : 0; - r = _parse_col(rgba, from + 0); + r = _parse_col(rgba, from + 0) / 255f; if (r < 0) - throw new ArgumentOutOfRangeException("Invalid color code. Red is " + r + " but zero or greater is expected: " + rgba); + throw new ArgumentOutOfRangeException("Invalid color code. Red part is not valid hexadecimal: " + rgba); - g = _parse_col(rgba, from + 2); + g = _parse_col(rgba, from + 2) / 255f; if (g < 0) - throw new ArgumentOutOfRangeException("Invalid color code. Green is " + g + " but zero or greater is expected: " + rgba); + throw new ArgumentOutOfRangeException("Invalid color code. Green part is not valid hexadecimal: " + rgba); - b = _parse_col(rgba, from + 4); + b = _parse_col(rgba, from + 4) / 255f; if (b < 0) - throw new ArgumentOutOfRangeException("Invalid color code. Blue is " + b + " but zero or greater is expected: " + rgba); + throw new ArgumentOutOfRangeException("Invalid color code. Blue part is not valid hexadecimal: " + rgba); } public static bool operator ==(Color left, Color right) diff --git a/modules/mono/glue/cs_files/DebuggingUtils.cs b/modules/mono/glue/cs_files/DebuggingUtils.cs new file mode 100644 index 0000000000..ced78f658d --- /dev/null +++ b/modules/mono/glue/cs_files/DebuggingUtils.cs @@ -0,0 +1,77 @@ +using System; +using System.Diagnostics; +using System.Reflection; +using System.Text; + +namespace Godot +{ + internal static class DebuggingUtils + { + internal static void AppendTypeName(this StringBuilder sb, Type type) + { + if (type.IsPrimitive) + sb.Append(type.Name); + else if (type == typeof(void)) + sb.Append("void"); + else + sb.Append(type.ToString()); + + sb.Append(" "); + } + + public static void GetStackFrameInfo(StackFrame frame, out string fileName, out int fileLineNumber, out string methodDecl) + { + fileName = frame.GetFileName(); + fileLineNumber = frame.GetFileLineNumber(); + + MethodBase methodBase = frame.GetMethod(); + + StringBuilder sb = new StringBuilder(); + + if (methodBase is MethodInfo methodInfo) + sb.AppendTypeName(methodInfo.ReturnType); + + sb.Append(methodBase.DeclaringType.FullName); + sb.Append("."); + sb.Append(methodBase.Name); + + if (methodBase.IsGenericMethod) + { + Type[] genericParams = methodBase.GetGenericArguments(); + + sb.Append("<"); + + for (int j = 0; j < genericParams.Length; j++) + { + if (j > 0) + sb.Append(", "); + + sb.AppendTypeName(genericParams[j]); + } + + sb.Append(">"); + } + + sb.Append("("); + + bool varArgs = (methodBase.CallingConvention & CallingConventions.VarArgs) != 0; + + ParameterInfo[] parameter = methodBase.GetParameters(); + + for (int i = 0; i < parameter.Length; i++) + { + if (i > 0) + sb.Append(", "); + + if (i == parameter.Length - 1 && varArgs) + sb.Append("params "); + + sb.AppendTypeName(parameter[i].ParameterType); + } + + sb.Append(")"); + + methodDecl = sb.ToString(); + } + } +} diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index d4df7e0cb2..6c07c90f79 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -226,7 +226,7 @@ void GDMono::initialize() { mono_install_unhandled_exception_hook(gdmono_unhandled_exception_hook, NULL); - OS::get_singleton()->print("Mono: ALL IS GOOD\n"); + OS::get_singleton()->print("Mono: INITIALIZED\n"); } #ifndef MONO_GLUE_DISABLED diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp index d3315568cb..b826352f02 100644 --- a/modules/mono/mono_gd/gd_mono_class.cpp +++ b/modules/mono/mono_gd/gd_mono_class.cpp @@ -89,11 +89,6 @@ Vector<MonoClassField *> GDMonoClass::get_enum_fields() { } #endif -bool GDMonoClass::has_method(const StringName &p_name) { - - return get_method(p_name) != NULL; -} - bool GDMonoClass::has_attribute(GDMonoClass *p_attr_class) { #ifdef DEBUG_ENABLED @@ -225,7 +220,7 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base methods_fetched = true; } -GDMonoMethod *GDMonoClass::get_method(const StringName &p_name) { +GDMonoMethod *GDMonoClass::get_fetched_method_unknown_params(const StringName &p_name) { ERR_FAIL_COND_V(!methods_fetched, NULL); @@ -239,6 +234,11 @@ GDMonoMethod *GDMonoClass::get_method(const StringName &p_name) { return NULL; } +bool GDMonoClass::has_fetched_method_unknown_params(const StringName &p_name) { + + return get_fetched_method_unknown_params(p_name) != NULL; +} + GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_count) { MethodKey key = MethodKey(p_name, p_params_count); @@ -303,6 +303,8 @@ GDMonoMethod *GDMonoClass::get_method_with_desc(const String &p_description, boo MonoMethod *method = mono_method_desc_search_in_class(desc, mono_class); mono_method_desc_free(desc); + ERR_FAIL_COND_V(mono_method_get_class(method) != mono_class, NULL); + return get_method(method); } diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h index b6052ac0ed..f5895be144 100644 --- a/modules/mono/mono_gd/gd_mono_class.h +++ b/modules/mono/mono_gd/gd_mono_class.h @@ -112,7 +112,8 @@ public: Vector<MonoClassField *> get_enum_fields(); #endif - bool has_method(const StringName &p_name); + GDMonoMethod *get_fetched_method_unknown_params(const StringName &p_name); + bool has_fetched_method_unknown_params(const StringName &p_name); bool has_attribute(GDMonoClass *p_attr_class); MonoObject *get_attribute(GDMonoClass *p_attr_class); @@ -120,8 +121,7 @@ public: void fetch_attributes(); void fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base); - GDMonoMethod *get_method(const StringName &p_name); - GDMonoMethod *get_method(const StringName &p_name, int p_params_count); + GDMonoMethod *get_method(const StringName &p_name, int p_params_count = 0); GDMonoMethod *get_method(MonoMethod *p_raw_method); GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name); GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count); diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index ff999b36f2..d02c73978e 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -31,6 +31,7 @@ #include "gd_mono_utils.h" #include "os/dir_access.h" +#include "os/os.h" #include "project_settings.h" #include "reference.h" @@ -53,6 +54,7 @@ MonoCache mono_cache; #define CACHE_NS_CLASS_AND_CHECK(m_ns, m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.class_##m_ns##_##m_class, m_val) #define CACHE_RAW_MONO_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.rawclass_##m_class, m_val) #define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.field_##m_class##_##m_field, m_val) +#define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.method_##m_class##_##m_method, m_val) #define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method, m_val) void MonoCache::clear_members() { @@ -72,6 +74,13 @@ void MonoCache::clear_members() { class_String = NULL; class_IntPtr = NULL; +#ifdef DEBUG_ENABLED + class_System_Diagnostics_StackTrace = NULL; + methodthunk_System_Diagnostics_StackTrace_GetFrames = NULL; + method_System_Diagnostics_StackTrace_ctor_bool = NULL; + method_System_Diagnostics_StackTrace_ctor_Exception_bool = NULL; +#endif + rawclass_Dictionary = NULL; class_Vector2 = NULL; @@ -94,6 +103,11 @@ void MonoCache::clear_members() { class_WeakRef = NULL; class_MarshalUtils = NULL; +#ifdef DEBUG_ENABLED + class_DebuggingUtils = NULL; + methodthunk_DebuggingUtils_GetStackFrameInfo = NULL; +#endif + class_ExportAttribute = NULL; field_ExportAttribute_hint = NULL; field_ExportAttribute_hintString = NULL; @@ -137,6 +151,13 @@ void update_corlib_cache() { CACHE_CLASS_AND_CHECK(double, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_double_class())); CACHE_CLASS_AND_CHECK(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class())); CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class())); + +#ifdef DEBUG_ENABLED + CACHE_CLASS_AND_CHECK(System_Diagnostics_StackTrace, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Diagnostics", "StackTrace")); + CACHE_METHOD_THUNK_AND_CHECK(System_Diagnostics_StackTrace, GetFrames, (StackTrace_GetFrames)CACHED_CLASS(System_Diagnostics_StackTrace)->get_method("GetFrames")->get_thunk()); + CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(bool)", true)); + CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true)); +#endif } void update_godot_api_cache() { @@ -161,6 +182,10 @@ void update_godot_api_cache() { CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef)); CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils)); +#ifdef DEBUG_ENABLED + CACHE_CLASS_AND_CHECK(DebuggingUtils, GODOT_API_CLASS(DebuggingUtils)); +#endif + // Attributes CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute)); CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint")); @@ -183,6 +208,10 @@ void update_godot_api_cache() { CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("FailureCallback", 0)->get_thunk()); CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0)->get_thunk()); +#ifdef DEBUG_ENABLED + CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4)->get_thunk()); +#endif + { /* * TODO Right now we only support Dictionary<object, object>. @@ -366,9 +395,47 @@ String get_exception_name_and_message(MonoObject *p_ex) { return res; } -void print_unhandled_exception(MonoObject *p_ex) { - ERR_PRINT(GDMonoUtils::get_exception_name_and_message(p_ex).utf8()); - mono_print_unhandled_exception(p_ex); +void print_unhandled_exception(MonoObject *p_exc) { + print_unhandled_exception(p_exc, false); +} + +void print_unhandled_exception(MonoObject *p_exc, bool p_recursion_caution) { + mono_print_unhandled_exception(p_exc); +#ifdef DEBUG_ENABLED + GDMonoClass *st_klass = CACHED_CLASS(System_Diagnostics_StackTrace); + MonoObject *stack_trace = mono_object_new(mono_domain_get(), st_klass->get_mono_ptr()); + + MonoBoolean need_file_info = true; + void *ctor_args[2] = { p_exc, &need_file_info }; + + MonoObject *unexpected_exc = NULL; + CACHED_METHOD(System_Diagnostics_StackTrace, ctor_Exception_bool)->invoke_raw(stack_trace, ctor_args, &unexpected_exc); + + if (unexpected_exc != NULL) { + mono_print_unhandled_exception(unexpected_exc); + + if (p_recursion_caution) { + // Called from CSharpLanguage::get_current_stack_info, + // so printing an error here could result in endless recursion + OS::get_singleton()->printerr("Mono: Method GDMonoUtils::print_unhandled_exception failed"); + return; + } else { + ERR_FAIL(); + } + } + + Vector<ScriptLanguage::StackInfo> si; + if (stack_trace != NULL && !p_recursion_caution) + si = CSharpLanguage::get_singleton()->stack_trace_get_info(stack_trace); + + String file = si.size() ? si[0].file : __FILE__; + String func = si.size() ? si[0].func : FUNCTION_STR; + int line = si.size() ? si[0].line : __LINE__; + String error_msg = "Unhandled exception"; + String exc_msg = GDMonoUtils::get_exception_name_and_message(p_exc); + + ScriptDebugger::get_singleton()->send_error(func, file, line, error_msg, exc_msg, ERR_HANDLER_ERROR, si); +#endif } } // namespace GDMonoUtils diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index 284585856e..597397eced 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -46,13 +46,10 @@ typedef MonoObject *(*MarshalUtils_ArraysToDict)(MonoArray *, MonoArray *, MonoO typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray **, MonoObject **); typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoObject **); typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoObject **); +typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoObject **); +typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoObject **); struct MonoCache { - // Format for cached classes in the Godot namespace: class_<Class> - // Macro: CACHED_CLASS(<Class>) - - // Format for cached classes in a different namespace: class_<Namespace>_<Class> - // Macro: CACHED_NS_CLASS(<Namespace>, <Class>) // ----------------------------------------------- // corlib classes @@ -73,6 +70,13 @@ struct MonoCache { GDMonoClass *class_String; GDMonoClass *class_IntPtr; +#ifdef DEBUG_ENABLED + GDMonoClass *class_System_Diagnostics_StackTrace; + StackTrace_GetFrames methodthunk_System_Diagnostics_StackTrace_GetFrames; + GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool; + GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool; +#endif + MonoClass *rawclass_Dictionary; // ----------------------------------------------- @@ -96,6 +100,11 @@ struct MonoCache { GDMonoClass *class_WeakRef; GDMonoClass *class_MarshalUtils; +#ifdef DEBUG_ENABLED + GDMonoClass *class_DebuggingUtils; + DebugUtils_StackFrameInfo methodthunk_DebuggingUtils_GetStackFrameInfo; +#endif + GDMonoClass *class_ExportAttribute; GDMonoField *field_ExportAttribute_hint; GDMonoField *field_ExportAttribute_hintString; @@ -167,7 +176,8 @@ MonoDomain *create_domain(const String &p_friendly_name); String get_exception_name_and_message(MonoObject *p_ex); -void print_unhandled_exception(MonoObject *p_ex); +void print_unhandled_exception(MonoObject *p_exc); +void print_unhandled_exception(MonoObject *p_exc, bool p_recursion_caution); } // namespace GDMonoUtils @@ -175,9 +185,9 @@ void print_unhandled_exception(MonoObject *p_ex); #define CACHED_CLASS(m_class) (GDMonoUtils::mono_cache.class_##m_class) #define CACHED_CLASS_RAW(m_class) (GDMonoUtils::mono_cache.class_##m_class->get_mono_ptr()) -#define CACHED_NS_CLASS(m_ns, m_class) (GDMonoUtils::mono_cache.class_##m_ns##_##m_class) #define CACHED_RAW_MONO_CLASS(m_class) (GDMonoUtils::mono_cache.rawclass_##m_class) #define CACHED_FIELD(m_class, m_field) (GDMonoUtils::mono_cache.field_##m_class##_##m_field) +#define CACHED_METHOD(m_class, m_method) (GDMonoUtils::mono_cache.method_##m_class##_##m_method) #define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method) #ifdef REAL_T_IS_DOUBLE |