summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/bullet/bullet_physics_server.h2
-rw-r--r--modules/bullet/collision_object_bullet.cpp9
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.cpp40
-rw-r--r--modules/bullet/rigid_body_bullet.cpp5
-rw-r--r--modules/csg/csg_shape.cpp131
-rw-r--r--modules/csg/csg_shape.h18
-rw-r--r--modules/csg/doc_classes/CSGShape.xml3
-rw-r--r--modules/enet/doc_classes/NetworkedMultiplayerENet.xml2
-rw-r--r--modules/freetype/SCsub2
-rw-r--r--modules/gdnative/gdnative.cpp19
-rw-r--r--modules/gdnative/gdnative/array.cpp32
-rw-r--r--modules/gdnative/gdnative/basis.cpp9
-rw-r--r--modules/gdnative/gdnative/color.cpp41
-rw-r--r--modules/gdnative/gdnative/node_path.cpp9
-rw-r--r--modules/gdnative/gdnative/quat.cpp6
-rw-r--r--modules/gdnative/gdnative/rect2.cpp21
-rw-r--r--modules/gdnative/gdnative/string.cpp58
-rw-r--r--modules/gdnative/gdnative_api.json177
-rw-r--r--modules/gdnative/include/gdnative/array.h8
-rw-r--r--modules/gdnative/include/gdnative/basis.h2
-rw-r--r--modules/gdnative/include/gdnative/color.h14
-rw-r--r--modules/gdnative/include/gdnative/node_path.h2
-rw-r--r--modules/gdnative/include/gdnative/quat.h2
-rw-r--r--modules/gdnative/include/gdnative/rect2.h6
-rw-r--r--modules/gdnative/include/gdnative/string.h6
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp8
-rw-r--r--modules/gdscript/doc_classes/GDScript.xml2
-rw-r--r--modules/gdscript/gdscript_editor.cpp57
-rw-r--r--modules/gdscript/gdscript_function.cpp57
-rw-r--r--modules/gdscript/gdscript_functions.cpp51
-rw-r--r--modules/gdscript/gdscript_functions.h3
-rw-r--r--modules/gdscript/gdscript_parser.cpp99
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml2
-rw-r--r--modules/gridmap/grid_map.cpp2
-rw-r--r--modules/gridmap/grid_map_editor_plugin.cpp4
-rw-r--r--modules/mono/editor/csharp_project.cpp3
-rw-r--r--modules/mono/glue/Managed/Files/GD.cs16
-rw-r--r--modules/mono/glue/gd_glue.cpp10
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp2
-rw-r--r--modules/regex/regex.cpp8
-rw-r--r--modules/squish/image_compress_squish.cpp7
-rw-r--r--modules/visual_script/doc_classes/VisualScript.xml2
-rw-r--r--modules/visual_script/visual_script_editor.cpp21
-rw-r--r--modules/visual_script/visual_script_editor.h2
-rw-r--r--modules/websocket/emws_client.cpp14
-rw-r--r--modules/websocket/emws_client.h3
-rw-r--r--modules/websocket/emws_peer.cpp57
-rw-r--r--modules/websocket/emws_peer.h22
-rw-r--r--modules/websocket/emws_server.cpp4
-rw-r--r--modules/websocket/emws_server.h1
-rw-r--r--modules/websocket/lws_client.cpp25
-rw-r--r--modules/websocket/lws_client.h7
-rw-r--r--modules/websocket/lws_peer.cpp110
-rw-r--r--modules/websocket/lws_peer.h24
-rw-r--r--modules/websocket/lws_server.cpp11
-rw-r--r--modules/websocket/lws_server.h5
-rw-r--r--modules/websocket/packet_buffer.h122
-rw-r--r--modules/websocket/register_types.cpp17
-rw-r--r--modules/websocket/websocket_client.cpp2
-rw-r--r--modules/websocket/websocket_macros.h10
-rw-r--r--modules/websocket/websocket_multiplayer.cpp7
-rw-r--r--modules/websocket/websocket_multiplayer.h6
-rw-r--r--modules/websocket/websocket_peer.h1
63 files changed, 1141 insertions, 287 deletions
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index 6b7dcd86e6..c8c782267e 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -397,6 +397,8 @@ public:
virtual void flush_queries();
virtual void finish();
+ virtual bool is_flushing_queries() const { return false; }
+
virtual int get_process_info(ProcessInfo p_info);
CollisionObjectBullet *get_collisin_object(RID p_object) const;
diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp
index 402a276f95..441fa7c8af 100644
--- a/modules/bullet/collision_object_bullet.cpp
+++ b/modules/bullet/collision_object_bullet.cpp
@@ -304,7 +304,11 @@ bool RigidCollisionObjectBullet::is_shape_disabled(int p_index) {
}
void RigidCollisionObjectBullet::shape_changed(int p_shape_index) {
- bulletdelete(shapes.write[p_shape_index].bt_shape);
+ ShapeWrapper &shp = shapes.write[p_shape_index];
+ if (shp.bt_shape == mainShape) {
+ mainShape = NULL;
+ }
+ bulletdelete(shp.bt_shape);
reload_shapes();
}
@@ -366,5 +370,8 @@ void RigidCollisionObjectBullet::body_scale_changed() {
void RigidCollisionObjectBullet::internal_shape_destroy(int p_index, bool p_permanentlyFromThisBody) {
ShapeWrapper &shp = shapes.write[p_index];
shp.shape->remove_owner(this, p_permanentlyFromThisBody);
+ if (shp.bt_shape == mainShape) {
+ mainShape = NULL;
+ }
bulletdelete(shp.bt_shape);
}
diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp
index a36f1123bc..a94b88d566 100644
--- a/modules/bullet/generic_6dof_joint_bullet.cpp
+++ b/modules/bullet/generic_6dof_joint_bullet.cpp
@@ -135,6 +135,15 @@ void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer::G6DO
case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT:
sixDOFConstraint->getTranslationalLimitMotor()->m_maxMotorForce.m_floats[p_axis] = p_value;
break;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING:
+ sixDOFConstraint->getTranslationalLimitMotor()->m_springDamping.m_floats[p_axis] = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS:
+ sixDOFConstraint->getTranslationalLimitMotor()->m_springStiffness.m_floats[p_axis] = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT:
+ sixDOFConstraint->getTranslationalLimitMotor()->m_equilibriumPoint.m_floats[p_axis] = p_value;
+ break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT:
limits_lower[1][p_axis] = p_value;
set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, flags[p_axis][PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT]); // Reload bullet parameter
@@ -143,6 +152,9 @@ void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer::G6DO
limits_upper[1][p_axis] = p_value;
set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, flags[p_axis][PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT]); // Reload bullet parameter
break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION:
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_bounce = p_value;
+ break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP:
sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_stopERP = p_value;
break;
@@ -152,6 +164,15 @@ void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer::G6DO
case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT:
sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxMotorForce = p_value;
break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS:
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_springStiffness = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING:
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_springDamping = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT:
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_equilibriumPoint = p_value;
+ break;
default:
ERR_EXPLAIN("This parameter " + itos(p_param) + " is deprecated");
WARN_DEPRECATED
@@ -170,6 +191,12 @@ real_t Generic6DOFJointBullet::get_param(Vector3::Axis p_axis, PhysicsServer::G6
return sixDOFConstraint->getTranslationalLimitMotor()->m_targetVelocity.m_floats[p_axis];
case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT:
return sixDOFConstraint->getTranslationalLimitMotor()->m_maxMotorForce.m_floats[p_axis];
+ case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING:
+ return sixDOFConstraint->getTranslationalLimitMotor()->m_springDamping.m_floats[p_axis];
+ case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS:
+ return sixDOFConstraint->getTranslationalLimitMotor()->m_springStiffness.m_floats[p_axis];
+ case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT:
+ return sixDOFConstraint->getTranslationalLimitMotor()->m_equilibriumPoint.m_floats[p_axis];
case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT:
return limits_lower[1][p_axis];
case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT:
@@ -182,6 +209,12 @@ real_t Generic6DOFJointBullet::get_param(Vector3::Axis p_axis, PhysicsServer::G6
return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_targetVelocity;
case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT:
return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxMotorForce;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS:
+ return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_springStiffness;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING:
+ return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_springDamping;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT:
+ return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_equilibriumPoint;
default:
ERR_EXPLAIN("This parameter " + itos(p_param) + " is deprecated");
WARN_DEPRECATED;
@@ -215,6 +248,12 @@ void Generic6DOFJointBullet::set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOF
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR:
sixDOFConstraint->getTranslationalLimitMotor()->m_enableMotor[p_axis] = flags[p_axis][p_flag];
break;
+ case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING:
+ sixDOFConstraint->getTranslationalLimitMotor()->m_enableSpring[p_axis] = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING:
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_enableSpring = p_value;
+ break;
default:
ERR_EXPLAIN("This flag " + itos(p_flag) + " is deprecated");
WARN_DEPRECATED
@@ -224,6 +263,5 @@ void Generic6DOFJointBullet::set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOF
bool Generic6DOFJointBullet::get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag) const {
ERR_FAIL_INDEX_V(p_axis, 3, false);
-
return flags[p_axis][p_flag];
}
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index 37e7718969..85659e1523 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -797,7 +797,10 @@ void RigidBodyBullet::reload_shapes() {
const btScalar mass = invMass == 0 ? 0 : 1 / invMass;
if (mainShape) {
- btVector3 inertia;
+ // inertia initialised zero here because some of bullet's collision
+ // shapes incorrectly do not set the vector in calculateLocalIntertia.
+ // Arbitrary zero is preferable to undefined behaviour.
+ btVector3 inertia(0, 0, 0);
mainShape->calculateLocalInertia(mass, inertia);
btBody->setMassProps(mass, inertia);
}
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 44044d2750..23d879e1cd 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -159,6 +159,74 @@ CSGBrush *CSGShape::_get_brush() {
return brush;
}
+int CSGShape::mikktGetNumFaces(const SMikkTSpaceContext *pContext) {
+ ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
+
+ return surface.vertices.size() / 3;
+}
+
+int CSGShape::mikktGetNumVerticesOfFace(const SMikkTSpaceContext *pContext, const int iFace) {
+ // always 3
+ return 3;
+}
+
+void CSGShape::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvPosOut[], const int iFace, const int iVert) {
+ ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
+
+ Vector3 v = surface.verticesw[iFace * 3 + iVert];
+ fvPosOut[0] = v.x;
+ fvPosOut[1] = v.y;
+ fvPosOut[2] = v.z;
+}
+
+void CSGShape::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNormOut[], const int iFace, const int iVert) {
+ ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
+
+ Vector3 n = surface.normalsw[iFace * 3 + iVert];
+ fvNormOut[0] = n.x;
+ fvNormOut[1] = n.y;
+ fvNormOut[2] = n.z;
+}
+
+void CSGShape::mikktGetTexCoord(const SMikkTSpaceContext *pContext, float fvTexcOut[], const int iFace, const int iVert) {
+ ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
+
+ Vector2 t = surface.uvsw[iFace * 3 + iVert];
+ fvTexcOut[0] = t.x;
+ fvTexcOut[1] = t.y;
+}
+
+void CSGShape::mikktSetTSpaceBasic(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert) {
+ ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
+
+ int i = (iFace * 3 + iVert) * 4;
+
+ // Godot seems to want the tangent flipped because our handedness is reversed..
+ surface.tansw[i++] = -fvTangent[0];
+ surface.tansw[i++] = -fvTangent[1];
+ surface.tansw[i++] = -fvTangent[2];
+ surface.tansw[i++] = fSign;
+}
+
+void CSGShape::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT,
+ const tbool bIsOrientationPreserving, const int iFace, const int iVert) {
+
+ ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
+
+ int i = iFace * 3 + iVert;
+ Vector3 normal = surface.normalsw[i];
+ Vector3 tangent = Vector3(fvTangent[0], fvTangent[1], fvTangent[2]);
+ Vector3 bitangent = Vector3(fvBiTangent[0], fvBiTangent[1], fvBiTangent[2]);
+ float d = bitangent.dot(normal.cross(tangent));
+
+ // Godot seems to want the tangent flipped because our handedness is reversed..
+ i *= 4;
+ surface.tansw[i++] = -tangent.x;
+ surface.tansw[i++] = -tangent.y;
+ surface.tansw[i++] = -tangent.z;
+ surface.tansw[i++] = d < 0 ? -1 : 1;
+}
+
void CSGShape::_update_shape() {
if (parent)
@@ -211,6 +279,9 @@ void CSGShape::_update_shape() {
surfaces.write[i].vertices.resize(face_count[i] * 3);
surfaces.write[i].normals.resize(face_count[i] * 3);
surfaces.write[i].uvs.resize(face_count[i] * 3);
+ if (calculate_tangents) {
+ surfaces.write[i].tans.resize(face_count[i] * 3 * 4);
+ }
surfaces.write[i].last_added = 0;
if (i != surfaces.size() - 1) {
@@ -220,6 +291,9 @@ void CSGShape::_update_shape() {
surfaces.write[i].verticesw = surfaces.write[i].vertices.write();
surfaces.write[i].normalsw = surfaces.write[i].normals.write();
surfaces.write[i].uvsw = surfaces.write[i].uvs.write();
+ if (calculate_tangents) {
+ surfaces.write[i].tansw = surfaces.write[i].tans.write();
+ }
}
//fill arrays
@@ -274,9 +348,19 @@ void CSGShape::_update_shape() {
normal = -normal;
}
- surfaces[idx].verticesw[last + order[j]] = v;
- surfaces[idx].uvsw[last + order[j]] = n->faces[i].uvs[j];
- surfaces[idx].normalsw[last + order[j]] = normal;
+ int k = last + order[j];
+ surfaces[idx].verticesw[k] = v;
+ surfaces[idx].uvsw[k] = n->faces[i].uvs[j];
+ surfaces[idx].normalsw[k] = normal;
+
+ if (calculate_tangents) {
+ // zero out our tangents for now
+ k *= 4;
+ surfaces[idx].tansw[k++] = 0.0;
+ surfaces[idx].tansw[k++] = 0.0;
+ surfaces[idx].tansw[k++] = 0.0;
+ surfaces[idx].tansw[k++] = 0.0;
+ }
}
surfaces.write[idx].last_added += 3;
@@ -287,20 +371,43 @@ void CSGShape::_update_shape() {
//create surfaces
for (int i = 0; i < surfaces.size(); i++) {
+ // calculate tangents for this surface
+ bool have_tangents = calculate_tangents;
+ if (have_tangents) {
+ SMikkTSpaceInterface mkif;
+ mkif.m_getNormal = mikktGetNormal;
+ mkif.m_getNumFaces = mikktGetNumFaces;
+ mkif.m_getNumVerticesOfFace = mikktGetNumVerticesOfFace;
+ mkif.m_getPosition = mikktGetPosition;
+ mkif.m_getTexCoord = mikktGetTexCoord;
+ mkif.m_setTSpace = mikktSetTSpaceDefault;
+ mkif.m_setTSpaceBasic = NULL;
+
+ SMikkTSpaceContext msc;
+ msc.m_pInterface = &mkif;
+ msc.m_pUserData = &surfaces.write[i];
+ have_tangents = genTangSpaceDefault(&msc);
+ }
+ // unset write access
surfaces.write[i].verticesw = PoolVector<Vector3>::Write();
surfaces.write[i].normalsw = PoolVector<Vector3>::Write();
surfaces.write[i].uvsw = PoolVector<Vector2>::Write();
+ surfaces.write[i].tansw = PoolVector<float>::Write();
if (surfaces[i].last_added == 0)
continue;
+ // and convert to surface array
Array array;
array.resize(Mesh::ARRAY_MAX);
array[Mesh::ARRAY_VERTEX] = surfaces[i].vertices;
array[Mesh::ARRAY_NORMAL] = surfaces[i].normals;
array[Mesh::ARRAY_TEX_UV] = surfaces[i].uvs;
+ if (have_tangents) {
+ array[Mesh::ARRAY_TANGENT] = surfaces[i].tans;
+ }
int idx = root_mesh->get_surface_count();
root_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, array);
@@ -400,6 +507,15 @@ CSGShape::Operation CSGShape::get_operation() const {
return operation;
}
+void CSGShape::set_calculate_tangents(bool p_calculate_tangents) {
+ calculate_tangents = p_calculate_tangents;
+ _make_dirty();
+}
+
+bool CSGShape::is_calculating_tangents() const {
+ return calculate_tangents;
+}
+
void CSGShape::_validate_property(PropertyInfo &property) const {
if (is_inside_tree() && property.name.begins_with("use_collision") && !is_root_shape()) {
//hide collision if not root
@@ -421,9 +537,13 @@ void CSGShape::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CSGShape::set_snap);
ClassDB::bind_method(D_METHOD("get_snap"), &CSGShape::get_snap);
+ ClassDB::bind_method(D_METHOD("set_calculate_tangents", "enabled"), &CSGShape::set_calculate_tangents);
+ ClassDB::bind_method(D_METHOD("is_calculating_tangents"), &CSGShape::is_calculating_tangents);
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "Union,Intersection,Subtraction"), "set_operation", "get_operation");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_collision"), "set_use_collision", "is_using_collision");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "snap", PROPERTY_HINT_RANGE, "0.0001,1,0.001"), "set_snap", "get_snap");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "calculate_tangents"), "set_calculate_tangents", "is_calculating_tangents");
BIND_ENUM_CONSTANT(OPERATION_UNION);
BIND_ENUM_CONSTANT(OPERATION_INTERSECTION);
@@ -438,6 +558,7 @@ CSGShape::CSGShape() {
use_collision = false;
operation = OPERATION_UNION;
snap = 0.001;
+ calculate_tangents = true;
}
CSGShape::~CSGShape() {
@@ -598,8 +719,8 @@ CSGBrush *CSGMesh::_build_brush() {
mw[j / 3] = mat;
}
} else {
- int is = vertices.size();
- int as = avertices.size();
+ int as = vertices.size();
+ int is = avertices.size();
vertices.resize(as + is);
smooth.resize((as + is) / 3);
diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h
index 6898cdaf64..0a4bb5f665 100644
--- a/modules/csg/csg_shape.h
+++ b/modules/csg/csg_shape.h
@@ -36,6 +36,7 @@
#include "csg.h"
#include "scene/3d/visual_instance.h"
#include "scene/resources/concave_polygon_shape.h"
+#include "thirdparty/misc/mikktspace.h"
class CSGShape : public VisualInstance {
GDCLASS(CSGShape, VisualInstance);
@@ -63,6 +64,8 @@ private:
Ref<ConcavePolygonShape> root_collision_shape;
RID root_collision_instance;
+ bool calculate_tangents;
+
Ref<ArrayMesh> root_mesh;
struct Vector3Hasher {
@@ -78,14 +81,26 @@ private:
PoolVector<Vector3> vertices;
PoolVector<Vector3> normals;
PoolVector<Vector2> uvs;
+ PoolVector<float> tans;
Ref<Material> material;
int last_added;
PoolVector<Vector3>::Write verticesw;
PoolVector<Vector3>::Write normalsw;
PoolVector<Vector2>::Write uvsw;
+ PoolVector<float>::Write tansw;
};
+ //mikktspace callbacks
+ static int mikktGetNumFaces(const SMikkTSpaceContext *pContext);
+ static int mikktGetNumVerticesOfFace(const SMikkTSpaceContext *pContext, const int iFace);
+ static void mikktGetPosition(const SMikkTSpaceContext *pContext, float fvPosOut[], const int iFace, const int iVert);
+ static void mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNormOut[], const int iFace, const int iVert);
+ static void mikktGetTexCoord(const SMikkTSpaceContext *pContext, float fvTexcOut[], const int iFace, const int iVert);
+ static void mikktSetTSpaceBasic(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert);
+ static void mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT,
+ const tbool bIsOrientationPreserving, const int iFace, const int iVert);
+
void _update_shape();
protected:
@@ -115,6 +130,9 @@ public:
void set_snap(float p_snap);
float get_snap() const;
+ void set_calculate_tangents(bool p_calculate_tangents);
+ bool is_calculating_tangents() const;
+
bool is_root_shape() const;
CSGShape();
~CSGShape();
diff --git a/modules/csg/doc_classes/CSGShape.xml b/modules/csg/doc_classes/CSGShape.xml
index 90621b94f4..ac3c2342fc 100644
--- a/modules/csg/doc_classes/CSGShape.xml
+++ b/modules/csg/doc_classes/CSGShape.xml
@@ -20,6 +20,9 @@
</method>
</methods>
<members>
+ <member name="calculate_tangents" type="bool" setter="set_calculate_tangents" getter="is_calculating_tangents">
+ Calculate tangents for the CSG shape which allows the use of normal maps. This is only applied on the root shape, this setting is ignored on any child.
+ </member>
<member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape.Operation">
The operation that is performed on this shape. This is ignored for the first CSG child node as the operation is between this node and the previous child of this nodes parent.
</member>
diff --git a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
index 6d990f6f6f..e057a435ac 100644
--- a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
+++ b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
@@ -7,7 +7,7 @@
A PacketPeer implementation that should be passed to [method SceneTree.set_network_peer] after being initialized as either a client or server. Events can then be handled by connecting to [SceneTree] signals.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/networking/high_level_multiplayer.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/networking/high_level_multiplayer.html</link>
<link>http://enet.bespin.org/usergroup0.html</link>
</tutorials>
<demos>
diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub
index 7ca40c1b8b..3e2068b8db 100644
--- a/modules/freetype/SCsub
+++ b/modules/freetype/SCsub
@@ -59,6 +59,8 @@ if env['builtin_freetype']:
if env['platform'] == 'uwp':
# Include header for UWP to fix build issues
env_freetype.Append(CCFLAGS=['/FI', '"modules/freetype/uwpdef.h"'])
+ # Globally too, as freetype is used in scene (see bottom)
+ env.Append(CCFLAGS=['/FI', '"modules/freetype/uwpdef.h"'])
sfnt = thirdparty_dir + 'src/sfnt/sfnt.c'
if env['platform'] == 'javascript':
diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp
index ecde73ae1c..f07fdef488 100644
--- a/modules/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative.cpp
@@ -243,12 +243,12 @@ void GDNativeLibrary::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_symbol_prefix", "symbol_prefix"), &GDNativeLibrary::set_symbol_prefix);
ClassDB::bind_method(D_METHOD("set_reloadable", "reloadable"), &GDNativeLibrary::set_reloadable);
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "config_file", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile"), "set_config_file", "get_config_file");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "config_file", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile"), "set_config_file", "get_config_file");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "load_once"), "set_load_once", "should_load_once");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "singleton"), "set_singleton", "is_singleton");
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "symbol_prefix"), "set_symbol_prefix", "get_symbol_prefix");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "reloadable"), "set_reloadable", "is_reloadable");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "load_once"), "set_load_once", "should_load_once");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "singleton"), "set_singleton", "is_singleton");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "symbol_prefix"), "set_symbol_prefix", "get_symbol_prefix");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reloadable"), "set_reloadable", "is_reloadable");
}
GDNative::GDNative() {
@@ -268,7 +268,7 @@ void GDNative::_bind_methods() {
ClassDB::bind_method(D_METHOD("call_native", "calling_type", "procedure_name", "arguments"), &GDNative::call_native);
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library");
}
void GDNative::set_library(Ref<GDNativeLibrary> p_library) {
@@ -306,6 +306,13 @@ bool GDNative::initialize() {
#elif defined(UWP_ENABLED)
// On UWP we use a relative path from the app
String path = lib_path.replace("res://", "");
+#elif defined(OSX_ENABLED)
+ // On OSX the exported libraries are located under the Frameworks directory.
+ // So we need to replace the library path.
+ String path = ProjectSettings::get_singleton()->globalize_path(lib_path);
+ if (!FileAccess::exists(path)) {
+ path = OS::get_singleton()->get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(lib_path.get_file());
+ }
#else
String path = ProjectSettings::get_singleton()->globalize_path(lib_path);
#endif
diff --git a/modules/gdnative/gdnative/array.cpp b/modules/gdnative/gdnative/array.cpp
index 1fb0ff0500..a30cc09bf6 100644
--- a/modules/gdnative/gdnative/array.cpp
+++ b/modules/gdnative/gdnative/array.cpp
@@ -318,6 +318,38 @@ void GDAPI godot_array_destroy(godot_array *p_self) {
((Array *)p_self)->~Array();
}
+godot_array GDAPI godot_array_duplicate(const godot_array *p_self, const godot_bool p_deep) {
+ const Array *self = (const Array *)p_self;
+ godot_array res;
+ Array *val = (Array *)&res;
+ memnew_placement(val, Array);
+ *val = self->duplicate(p_deep);
+ return res;
+}
+
+godot_variant GDAPI godot_array_max(const godot_array *p_self) {
+ const Array *self = (const Array *)p_self;
+ godot_variant v;
+ Variant *val = (Variant *)&v;
+ memnew_placement(val, Variant);
+ *val = self->max();
+ return v;
+}
+
+godot_variant GDAPI godot_array_min(const godot_array *p_self) {
+ const Array *self = (const Array *)p_self;
+ godot_variant v;
+ Variant *val = (Variant *)&v;
+ memnew_placement(val, Variant);
+ *val = self->min();
+ return v;
+}
+
+void GDAPI godot_array_shuffle(godot_array *p_self) {
+ Array *self = (Array *)p_self;
+ self->shuffle();
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/basis.cpp b/modules/gdnative/gdnative/basis.cpp
index 70d2814577..d88499ade1 100644
--- a/modules/gdnative/gdnative/basis.cpp
+++ b/modules/gdnative/gdnative/basis.cpp
@@ -282,6 +282,15 @@ godot_basis GDAPI godot_basis_operator_multiply_scalar(const godot_basis *p_self
return raw_dest;
}
+godot_basis GDAPI godot_basis_slerp(const godot_basis *p_self, const godot_basis *p_b, const godot_real p_t) {
+ godot_basis raw_dest;
+ Basis *dest = (Basis *)&raw_dest;
+ const Basis *self = (const Basis *)p_self;
+ const Basis *b = (const Basis *)p_b;
+ *dest = self->slerp(*b, p_t);
+ return raw_dest;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/color.cpp b/modules/gdnative/gdnative/color.cpp
index 4089f4458a..79f0c71b5e 100644
--- a/modules/gdnative/gdnative/color.cpp
+++ b/modules/gdnative/gdnative/color.cpp
@@ -116,6 +116,26 @@ godot_int GDAPI godot_color_to_rgba32(const godot_color *p_self) {
return self->to_rgba32();
}
+godot_int GDAPI godot_color_to_abgr32(const godot_color *p_self) {
+ const Color *self = (const Color *)p_self;
+ return self->to_abgr32();
+}
+
+godot_int GDAPI godot_color_to_abgr64(const godot_color *p_self) {
+ const Color *self = (const Color *)p_self;
+ return self->to_abgr64();
+}
+
+godot_int GDAPI godot_color_to_argb64(const godot_color *p_self) {
+ const Color *self = (const Color *)p_self;
+ return self->to_argb64();
+}
+
+godot_int GDAPI godot_color_to_rgba64(const godot_color *p_self) {
+ const Color *self = (const Color *)p_self;
+ return self->to_rgba64();
+}
+
godot_int GDAPI godot_color_to_argb32(const godot_color *p_self) {
const Color *self = (const Color *)p_self;
return self->to_argb32();
@@ -156,6 +176,27 @@ godot_color GDAPI godot_color_blend(const godot_color *p_self, const godot_color
return dest;
}
+godot_color GDAPI godot_color_darkened(const godot_color *p_self, const godot_real p_amount) {
+ godot_color dest;
+ const Color *self = (const Color *)p_self;
+ *((Color *)&dest) = self->darkened(p_amount);
+ return dest;
+}
+
+godot_color GDAPI godot_color_from_hsv(const godot_color *p_self, const godot_real p_h, const godot_real p_s, const godot_real p_v, const godot_real p_a) {
+ godot_color dest;
+ const Color *self = (const Color *)p_self;
+ *((Color *)&dest) = self->from_hsv(p_h, p_s, p_v, p_a);
+ return dest;
+}
+
+godot_color GDAPI godot_color_lightened(const godot_color *p_self, const godot_real p_amount) {
+ godot_color dest;
+ const Color *self = (const Color *)p_self;
+ *((Color *)&dest) = self->lightened(p_amount);
+ return dest;
+}
+
godot_string GDAPI godot_color_to_html(const godot_color *p_self, const godot_bool p_with_alpha) {
godot_string dest;
const Color *self = (const Color *)p_self;
diff --git a/modules/gdnative/gdnative/node_path.cpp b/modules/gdnative/gdnative/node_path.cpp
index f24facaae8..cf82940e09 100644
--- a/modules/gdnative/gdnative/node_path.cpp
+++ b/modules/gdnative/gdnative/node_path.cpp
@@ -110,6 +110,15 @@ godot_bool GDAPI godot_node_path_operator_equal(const godot_node_path *p_self, c
return *self == *b;
}
+godot_node_path godot_node_path_get_as_property_path(const godot_node_path *p_self) {
+ const NodePath *self = (const NodePath *)p_self;
+ godot_node_path res;
+ NodePath *val = (NodePath *)&res;
+ memnew_placement(val, NodePath);
+ *val = self->get_as_property_path();
+ return res;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/quat.cpp b/modules/gdnative/gdnative/quat.cpp
index ddec77edcd..2594759508 100644
--- a/modules/gdnative/gdnative/quat.cpp
+++ b/modules/gdnative/gdnative/quat.cpp
@@ -225,6 +225,12 @@ godot_quat GDAPI godot_quat_operator_neg(const godot_quat *p_self) {
return raw_dest;
}
+void GDAPI godot_quat_set_axis_angle(godot_quat *p_self, const godot_vector3 *p_axis, const godot_real p_angle) {
+ Quat *self = (Quat *)p_self;
+ const Vector3 *axis = (const Vector3 *)p_axis;
+ self->set_axis_angle(*axis, p_angle);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/rect2.cpp b/modules/gdnative/gdnative/rect2.cpp
index 54b98fc4e5..5cbc2712c3 100644
--- a/modules/gdnative/gdnative/rect2.cpp
+++ b/modules/gdnative/gdnative/rect2.cpp
@@ -109,6 +109,27 @@ godot_rect2 GDAPI godot_rect2_grow(const godot_rect2 *p_self, const godot_real p
return dest;
}
+godot_rect2 GDAPI godot_rect2_grow_individual(const godot_rect2 *p_self, const godot_real p_left, const godot_real p_top, const godot_real p_right, const godot_real p_bottom) {
+ godot_rect2 dest;
+ const Rect2 *self = (const Rect2 *)p_self;
+ *((Rect2 *)&dest) = self->grow_individual(p_left, p_top, p_right, p_bottom);
+ return dest;
+}
+
+godot_rect2 GDAPI godot_rect2_grow_margin(const godot_rect2 *p_self, const godot_int p_margin, const godot_real p_by) {
+ godot_rect2 dest;
+ const Rect2 *self = (const Rect2 *)p_self;
+ *((Rect2 *)&dest) = self->grow_margin((Margin)p_margin, p_by);
+ return dest;
+}
+
+godot_rect2 GDAPI godot_rect2_abs(const godot_rect2 *p_self) {
+ godot_rect2 dest;
+ const Rect2 *self = (const Rect2 *)p_self;
+ *((Rect2 *)&dest) = self->abs();
+ return dest;
+}
+
godot_rect2 GDAPI godot_rect2_expand(const godot_rect2 *p_self, const godot_vector2 *p_to) {
godot_rect2 dest;
const Rect2 *self = (const Rect2 *)p_self;
diff --git a/modules/gdnative/gdnative/string.cpp b/modules/gdnative/gdnative/string.cpp
index 8ca57392a3..0996633b70 100644
--- a/modules/gdnative/gdnative/string.cpp
+++ b/modules/gdnative/gdnative/string.cpp
@@ -1285,6 +1285,64 @@ godot_bool GDAPI godot_string_is_valid_ip_address(const godot_string *p_self) {
return self->is_valid_ip_address();
}
+godot_string GDAPI godot_string_dedent(const godot_string *p_self) {
+ const String *self = (const String *)p_self;
+ godot_string result;
+ String return_value = self->dedent();
+ memnew_placement(&result, String(return_value));
+
+ return result;
+}
+
+godot_string GDAPI godot_string_trim_prefix(const godot_string *p_self, const godot_string *p_prefix) {
+ const String *self = (const String *)p_self;
+ String *prefix = (String *)p_prefix;
+ godot_string result;
+ String return_value = self->trim_prefix(*prefix);
+ memnew_placement(&result, String(return_value));
+
+ return result;
+}
+
+godot_string GDAPI godot_string_trim_suffix(const godot_string *p_self, const godot_string *p_suffix) {
+ const String *self = (const String *)p_self;
+ String *suffix = (String *)p_suffix;
+ godot_string result;
+ String return_value = self->trim_suffix(*suffix);
+ memnew_placement(&result, String(return_value));
+
+ return result;
+}
+
+godot_string GDAPI godot_string_rstrip(const godot_string *p_self, const godot_string *p_chars) {
+ const String *self = (const String *)p_self;
+ String *chars = (String *)p_chars;
+ godot_string result;
+ String return_value = self->rstrip(*chars);
+ memnew_placement(&result, String(return_value));
+
+ return result;
+}
+
+godot_pool_string_array GDAPI godot_string_rsplit(const godot_string *p_self, const godot_string *p_divisor,
+ const godot_bool p_allow_empty, const godot_int p_maxsplit) {
+ const String *self = (const String *)p_self;
+ String *divisor = (String *)p_divisor;
+
+ godot_pool_string_array result;
+ memnew_placement(&result, PoolStringArray);
+ PoolStringArray *proxy = (PoolStringArray *)&result;
+ PoolStringArray::Write proxy_writer = proxy->write();
+ Vector<String> tmp_result = self->rsplit(*divisor, p_allow_empty, p_maxsplit);
+ proxy->resize(tmp_result.size());
+
+ for (int i = 0; i < tmp_result.size(); i++) {
+ proxy_writer[i] = tmp_result[i];
+ }
+
+ return result;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json
index 16a34a9a33..c5a1fa139e 100644
--- a/modules/gdnative/gdnative_api.json
+++ b/modules/gdnative/gdnative_api.json
@@ -14,6 +14,183 @@
"next": null,
"api": [
{
+ "name": "godot_color_to_abgr32",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_color *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_color_to_abgr64",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_color *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_color_to_argb64",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_color *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_color_to_rgba64",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_color *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_color_darkened",
+ "return_type": "godot_color",
+ "arguments": [
+ ["const godot_color *", "p_self"],
+ ["const godot_real", "p_amount"]
+ ]
+ },
+ {
+ "name": "godot_color_from_hsv",
+ "return_type": "godot_color",
+ "arguments": [
+ ["const godot_color *", "p_self"],
+ ["const godot_real", "p_h"],
+ ["const godot_real", "p_s"],
+ ["const godot_real", "p_v"],
+ ["const godot_real", "p_a"]
+ ]
+ },
+ {
+ "name": "godot_color_lightened",
+ "return_type": "godot_color",
+ "arguments": [
+ ["const godot_color *", "p_self"],
+ ["const godot_real", "p_amount"]
+ ]
+ },
+ {
+ "name": "godot_array_duplicate",
+ "return_type": "godot_array",
+ "arguments": [
+ ["const godot_array *", "p_self"],
+ ["const godot_bool", "p_deep"]
+ ]
+ },
+ {
+ "name": "godot_array_max",
+ "return_type": "godot_variant",
+ "arguments": [
+ ["const godot_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_array_min",
+ "return_type": "godot_variant",
+ "arguments": [
+ ["const godot_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_array_shuffle",
+ "return_type": "void",
+ "arguments": [
+ ["godot_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_basis_slerp",
+ "return_type": "godot_basis",
+ "arguments": [
+ ["const godot_basis *", "p_self"],
+ ["const godot_basis *", "p_b"],
+ ["const godot_real", "p_t"]
+ ]
+ },
+ {
+ "name": "godot_node_path_get_as_property_path",
+ "return_type": "godot_node_path",
+ "arguments": [
+ ["const godot_node_path *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_quat_set_axis_angle",
+ "return_type": "void",
+ "arguments": [
+ ["godot_quat *", "p_self"],
+ ["const godot_vector3 *", "p_axis"],
+ ["const godot_real", "p_angle"]
+ ]
+ },
+ {
+ "name": "godot_rect2_grow_individual",
+ "return_type": "godot_rect2",
+ "arguments": [
+ ["const godot_rect2 *", "p_self"],
+ ["const godot_real", "p_left"],
+ ["const godot_real", "p_top"],
+ ["const godot_real", "p_right"],
+ ["const godot_real", "p_bottom"]
+ ]
+ },
+ {
+ "name": "godot_rect2_grow_margin",
+ "return_type": "godot_rect2",
+ "arguments": [
+ ["const godot_rect2 *", "p_self"],
+ ["const godot_int", "p_margin"],
+ ["const godot_real", "p_by"]
+ ]
+ },
+ {
+ "name": "godot_rect2_abs",
+ "return_type": "godot_rect2",
+ "arguments": [
+ ["const godot_rect2 *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_string_dedent",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_string_trim_prefix",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_prefix"]
+ ]
+ },
+ {
+ "name": "godot_string_trim_suffix",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_suffix"]
+ ]
+ },
+ {
+ "name": "godot_string_rstrip",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_chars"]
+ ]
+ },
+ {
+ "name": "godot_string_rsplit",
+ "return_type": "godot_pool_string_array",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_divisor"],
+ ["const godot_bool", "p_allow_empty"],
+ ["const godot_int", "p_maxsplit"]
+ ]
+ },
+ {
"name": "godot_basis_get_quat",
"return_type": "godot_quat",
"arguments": [
diff --git a/modules/gdnative/include/gdnative/array.h b/modules/gdnative/include/gdnative/array.h
index 1e66d133b9..876b8f8e8f 100644
--- a/modules/gdnative/include/gdnative/array.h
+++ b/modules/gdnative/include/gdnative/array.h
@@ -130,6 +130,14 @@ godot_int GDAPI godot_array_bsearch_custom(godot_array *p_self, const godot_vari
void GDAPI godot_array_destroy(godot_array *p_self);
+godot_array GDAPI godot_array_duplicate(const godot_array *p_self, const godot_bool p_deep);
+
+godot_variant GDAPI godot_array_max(const godot_array *p_self);
+
+godot_variant GDAPI godot_array_min(const godot_array *p_self);
+
+void GDAPI godot_array_shuffle(godot_array *p_self);
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/basis.h b/modules/gdnative/include/gdnative/basis.h
index ebe2b1125b..6128bf3ac3 100644
--- a/modules/gdnative/include/gdnative/basis.h
+++ b/modules/gdnative/include/gdnative/basis.h
@@ -127,6 +127,8 @@ godot_basis GDAPI godot_basis_operator_multiply_vector(const godot_basis *p_self
godot_basis GDAPI godot_basis_operator_multiply_scalar(const godot_basis *p_self, const godot_real p_b);
+godot_basis GDAPI godot_basis_slerp(const godot_basis *p_self, const godot_basis *p_b, const godot_real p_t);
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/color.h b/modules/gdnative/include/gdnative/color.h
index 1f0ac8354d..3007dbc6e3 100644
--- a/modules/gdnative/include/gdnative/color.h
+++ b/modules/gdnative/include/gdnative/color.h
@@ -81,6 +81,14 @@ godot_string GDAPI godot_color_as_string(const godot_color *p_self);
godot_int GDAPI godot_color_to_rgba32(const godot_color *p_self);
+godot_int GDAPI godot_color_to_abgr32(const godot_color *p_self);
+
+godot_int GDAPI godot_color_to_abgr64(const godot_color *p_self);
+
+godot_int GDAPI godot_color_to_argb64(const godot_color *p_self);
+
+godot_int GDAPI godot_color_to_rgba64(const godot_color *p_self);
+
godot_int GDAPI godot_color_to_argb32(const godot_color *p_self);
godot_real GDAPI godot_color_gray(const godot_color *p_self);
@@ -93,6 +101,12 @@ godot_color GDAPI godot_color_linear_interpolate(const godot_color *p_self, cons
godot_color GDAPI godot_color_blend(const godot_color *p_self, const godot_color *p_over);
+godot_color GDAPI godot_color_darkened(const godot_color *p_self, const godot_real p_amount);
+
+godot_color GDAPI godot_color_from_hsv(const godot_color *p_self, const godot_real p_h, const godot_real p_s, const godot_real p_v, const godot_real p_a);
+
+godot_color GDAPI godot_color_lightened(const godot_color *p_self, const godot_real p_amount);
+
godot_string GDAPI godot_color_to_html(const godot_color *p_self, const godot_bool p_with_alpha);
godot_bool GDAPI godot_color_operator_equal(const godot_color *p_self, const godot_color *p_b);
diff --git a/modules/gdnative/include/gdnative/node_path.h b/modules/gdnative/include/gdnative/node_path.h
index 2b55e01d13..48fe5b4d3d 100644
--- a/modules/gdnative/include/gdnative/node_path.h
+++ b/modules/gdnative/include/gdnative/node_path.h
@@ -80,6 +80,8 @@ godot_bool GDAPI godot_node_path_is_empty(const godot_node_path *p_self);
godot_bool GDAPI godot_node_path_operator_equal(const godot_node_path *p_self, const godot_node_path *p_b);
+godot_node_path godot_node_path_get_as_property_path(const godot_node_path *p_self);
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/quat.h b/modules/gdnative/include/gdnative/quat.h
index b1290f745c..634f486e66 100644
--- a/modules/gdnative/include/gdnative/quat.h
+++ b/modules/gdnative/include/gdnative/quat.h
@@ -109,6 +109,8 @@ godot_bool GDAPI godot_quat_operator_equal(const godot_quat *p_self, const godot
godot_quat GDAPI godot_quat_operator_neg(const godot_quat *p_self);
+void GDAPI godot_quat_set_axis_angle(godot_quat *p_self, const godot_vector3 *p_axis, const godot_real p_angle);
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/rect2.h b/modules/gdnative/include/gdnative/rect2.h
index 4adcb73e3d..47c15c80bd 100644
--- a/modules/gdnative/include/gdnative/rect2.h
+++ b/modules/gdnative/include/gdnative/rect2.h
@@ -77,6 +77,12 @@ godot_bool GDAPI godot_rect2_has_point(const godot_rect2 *p_self, const godot_ve
godot_rect2 GDAPI godot_rect2_grow(const godot_rect2 *p_self, const godot_real p_by);
+godot_rect2 GDAPI godot_rect2_grow_individual(const godot_rect2 *p_self, const godot_real p_left, const godot_real p_top, const godot_real p_right, const godot_real p_bottom);
+
+godot_rect2 GDAPI godot_rect2_grow_margin(const godot_rect2 *p_self, const godot_int p_margin, const godot_real p_by);
+
+godot_rect2 GDAPI godot_rect2_abs(const godot_rect2 *p_self);
+
godot_rect2 GDAPI godot_rect2_expand(const godot_rect2 *p_self, const godot_vector2 *p_to);
godot_bool GDAPI godot_rect2_operator_equal(const godot_rect2 *p_self, const godot_rect2 *p_b);
diff --git a/modules/gdnative/include/gdnative/string.h b/modules/gdnative/include/gdnative/string.h
index 73245160c1..95ae42a9ec 100644
--- a/modules/gdnative/include/gdnative/string.h
+++ b/modules/gdnative/include/gdnative/string.h
@@ -246,6 +246,12 @@ godot_bool GDAPI godot_string_is_valid_identifier(const godot_string *p_self);
godot_bool GDAPI godot_string_is_valid_integer(const godot_string *p_self);
godot_bool GDAPI godot_string_is_valid_ip_address(const godot_string *p_self);
+godot_string GDAPI godot_string_dedent(const godot_string *p_self);
+godot_string GDAPI godot_string_trim_prefix(const godot_string *p_self, const godot_string *p_prefix);
+godot_string GDAPI godot_string_trim_suffix(const godot_string *p_self, const godot_string *p_suffix);
+godot_string GDAPI godot_string_rstrip(const godot_string *p_self, const godot_string *p_chars);
+godot_pool_string_array GDAPI godot_string_rsplit(const godot_string *p_self, const godot_string *p_divisor, const godot_bool p_allow_empty, const godot_int p_maxsplit);
+
void GDAPI godot_string_destroy(godot_string *p_self);
#ifdef __cplusplus
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index 3e56275396..eb133502c4 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -72,11 +72,11 @@ void NativeScript::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_signal_documentation", "signal_name"), &NativeScript::get_signal_documentation);
ClassDB::bind_method(D_METHOD("get_property_documentation", "path"), &NativeScript::get_property_documentation);
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "class_name"), "set_class_name", "get_class_name");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "class_name"), "set_class_name", "get_class_name");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library");
ADD_GROUP("Script Class", "script_class_");
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "script_class_name"), "set_script_class_name", "get_script_class_name");
- ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "script_class_icon_path", PROPERTY_HINT_FILE), "set_script_class_icon_path", "get_script_class_icon_path");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "script_class_name"), "set_script_class_name", "get_script_class_name");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "script_class_icon_path", PROPERTY_HINT_FILE), "set_script_class_icon_path", "get_script_class_icon_path");
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &NativeScript::_new, MethodInfo(Variant::OBJECT, "new"));
}
diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml
index 632970f8c0..4cefdbd7cb 100644
--- a/modules/gdscript/doc_classes/GDScript.xml
+++ b/modules/gdscript/doc_classes/GDScript.xml
@@ -8,7 +8,7 @@
[method new] creates a new instance of the script. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/getting_started/scripting/gdscript/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/index.html</link>
</tutorials>
<demos>
</demos>
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 2ce92f340d..068e8d2d92 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -1308,37 +1308,38 @@ static bool _guess_identifier_type(const GDScriptCompletionContext &p_context, c
return false;
}
- // Check ClassDB
- if (ClassDB::class_exists(p_identifier)) {
- r_type.type.has_type = true;
- r_type.type.kind = GDScriptParser::DataType::NATIVE;
- r_type.type.native_type = p_identifier;
- if (Engine::get_singleton()->has_singleton(p_identifier)) {
- r_type.type.is_meta_type = false;
- r_type.value = Engine::get_singleton()->get_singleton_object(p_identifier);
- } else {
- r_type.type.is_meta_type = true;
- int idx = GDScriptLanguage::get_singleton()->get_global_map()[p_identifier];
- r_type.value = GDScriptLanguage::get_singleton()->get_global_array()[idx];
+ for (int i = 0; i < 2; i++) {
+ StringName target_id;
+ switch (i) {
+ case 0:
+ // Check ClassDB
+ target_id = p_identifier;
+ break;
+ case 1:
+ // ClassDB again for underscore-prefixed classes
+ target_id = String("_") + p_identifier;
+ break;
}
- return true;
- }
- // ClassDB again for underscore-prefixed classes
- StringName under_id = String("_") + p_identifier;
- if (ClassDB::class_exists(under_id)) {
- r_type.type.has_type = true;
- r_type.type.kind = GDScriptParser::DataType::NATIVE;
- r_type.type.native_type = p_identifier;
- if (Engine::get_singleton()->has_singleton(p_identifier)) {
- r_type.type.is_meta_type = false;
- r_type.value = Engine::get_singleton()->get_singleton_object(p_identifier);
- } else {
- r_type.type.is_meta_type = true;
- int idx = GDScriptLanguage::get_singleton()->get_global_map()[p_identifier];
- r_type.value = GDScriptLanguage::get_singleton()->get_global_array()[idx];
+ if (ClassDB::class_exists(target_id)) {
+ r_type.type.has_type = true;
+ r_type.type.kind = GDScriptParser::DataType::NATIVE;
+ r_type.type.native_type = target_id;
+ if (Engine::get_singleton()->has_singleton(target_id)) {
+ r_type.type.is_meta_type = false;
+ r_type.value = Engine::get_singleton()->get_singleton_object(target_id);
+ } else {
+ r_type.type.is_meta_type = true;
+ const Map<StringName, int>::Element *target_elem = GDScriptLanguage::get_singleton()->get_global_map().find(target_id);
+ // Check because classes like EditorNode are in ClassDB by now, but unknown to GDScript
+ if (!target_elem) {
+ return false;
+ }
+ int idx = target_elem->get();
+ r_type.value = GDScriptLanguage::get_singleton()->get_global_array()[idx];
+ }
+ return true;
}
- return true;
}
// Check autoload singletons
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index 31115a4bd9..c67cf124c0 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -477,56 +477,53 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GET_VARIANT_PTR(dst, 3);
#ifdef DEBUG_ENABLED
- if (a->get_type() != Variant::OBJECT || a->operator Object *() == NULL) {
-
- err_text = "Left operand of 'is' is not an instance of anything.";
- OPCODE_BREAK;
- }
if (b->get_type() != Variant::OBJECT || b->operator Object *() == NULL) {
err_text = "Right operand of 'is' is not a class.";
OPCODE_BREAK;
}
#endif
- Object *obj_A = *a;
- Object *obj_B = *b;
-
- GDScript *scr_B = Object::cast_to<GDScript>(obj_B);
bool extends_ok = false;
+ if (a->get_type() == Variant::OBJECT && a->operator Object *() != NULL) {
+ Object *obj_A = *a;
+ Object *obj_B = *b;
- if (scr_B) {
- //if B is a script, the only valid condition is that A has an instance which inherits from the script
- //in other situation, this shoul return false.
+ GDScript *scr_B = Object::cast_to<GDScript>(obj_B);
- if (obj_A->get_script_instance() && obj_A->get_script_instance()->get_language() == GDScriptLanguage::get_singleton()) {
+ if (scr_B) {
+ //if B is a script, the only valid condition is that A has an instance which inherits from the script
+ //in other situation, this shoul return false.
- GDScript *cmp = static_cast<GDScript *>(obj_A->get_script_instance()->get_script().ptr());
- //bool found=false;
- while (cmp) {
+ if (obj_A->get_script_instance() && obj_A->get_script_instance()->get_language() == GDScriptLanguage::get_singleton()) {
- if (cmp == scr_B) {
- //inherits from script, all ok
- extends_ok = true;
- break;
- }
+ GDScript *cmp = static_cast<GDScript *>(obj_A->get_script_instance()->get_script().ptr());
+ //bool found=false;
+ while (cmp) {
- cmp = cmp->_base;
+ if (cmp == scr_B) {
+ //inherits from script, all ok
+ extends_ok = true;
+ break;
+ }
+
+ cmp = cmp->_base;
+ }
}
- }
- } else {
+ } else {
- GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(obj_B);
+ GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(obj_B);
#ifdef DEBUG_ENABLED
- if (!nc) {
+ if (!nc) {
- err_text = "Right operand of 'is' is not a class (type: '" + obj_B->get_class() + "').";
- OPCODE_BREAK;
- }
+ err_text = "Right operand of 'is' is not a class (type: '" + obj_B->get_class() + "').";
+ OPCODE_BREAK;
+ }
#endif
- extends_ok = ClassDB::is_parent_class(obj_A->get_class_name(), nc->get_name());
+ extends_ok = ClassDB::is_parent_class(obj_A->get_class_name(), nc->get_name());
+ }
}
*dst = extends_ok;
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index 5af9bbc05f..2f31d59c46 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -106,6 +106,8 @@ const char *GDScriptFunctions::get_func_name(Function p_func) {
"printerr",
"printraw",
"print_debug",
+ "push_error",
+ "push_warning",
"var2str",
"str2var",
"var2bytes",
@@ -707,13 +709,40 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
ScriptLanguage *script = GDScriptLanguage::get_singleton();
if (script->debug_get_stack_level_count() > 0) {
- str += "\n\t";
- str += "At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)); // + " in function '" + script->debug_get_stack_level_function(0) + "'";
+ str += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()";
}
print_line(str);
r_ret = Variant();
} break;
+ case PUSH_ERROR: {
+ VALIDATE_ARG_COUNT(1);
+ if (p_args[0]->get_type() != Variant::STRING) {
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::STRING;
+ r_ret = Variant();
+ break;
+ }
+
+ String message = *p_args[0];
+ ERR_PRINTS(message);
+ r_ret = Variant();
+ } break;
+ case PUSH_WARNING: {
+ VALIDATE_ARG_COUNT(1);
+ if (p_args[0]->get_type() != Variant::STRING) {
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::STRING;
+ r_ret = Variant();
+ break;
+ }
+
+ String message = *p_args[0];
+ WARN_PRINTS(message);
+ r_ret = Variant();
+ } break;
case VAR_TO_STR: {
VALIDATE_ARG_COUNT(1);
String vars;
@@ -1754,11 +1783,25 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
return mi;
} break;
+ case PUSH_ERROR: {
+
+ MethodInfo mi(Variant::NIL, "push_error", PropertyInfo(Variant::STRING, "message"));
+ mi.return_val.type = Variant::NIL;
+ return mi;
+
+ } break;
+ case PUSH_WARNING: {
+
+ MethodInfo mi(Variant::NIL, "push_warning", PropertyInfo(Variant::STRING, "message"));
+ mi.return_val.type = Variant::NIL;
+ return mi;
+
+ } break;
case VAR_TO_STR: {
+
MethodInfo mi("var2str", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
mi.return_val.type = Variant::STRING;
return mi;
-
} break;
case STR_TO_VAR: {
@@ -1768,10 +1811,10 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
return mi;
} break;
case VAR_TO_BYTES: {
+
MethodInfo mi("var2bytes", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
mi.return_val.type = Variant::POOL_BYTE_ARRAY;
return mi;
-
} break;
case BYTES_TO_VAR: {
diff --git a/modules/gdscript/gdscript_functions.h b/modules/gdscript/gdscript_functions.h
index e920dd4ece..33d5f27230 100644
--- a/modules/gdscript/gdscript_functions.h
+++ b/modules/gdscript/gdscript_functions.h
@@ -97,6 +97,8 @@ public:
TEXT_PRINTERR,
TEXT_PRINTRAW,
TEXT_PRINT_DEBUG,
+ PUSH_ERROR,
+ PUSH_WARNING,
VAR_TO_STR,
STR_TO_VAR,
VAR_TO_BYTES,
@@ -117,7 +119,6 @@ public:
LEN,
IS_INSTANCE_VALID,
FUNC_MAX
-
};
static const char *get_func_name(Function p_func);
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 97ac6f7de6..a4bda42b16 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -4353,6 +4353,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
current_export.type = Variant::INT;
current_export.hint = is_flags ? PROPERTY_HINT_FLAGS : PROPERTY_HINT_ENUM;
+ current_export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
Dictionary enum_values = constant;
List<Variant> keys;
@@ -4839,6 +4840,21 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
tokenizer->advance();
if (tokenizer->is_token_literal(0, true)) {
enum_name = tokenizer->get_token_literal();
+
+ if (current_class->constant_expressions.has(enum_name)) {
+ _set_error("A constant named '" + String(enum_name) + "' already exists in this class (at line: " +
+ itos(current_class->constant_expressions[enum_name].expression->line) + ").");
+ return;
+ }
+
+ for (int i = 0; i < current_class->variables.size(); i++) {
+ if (current_class->variables[i].identifier == enum_name) {
+ _set_error("A variable named '" + String(enum_name) + "' already exists in this class (at line: " +
+ itos(current_class->variables[i].line) + ").");
+ return;
+ }
+ }
+
tokenizer->advance();
}
if (tokenizer->get_token() != GDScriptTokenizer::TK_CURLY_BRACKET_OPEN) {
@@ -4865,26 +4881,12 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
} else { // tokenizer->is_token_literal(0, true)
- ClassNode::Constant constant;
-
StringName const_id = tokenizer->get_token_literal();
- if (current_class->constant_expressions.has(const_id)) {
- _set_error("A constant named '" + String(const_id) + "' already exists in this class (at line: " +
- itos(current_class->constant_expressions[const_id].expression->line) + ").");
- return;
- }
-
- for (int i = 0; i < current_class->variables.size(); i++) {
- if (current_class->variables[i].identifier == const_id) {
- _set_error("A variable named '" + String(const_id) + "' already exists in this class (at line: " +
- itos(current_class->variables[i].line) + ").");
- return;
- }
- }
-
tokenizer->advance();
+ ConstantNode *enum_value_expr;
+
if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) {
tokenizer->advance();
@@ -4901,23 +4903,20 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
- ConstantNode *subexpr_const = static_cast<ConstantNode *>(subexpr);
+ enum_value_expr = static_cast<ConstantNode *>(subexpr);
- if (subexpr_const->value.get_type() != Variant::INT) {
+ if (enum_value_expr->value.get_type() != Variant::INT) {
_set_error("Expected an int value for enum");
return;
}
- last_assign = subexpr_const->value;
-
- constant.expression = subexpr_const;
+ last_assign = enum_value_expr->value;
} else {
last_assign = last_assign + 1;
- ConstantNode *cn = alloc_node<ConstantNode>();
- cn->value = last_assign;
- cn->datatype = _type_from_variant(cn->value);
- constant.expression = cn;
+ enum_value_expr = alloc_node<ConstantNode>();
+ enum_value_expr->value = last_assign;
+ enum_value_expr->datatype = _type_from_variant(enum_value_expr->value);
}
if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) {
@@ -4925,14 +4924,29 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
if (enum_name != "") {
- const ConstantNode *cn = static_cast<const ConstantNode *>(constant.expression);
- enum_dict[const_id] = cn->value;
- }
+ enum_dict[const_id] = enum_value_expr->value;
+ } else {
+ if (current_class->constant_expressions.has(const_id)) {
+ _set_error("A constant named '" + String(const_id) + "' already exists in this class (at line: " +
+ itos(current_class->constant_expressions[const_id].expression->line) + ").");
+ return;
+ }
+
+ for (int i = 0; i < current_class->variables.size(); i++) {
+ if (current_class->variables[i].identifier == const_id) {
+ _set_error("A variable named '" + String(const_id) + "' already exists in this class (at line: " +
+ itos(current_class->variables[i].line) + ").");
+ return;
+ }
+ }
- constant.type.has_type = true;
- constant.type.kind = DataType::BUILTIN;
- constant.type.builtin_type = Variant::INT;
- p_class->constant_expressions.insert(const_id, constant);
+ ClassNode::Constant constant;
+ constant.type.has_type = true;
+ constant.type.kind = DataType::BUILTIN;
+ constant.type.builtin_type = Variant::INT;
+ constant.expression = enum_value_expr;
+ p_class->constant_expressions.insert(const_id, constant);
+ }
}
}
@@ -6418,6 +6432,10 @@ bool GDScriptParser::_get_function_signature(DataType &p_base_type, const String
StringName native;
if (p_base_type.kind == DataType::GDSCRIPT) {
base_gdscript = p_base_type.script_type;
+ if (base_gdscript.is_null() || !base_gdscript->is_valid()) {
+ // GDScript wasn't properly compíled, don't bother trying
+ return false;
+ }
} else if (p_base_type.kind == DataType::SCRIPT) {
base_script = p_base_type.script_type;
} else if (p_base_type.kind == DataType::NATIVE) {
@@ -6458,6 +6476,12 @@ bool GDScriptParser::_get_function_signature(DataType &p_base_type, const String
base_script = base_script->get_base_script();
}
+ if (native == StringName()) {
+ // Empty native class, might happen in some Script implementations
+ // Just ignore it
+ return false;
+ }
+
#ifdef DEBUG_METHODS_ENABLED
// Only native remains
@@ -6900,6 +6924,10 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN
Ref<GDScript> gds;
if (base_type.kind == DataType::GDSCRIPT) {
gds = base_type.script_type;
+ if (gds.is_null() || !gds->is_valid()) {
+ // GDScript wasn't properly compíled, don't bother trying
+ return false;
+ }
}
Ref<Script> scr;
@@ -6962,6 +6990,12 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN
scr = scr->get_base_script();
}
+ if (native == StringName()) {
+ // Empty native class, might happen in some Script implementations
+ // Just ignore it
+ return false;
+ }
+
// Check ClassDB
if (!ClassDB::class_exists(native)) {
native = "_" + native.operator String();
@@ -7080,7 +7114,6 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType
DataType member_type;
for (int i = 0; i < current_class->variables.size(); i++) {
- ClassNode::Member m = current_class->variables[i];
if (current_class->variables[i].identifier == p_identifier) {
member_type = current_class->variables[i].data_type;
current_class->variables.write[i].usages += 1;
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index f13479940d..9b9088dd82 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -10,7 +10,7 @@
A GridMap is split into a sparse collection of octants for efficient rendering and physics processing. Every octant has the same dimensions and can contain several cells.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/tutorials/3d/using_gridmaps.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/using_gridmaps.html</link>
</tutorials>
<demos>
</demos>
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index a8fdf8cf1f..274a2f0249 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -892,7 +892,7 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("make_baked_meshes", "gen_lightmap_uv", "lightmap_uv_texel_size"), &GridMap::make_baked_meshes, DEFVAL(false), DEFVAL(0.1));
#ifndef DISABLE_DEPRECATED
- ADD_PROPERTYNO(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary", 0), "set_theme", "get_theme");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary", 0), "set_theme", "get_theme");
#endif // DISABLE_DEPRECATED
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh_library", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary"), "set_mesh_library", "get_mesh_library");
diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp
index fae88042af..126b49832a 100644
--- a/modules/gridmap/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/grid_map_editor_plugin.cpp
@@ -802,7 +802,9 @@ void GridMapEditor::edit(GridMap *p_gridmap) {
VisualServer::get_singleton()->instance_set_visible(grid_instance[i], false);
}
- VisualServer::get_singleton()->instance_set_visible(cursor_instance, false);
+ if (cursor_instance.is_valid()) {
+ VisualServer::get_singleton()->instance_set_visible(cursor_instance, false);
+ }
return;
}
diff --git a/modules/mono/editor/csharp_project.cpp b/modules/mono/editor/csharp_project.cpp
index 2400e9757b..416108603b 100644
--- a/modules/mono/editor/csharp_project.cpp
+++ b/modules/mono/editor/csharp_project.cpp
@@ -108,6 +108,9 @@ String generate_game_project(const String &p_dir, const String &p_name, const Ve
void add_item(const String &p_project_path, const String &p_item_type, const String &p_include) {
+ if (!GLOBAL_DEF("mono/project/auto_update_project", true))
+ return;
+
_GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectUtils");
diff --git a/modules/mono/glue/Managed/Files/GD.cs b/modules/mono/glue/Managed/Files/GD.cs
index e4818e186c..75a35a9eea 100644
--- a/modules/mono/glue/Managed/Files/GD.cs
+++ b/modules/mono/glue/Managed/Files/GD.cs
@@ -70,6 +70,16 @@ namespace Godot
return ResourceLoader.Load<T>(path);
}
+ public static void PushError(string message)
+ {
+ godot_icall_GD_pusherror(message);
+ }
+
+ public static void PushWarning(string message)
+ {
+ godot_icall_GD_pushwarning(message);
+ }
+
public static void Print(params object[] what)
{
godot_icall_GD_print(what);
@@ -238,5 +248,11 @@ namespace Godot
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static string godot_icall_GD_var2str(object var);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_GD_pusherror(string type);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_GD_pushwarning(string type);
}
}
diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp
index 051f42b966..9f5bcecdd9 100644
--- a/modules/mono/glue/gd_glue.cpp
+++ b/modules/mono/glue/gd_glue.cpp
@@ -157,6 +157,14 @@ bool godot_icall_GD_type_exists(MonoString *p_type) {
return ClassDB::class_exists(GDMonoMarshal::mono_string_to_godot(p_type));
}
+void godot_icall_GD_pusherror(MonoString *p_str) {
+ ERR_PRINTS(GDMonoMarshal::mono_string_to_godot(p_str));
+}
+
+void godot_icall_GD_pushwarning(MonoString *p_str) {
+ WARN_PRINTS(GDMonoMarshal::mono_string_to_godot(p_str));
+}
+
MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var) {
Variant var = GDMonoMarshal::mono_object_to_variant(p_var);
@@ -186,6 +194,8 @@ void godot_register_gd_icalls() {
mono_add_internal_call("Godot.GD::godot_icall_GD_convert", (void *)godot_icall_GD_convert);
mono_add_internal_call("Godot.GD::godot_icall_GD_hash", (void *)godot_icall_GD_hash);
mono_add_internal_call("Godot.GD::godot_icall_GD_instance_from_id", (void *)godot_icall_GD_instance_from_id);
+ mono_add_internal_call("Godot.GD::godot_icall_GD_pusherror", (void *)godot_icall_GD_pusherror);
+ mono_add_internal_call("Godot.GD::godot_icall_GD_pushwarning", (void *)godot_icall_GD_pushwarning);
mono_add_internal_call("Godot.GD::godot_icall_GD_print", (void *)godot_icall_GD_print);
mono_add_internal_call("Godot.GD::godot_icall_GD_printerr", (void *)godot_icall_GD_printerr);
mono_add_internal_call("Godot.GD::godot_icall_GD_printraw", (void *)godot_icall_GD_printraw);
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index fe41722af0..5d9b9213e7 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -223,6 +223,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
ERR_FAIL();
}
}
+
+ break;
}
ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + tclass->get_name());
diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp
index bdd3e31eb8..03ef024587 100644
--- a/modules/regex/regex.cpp
+++ b/modules/regex/regex.cpp
@@ -178,13 +178,17 @@ void RegEx::clear() {
if (sizeof(CharType) == 2) {
- if (code)
+ if (code) {
pcre2_code_free_16((pcre2_code_16 *)code);
+ code = NULL;
+ }
} else {
- if (code)
+ if (code) {
pcre2_code_free_32((pcre2_code_32 *)code);
+ code = NULL;
+ }
}
}
diff --git a/modules/squish/image_compress_squish.cpp b/modules/squish/image_compress_squish.cpp
index 26cb76011c..a08ac7bd28 100644
--- a/modules/squish/image_compress_squish.cpp
+++ b/modules/squish/image_compress_squish.cpp
@@ -64,12 +64,13 @@ void image_decompress_squish(Image *p_image) {
return;
}
- int dst_ofs = 0;
-
for (int i = 0; i <= mm_count; i++) {
int src_ofs = 0, mipmap_size = 0, mipmap_w = 0, mipmap_h = 0;
p_image->get_mipmap_offset_size_and_dimensions(i, src_ofs, mipmap_size, mipmap_w, mipmap_h);
- squish::DecompressImage(&wb[dst_ofs], mipmap_w, mipmap_h, &rb[src_ofs], squish_flags);
+ int dst_ofs = Image::get_image_mipmap_offset(p_image->get_width(), p_image->get_height(), target_format, i);
+ squish::DecompressImage(&wb[dst_ofs], w, h, &rb[src_ofs], squish_flags);
+ w >>= 1;
+ h >>= 1;
}
p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml
index 28764aca40..70849c5a80 100644
--- a/modules/visual_script/doc_classes/VisualScript.xml
+++ b/modules/visual_script/doc_classes/VisualScript.xml
@@ -9,7 +9,7 @@
You are most likely to use this class via the Visual Script editor or when writing plugins for it.
</description>
<tutorials>
- <link>http://docs.godotengine.org/en/3.0/getting_started/scripting/visual_script/index.html</link>
+ <link>https://docs.godotengine.org/en/latest/getting_started/scripting/visual_script/index.html</link>
</tutorials>
<demos>
</demos>
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 7fdd7fe446..c5f2070963 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -765,6 +765,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
}
void VisualScriptEditor::_update_members() {
+ ERR_FAIL_COND(!script.is_valid());
updating_members = true;
@@ -3018,11 +3019,15 @@ void VisualScriptEditor::_node_filter_changed(const String &p_text) {
void VisualScriptEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_READY) {
+ if (p_what == NOTIFICATION_READY || (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree())) {
+
node_filter->set_right_icon(Control::get_icon("Search", "EditorIcons"));
node_filter->set_clear_button_enabled(true);
- variable_editor->connect("changed", this, "_update_members");
- signal_editor->connect("changed", this, "_update_members");
+
+ if (p_what == NOTIFICATION_READY) {
+ variable_editor->connect("changed", this, "_update_members");
+ signal_editor->connect("changed", this, "_update_members");
+ }
Ref<Theme> tm = EditorNode::get_singleton()->get_theme_base()->get_theme();
@@ -3056,8 +3061,12 @@ void VisualScriptEditor::_notification(int p_what) {
node_styles[E->get().first] = frame_style;
}
}
- }
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+
+ if (is_visible_in_tree() && script.is_valid()) {
+ _update_members();
+ _update_graph();
+ }
+ } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
left_vsplit->set_visible(is_visible_in_tree());
}
}
@@ -3644,7 +3653,7 @@ VisualScriptEditor::VisualScriptEditor() {
new_virtual_method_select = memnew(VisualScriptPropertySelector);
add_child(new_virtual_method_select);
new_virtual_method_select->connect("selected", this, "_selected_new_virtual_method");
- new_virtual_method_select->get_cancel()->connect("pressed", this, "_selected_new_virtual_method");
+ new_virtual_method_select->get_cancel();
member_popup = memnew(PopupMenu);
add_child(member_popup);
diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h
index 97c75dae94..ce3245bc28 100644
--- a/modules/visual_script/visual_script_editor.h
+++ b/modules/visual_script/visual_script_editor.h
@@ -176,7 +176,7 @@ class VisualScriptEditor : public ScriptEditorBase {
void _cancel_connect_node();
void _create_new_node(const String &p_text, const String &p_category, const Vector2 &p_point);
- void _selected_new_virtual_method(const String &p_text = String(""), const String &p_category = String(""), const bool p_connecting = true);
+ void _selected_new_virtual_method(const String &p_text, const String &p_category, const bool p_connecting);
int error_line;
diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp
index 8255ed7116..82a577790e 100644
--- a/modules/websocket/emws_client.cpp
+++ b/modules/websocket/emws_client.cpp
@@ -31,6 +31,7 @@
#include "emws_client.h"
#include "core/io/ip.h"
+#include "core/project_settings.h"
#include "emscripten.h"
extern "C" {
@@ -43,8 +44,9 @@ EMSCRIPTEN_KEEPALIVE void _esws_on_connect(void *obj, char *proto) {
EMSCRIPTEN_KEEPALIVE void _esws_on_message(void *obj, uint8_t *p_data, int p_data_size, int p_is_string) {
EMWSClient *client = static_cast<EMWSClient *>(obj);
- static_cast<EMWSPeer *>(*client->get_peer(1))->read_msg(p_data, p_data_size, p_is_string == 1);
- client->_on_peer_packet();
+ Error err = static_cast<EMWSPeer *>(*client->get_peer(1))->read_msg(p_data, p_data_size, p_is_string == 1);
+ if (err == OK)
+ client->_on_peer_packet();
}
EMSCRIPTEN_KEEPALIVE void _esws_on_error(void *obj) {
@@ -159,7 +161,7 @@ Error EMWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
}, _js_id, str.utf8().get_data(), proto_string.utf8().get_data());
/* clang-format on */
- static_cast<Ref<EMWSPeer> >(_peer)->set_sock(peer_sock);
+ static_cast<Ref<EMWSPeer> >(_peer)->set_sock(peer_sock, _in_buf_size, _in_pkt_size);
return OK;
};
@@ -198,7 +200,13 @@ uint16_t EMWSClient::get_connected_port() const {
return 1025;
};
+int EMWSClient::get_max_packet_size() const {
+ return (1 << _in_buf_size) - PROTO_SIZE;
+}
+
EMWSClient::EMWSClient() {
+ _in_buf_size = GLOBAL_GET(WSC_IN_BUF);
+ _in_pkt_size = GLOBAL_GET(WSC_IN_PKT);
_is_connecting = false;
_peer = Ref<EMWSPeer>(memnew(EMWSPeer));
/* clang-format off */
diff --git a/modules/websocket/emws_client.h b/modules/websocket/emws_client.h
index b20633baff..a21090a1a3 100644
--- a/modules/websocket/emws_client.h
+++ b/modules/websocket/emws_client.h
@@ -41,6 +41,8 @@ class EMWSClient : public WebSocketClient {
GDCIIMPL(EMWSClient, WebSocketClient);
private:
+ int _in_buf_size;
+ int _in_pkt_size;
int _js_id;
public:
@@ -52,6 +54,7 @@ public:
IP_Address get_connected_host() const;
uint16_t get_connected_port() const;
virtual ConnectionStatus get_connection_status() const;
+ int get_max_packet_size() const;
virtual void poll();
EMWSClient();
~EMWSClient();
diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp
index 68f41165eb..bb97934824 100644
--- a/modules/websocket/emws_peer.cpp
+++ b/modules/websocket/emws_peer.cpp
@@ -32,11 +32,11 @@
#include "emws_peer.h"
#include "core/io/ip.h"
-void EMWSPeer::set_sock(int p_sock) {
+void EMWSPeer::set_sock(int p_sock, unsigned int p_in_buf_size, unsigned int p_in_pkt_size) {
peer_sock = p_sock;
- in_buffer.clear();
- queue_count = 0;
+ _in_buffer.resize(p_in_pkt_size, p_in_buf_size);
+ _packet_buffer.resize((1 << p_in_buf_size));
}
void EMWSPeer::set_write_mode(WriteMode p_mode) {
@@ -47,18 +47,10 @@ EMWSPeer::WriteMode EMWSPeer::get_write_mode() const {
return write_mode;
}
-void EMWSPeer::read_msg(uint8_t *p_data, uint32_t p_size, bool p_is_string) {
-
- if (in_buffer.space_left() < p_size + 5) {
- ERR_EXPLAIN("Buffer full! Dropping data");
- ERR_FAIL();
- }
+Error EMWSPeer::read_msg(uint8_t *p_data, uint32_t p_size, bool p_is_string) {
uint8_t is_string = p_is_string ? 1 : 0;
- in_buffer.write((uint8_t *)&p_size, 4);
- in_buffer.write((uint8_t *)&is_string, 1);
- in_buffer.write(p_data, p_size);
- queue_count++;
+ return _in_buffer.write_packet(p_data, p_size, &is_string);
}
Error EMWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
@@ -89,40 +81,28 @@ Error EMWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
Error EMWSPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
- if (queue_count == 0)
+ if (_in_buffer.packets_left() == 0)
return ERR_UNAVAILABLE;
- uint32_t to_read = 0;
- uint32_t left = 0;
- uint8_t is_string = 0;
- r_buffer_size = 0;
-
- in_buffer.read((uint8_t *)&to_read, 4);
- --queue_count;
- left = in_buffer.data_left();
+ PoolVector<uint8_t>::Write rw = _packet_buffer.write();
+ int read = 0;
+ Error err = _in_buffer.read_packet(rw.ptr(), _packet_buffer.size(), &_is_string, read);
+ ERR_FAIL_COND_V(err != OK, err);
- if (left < to_read + 1) {
- in_buffer.advance_read(left);
- return FAILED;
- }
-
- in_buffer.read(&is_string, 1);
- _was_string = is_string == 1;
- in_buffer.read(packet_buffer, to_read);
- *r_buffer = packet_buffer;
- r_buffer_size = to_read;
+ *r_buffer = rw.ptr();
+ r_buffer_size = read;
return OK;
};
int EMWSPeer::get_available_packet_count() const {
- return queue_count;
+ return _in_buffer.packets_left();
};
bool EMWSPeer::was_string_packet() const {
- return _was_string;
+ return _is_string;
};
bool EMWSPeer::is_connected_to_host() const {
@@ -143,9 +123,9 @@ void EMWSPeer::close(int p_code, String p_reason) {
}, peer_sock, p_code, p_reason.utf8().get_data());
/* clang-format on */
}
+ _is_string = 0;
+ _in_buffer.clear();
peer_sock = -1;
- queue_count = 0;
- in_buffer.clear();
};
IP_Address EMWSPeer::get_connected_host() const {
@@ -162,15 +142,12 @@ uint16_t EMWSPeer::get_connected_port() const {
EMWSPeer::EMWSPeer() {
peer_sock = -1;
- queue_count = 0;
- _was_string = false;
- in_buffer.resize(16);
write_mode = WRITE_MODE_BINARY;
+ close();
};
EMWSPeer::~EMWSPeer() {
- in_buffer.resize(0);
close();
};
diff --git a/modules/websocket/emws_peer.h b/modules/websocket/emws_peer.h
index a4b2c8f50b..4beb86d45b 100644
--- a/modules/websocket/emws_peer.h
+++ b/modules/websocket/emws_peer.h
@@ -36,6 +36,7 @@
#include "core/io/packet_peer.h"
#include "core/ring_buffer.h"
#include "emscripten.h"
+#include "packet_buffer.h"
#include "websocket_peer.h"
class EMWSPeer : public WebSocketPeer {
@@ -43,25 +44,20 @@ class EMWSPeer : public WebSocketPeer {
GDCIIMPL(EMWSPeer, WebSocketPeer);
private:
- enum {
- PACKET_BUFFER_SIZE = 65536 - 5 // 4 bytes for the size, 1 for for type
- };
-
int peer_sock;
WriteMode write_mode;
- uint8_t packet_buffer[PACKET_BUFFER_SIZE];
- RingBuffer<uint8_t> in_buffer;
- int queue_count;
- bool _was_string;
+ PoolVector<uint8_t> _packet_buffer;
+ PacketBuffer<uint8_t> _in_buffer;
+ uint8_t _is_string;
public:
- void read_msg(uint8_t *p_data, uint32_t p_size, bool p_is_string);
- void set_sock(int sock);
+ Error read_msg(uint8_t *p_data, uint32_t p_size, bool p_is_string);
+ void set_sock(int p_sock, unsigned int p_in_buf_size, unsigned int p_in_pkt_size);
virtual int get_available_packet_count() const;
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
- virtual int get_max_packet_size() const { return PACKET_BUFFER_SIZE; };
+ virtual int get_max_packet_size() const { return _packet_buffer.size(); };
virtual void close(int p_code = 1000, String p_reason = "");
virtual bool is_connected_to_host() const;
@@ -72,10 +68,6 @@ public:
virtual void set_write_mode(WriteMode p_mode);
virtual bool was_string_packet() const;
- void set_wsi(struct lws *wsi);
- Error read_wsi(void *in, size_t len);
- Error write_wsi();
-
EMWSPeer();
~EMWSPeer();
};
diff --git a/modules/websocket/emws_server.cpp b/modules/websocket/emws_server.cpp
index db02162699..09f9c1ceec 100644
--- a/modules/websocket/emws_server.cpp
+++ b/modules/websocket/emws_server.cpp
@@ -74,6 +74,10 @@ void EMWSServer::disconnect_peer(int p_peer_id, int p_code, String p_reason) {
void EMWSServer::poll() {
}
+int EMWSServer::get_max_packet_size() const {
+ return 0;
+}
+
EMWSServer::EMWSServer() {
}
diff --git a/modules/websocket/emws_server.h b/modules/websocket/emws_server.h
index 74b689a29b..2dc455c389 100644
--- a/modules/websocket/emws_server.h
+++ b/modules/websocket/emws_server.h
@@ -49,6 +49,7 @@ public:
IP_Address get_peer_address(int p_peer_id) const;
int get_peer_port(int p_peer_id) const;
void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "");
+ int get_max_packet_size() const;
virtual void poll();
virtual PoolVector<String> get_protocols() const;
diff --git a/modules/websocket/lws_client.cpp b/modules/websocket/lws_client.cpp
index d71d091720..fa0bb4cfb2 100644
--- a/modules/websocket/lws_client.cpp
+++ b/modules/websocket/lws_client.cpp
@@ -32,6 +32,7 @@
#include "lws_client.h"
#include "core/io/ip.h"
#include "core/io/stream_peer_ssl.h"
+#include "core/project_settings.h"
#include "tls/mbedtls/wrapper/include/openssl/ssl.h"
Error LWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocols) {
@@ -90,12 +91,13 @@ Error LWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
i.ssl_connection = 0;
}
- // This String needs to survive till we call lws_client_connect_via_info
- String addr_str = (String)addr;
-
- i.address = addr_str.ascii().get_data();
- i.host = p_host.utf8().get_data();
- i.path = p_path.utf8().get_data();
+ // These CharStrings needs to survive till we call lws_client_connect_via_info
+ CharString addr_ch = ((String)addr).ascii();
+ CharString host_ch = p_host.utf8();
+ CharString path_ch = p_path.utf8();
+ i.address = addr_ch.get_data();
+ i.host = host_ch.get_data();
+ i.path = path_ch.get_data();
i.port = p_port;
lws_client_connect_via_info(&i);
@@ -103,6 +105,10 @@ Error LWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
return OK;
};
+int LWSClient::get_max_packet_size() const {
+ return (1 << _out_buf_size) - PROTO_SIZE;
+}
+
void LWSClient::poll() {
_lws_poll();
@@ -123,7 +129,7 @@ int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi
} break;
case LWS_CALLBACK_CLIENT_ESTABLISHED:
- peer->set_wsi(wsi);
+ peer->set_wsi(wsi, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size);
peer_data->peer_id = 0;
peer_data->force_close = false;
peer_data->clean_close = false;
@@ -206,6 +212,11 @@ uint16_t LWSClient::get_connected_port() const {
};
LWSClient::LWSClient() {
+ _in_buf_size = nearest_shift((int)GLOBAL_GET(WSC_IN_BUF) - 1) + 10;
+ _in_pkt_size = nearest_shift((int)GLOBAL_GET(WSC_IN_PKT) - 1);
+ _out_buf_size = nearest_shift((int)GLOBAL_GET(WSC_OUT_BUF) - 1) + 10;
+ _out_pkt_size = nearest_shift((int)GLOBAL_GET(WSC_OUT_PKT) - 1);
+
context = NULL;
_lws_ref = NULL;
_peer = Ref<LWSPeer>(memnew(LWSPeer));
diff --git a/modules/websocket/lws_client.h b/modules/websocket/lws_client.h
index 1bbc19f352..fdecb99925 100644
--- a/modules/websocket/lws_client.h
+++ b/modules/websocket/lws_client.h
@@ -43,8 +43,15 @@ class LWSClient : public WebSocketClient {
LWS_HELPER(LWSClient);
+private:
+ int _in_buf_size;
+ int _in_pkt_size;
+ int _out_buf_size;
+ int _out_pkt_size;
+
public:
Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocol = PoolVector<String>());
+ int get_max_packet_size() const;
Ref<WebSocketPeer> get_peer(int p_peer_id) const;
void disconnect_from_host(int p_code = 1000, String p_reason = "");
IP_Address get_connected_host() const;
diff --git a/modules/websocket/lws_peer.cpp b/modules/websocket/lws_peer.cpp
index b5c130b308..04e6e7c951 100644
--- a/modules/websocket/lws_peer.cpp
+++ b/modules/websocket/lws_peer.cpp
@@ -41,11 +41,12 @@
#include "drivers/unix/net_socket_posix.h"
-void LWSPeer::set_wsi(struct lws *p_wsi) {
+void LWSPeer::set_wsi(struct lws *p_wsi, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size, unsigned int p_out_pkt_size) {
ERR_FAIL_COND(wsi != NULL);
- rbw.resize(16);
- rbr.resize(16);
+ _in_buffer.resize(p_in_pkt_size, p_in_buf_size);
+ _out_buffer.resize(p_out_pkt_size, p_out_buf_size);
+ _packet_buffer.resize((1 << MAX(p_in_buf_size, p_out_buf_size)) + LWS_PRE);
wsi = p_wsi;
};
@@ -61,24 +62,29 @@ Error LWSPeer::read_wsi(void *in, size_t len) {
ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
- uint32_t size = in_size;
- uint8_t is_string = lws_frame_is_binary(wsi) ? 0 : 1;
+ if (lws_is_first_fragment(wsi))
+ _in_size = 0;
+ else if (_in_size == -1) // Trash this frame
+ return ERR_FILE_CORRUPT;
- if (rbr.space_left() < len + 5) {
- ERR_EXPLAIN("Buffer full! Dropping data");
- ERR_FAIL_V(FAILED);
+ Error err = _in_buffer.write_packet((const uint8_t *)in, len, NULL);
+
+ if (err != OK) {
+ _in_buffer.discard_payload(_in_size);
+ _in_size = -1;
+ ERR_FAIL_V(err);
}
- copymem(&(input_buffer[size]), in, len);
- size += len;
+ _in_size += len;
- in_size = size;
if (lws_is_final_fragment(wsi)) {
- rbr.write((uint8_t *)&size, 4);
- rbr.write((uint8_t *)&is_string, 1);
- rbr.write(input_buffer, size);
- in_count++;
- in_size = 0;
+ uint8_t is_string = lws_frame_is_binary(wsi) ? 0 : 1;
+ err = _in_buffer.write_packet(NULL, _in_size, &is_string);
+ if (err != OK) {
+ _in_buffer.discard_payload(_in_size);
+ _in_size = -1;
+ ERR_FAIL_V(err);
+ }
}
return OK;
@@ -89,26 +95,20 @@ Error LWSPeer::write_wsi() {
ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
PoolVector<uint8_t> tmp;
- int left = rbw.data_left();
- uint32_t to_write = 0;
+ int count = _out_buffer.packets_left();
- if (left == 0 || out_count == 0)
+ if (count == 0)
return OK;
- rbw.read((uint8_t *)&to_write, 4);
- out_count--;
-
- if (left < to_write) {
- rbw.advance_read(left);
- return FAILED;
- }
+ int read = 0;
+ uint8_t is_string;
+ PoolVector<uint8_t>::Write rw = _packet_buffer.write();
+ _out_buffer.read_packet(&(rw[LWS_PRE]), _packet_buffer.size() - LWS_PRE, &is_string, read);
- tmp.resize(LWS_PRE + to_write);
- rbw.read(&(tmp.write()[LWS_PRE]), to_write);
- lws_write(wsi, &(tmp.write()[LWS_PRE]), to_write, (enum lws_write_protocol)write_mode);
- tmp.resize(0);
+ enum lws_write_protocol mode = is_string ? LWS_WRITE_TEXT : LWS_WRITE_BINARY;
+ lws_write(wsi, &(rw[LWS_PRE]), read, mode);
- if (out_count > 0)
+ if (count > 1)
lws_callback_on_writable(wsi); // we want to write more!
return OK;
@@ -118,40 +118,27 @@ Error LWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
- rbw.write((uint8_t *)&p_buffer_size, 4);
- rbw.write(p_buffer, MIN(p_buffer_size, rbw.space_left()));
- out_count++;
-
+ uint8_t is_string = write_mode == WRITE_MODE_TEXT;
+ _out_buffer.write_packet(p_buffer, p_buffer_size, &is_string);
lws_callback_on_writable(wsi); // notify that we want to write
return OK;
};
Error LWSPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
+ r_buffer_size = 0;
+
ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
- if (in_count == 0)
+ if (_in_buffer.packets_left() == 0)
return ERR_UNAVAILABLE;
- uint32_t to_read = 0;
- uint32_t left = 0;
- uint8_t is_string = 0;
- r_buffer_size = 0;
-
- rbr.read((uint8_t *)&to_read, 4);
- in_count--;
- left = rbr.data_left();
-
- if (left < to_read + 1) {
- rbr.advance_read(left);
- return FAILED;
- }
+ int read = 0;
+ PoolVector<uint8_t>::Write rw = _packet_buffer.write();
+ _in_buffer.read_packet(rw.ptr(), _packet_buffer.size(), &_is_string, read);
- rbr.read(&is_string, 1);
- rbr.read(packet_buffer, to_read);
- *r_buffer = packet_buffer;
- r_buffer_size = to_read;
- _was_string = is_string;
+ *r_buffer = rw.ptr();
+ r_buffer_size = read;
return OK;
};
@@ -161,12 +148,12 @@ int LWSPeer::get_available_packet_count() const {
if (!is_connected_to_host())
return 0;
- return in_count;
+ return _in_buffer.packets_left();
};
bool LWSPeer::was_string_packet() const {
- return _was_string;
+ return _is_string;
};
bool LWSPeer::is_connected_to_host() const {
@@ -219,12 +206,11 @@ void LWSPeer::close(int p_code, String p_reason) {
close_reason = "";
}
wsi = NULL;
- rbw.resize(0);
- rbr.resize(0);
- in_count = 0;
- in_size = 0;
- out_count = 0;
- _was_string = false;
+ _in_buffer.clear();
+ _out_buffer.clear();
+ _in_size = 0;
+ _is_string = 0;
+ _packet_buffer.resize(0);
};
IP_Address LWSPeer::get_connected_host() const {
diff --git a/modules/websocket/lws_peer.h b/modules/websocket/lws_peer.h
index 571445db01..3ded3810d1 100644
--- a/modules/websocket/lws_peer.h
+++ b/modules/websocket/lws_peer.h
@@ -37,6 +37,7 @@
#include "core/ring_buffer.h"
#include "libwebsockets.h"
#include "lws_config.h"
+#include "packet_buffer.h"
#include "websocket_peer.h"
class LWSPeer : public WebSocketPeer {
@@ -44,14 +45,16 @@ class LWSPeer : public WebSocketPeer {
GDCIIMPL(LWSPeer, WebSocketPeer);
private:
- enum {
- PACKET_BUFFER_SIZE = 65536 - 5 // 4 bytes for the size, 1 for the type
- };
+ int _in_size;
+ uint8_t _is_string;
+ // Our packet info is just a boolean (is_string), using uint8_t for it.
+ PacketBuffer<uint8_t> _in_buffer;
+ PacketBuffer<uint8_t> _out_buffer;
+
+ PoolVector<uint8_t> _packet_buffer;
- uint8_t packet_buffer[PACKET_BUFFER_SIZE];
struct lws *wsi;
WriteMode write_mode;
- bool _was_string;
int close_code;
String close_reason;
@@ -63,17 +66,10 @@ public:
bool clean_close;
};
- RingBuffer<uint8_t> rbw;
- RingBuffer<uint8_t> rbr;
- uint8_t input_buffer[PACKET_BUFFER_SIZE];
- uint32_t in_size;
- int in_count;
- int out_count;
-
virtual int get_available_packet_count() const;
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
- virtual int get_max_packet_size() const { return PACKET_BUFFER_SIZE; };
+ virtual int get_max_packet_size() const { return _packet_buffer.size(); };
virtual void close(int p_code = 1000, String p_reason = "");
virtual bool is_connected_to_host() const;
@@ -84,7 +80,7 @@ public:
virtual void set_write_mode(WriteMode p_mode);
virtual bool was_string_packet() const;
- void set_wsi(struct lws *wsi);
+ void set_wsi(struct lws *wsi, unsigned int _in_buf_size, unsigned int _in_pkt_size, unsigned int _out_buf_size, unsigned int _out_pkt_size);
Error read_wsi(void *in, size_t len);
Error write_wsi();
void send_close_status(struct lws *wsi);
diff --git a/modules/websocket/lws_server.cpp b/modules/websocket/lws_server.cpp
index 58fa043346..0e551eb318 100644
--- a/modules/websocket/lws_server.cpp
+++ b/modules/websocket/lws_server.cpp
@@ -31,6 +31,7 @@
#include "lws_server.h"
#include "core/os/os.h"
+#include "core/project_settings.h"
Error LWSServer::listen(int p_port, PoolVector<String> p_protocols, bool gd_mp_api) {
@@ -67,6 +68,10 @@ bool LWSServer::is_listening() const {
return context != NULL;
}
+int LWSServer::get_max_packet_size() const {
+ return (1 << _out_buf_size) - PROTO_SIZE;
+}
+
int LWSServer::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
LWSPeer::PeerData *peer_data = (LWSPeer::PeerData *)user;
@@ -85,7 +90,7 @@ int LWSServer::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi
int32_t id = _gen_unique_id();
Ref<LWSPeer> peer = Ref<LWSPeer>(memnew(LWSPeer));
- peer->set_wsi(wsi);
+ peer->set_wsi(wsi, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size);
_peer_map[id] = peer;
peer_data->peer_id = id;
@@ -192,6 +197,10 @@ void LWSServer::disconnect_peer(int p_peer_id, int p_code, String p_reason) {
}
LWSServer::LWSServer() {
+ _in_buf_size = nearest_shift((int)GLOBAL_GET(WSS_IN_BUF) - 1) + 10;
+ _in_pkt_size = nearest_shift((int)GLOBAL_GET(WSS_IN_PKT) - 1);
+ _out_buf_size = nearest_shift((int)GLOBAL_GET(WSS_OUT_BUF) - 1) + 10;
+ _out_pkt_size = nearest_shift((int)GLOBAL_GET(WSS_OUT_PKT) - 1);
context = NULL;
_lws_ref = NULL;
}
diff --git a/modules/websocket/lws_server.h b/modules/websocket/lws_server.h
index 346773ebc4..c43044f194 100644
--- a/modules/websocket/lws_server.h
+++ b/modules/websocket/lws_server.h
@@ -45,11 +45,16 @@ class LWSServer : public WebSocketServer {
private:
Map<int, Ref<LWSPeer> > peer_map;
+ int _in_buf_size;
+ int _in_pkt_size;
+ int _out_buf_size;
+ int _out_pkt_size;
public:
Error listen(int p_port, PoolVector<String> p_protocols = PoolVector<String>(), bool gd_mp_api = false);
void stop();
bool is_listening() const;
+ int get_max_packet_size() const;
bool has_peer(int p_id) const;
Ref<WebSocketPeer> get_peer(int p_id) const;
IP_Address get_peer_address(int p_peer_id) const;
diff --git a/modules/websocket/packet_buffer.h b/modules/websocket/packet_buffer.h
new file mode 100644
index 0000000000..a3af7f728a
--- /dev/null
+++ b/modules/websocket/packet_buffer.h
@@ -0,0 +1,122 @@
+/*************************************************************************/
+/* packet_buffer.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef PACKET_BUFFER_H
+#define PACKET_BUFFER_H
+
+#include "core/os/copymem.h"
+#include "core/ring_buffer.h"
+
+template <class T>
+class PacketBuffer {
+
+private:
+ typedef struct {
+ uint32_t size;
+ T info;
+ } _Packet;
+
+ RingBuffer<_Packet> _packets;
+ RingBuffer<uint8_t> _payload;
+
+public:
+ Error write_packet(const uint8_t *p_payload, uint32_t p_size, const T *p_info) {
+#ifdef TOOLS_ENABLED
+ // Verbose buffer warnings
+ if (p_payload && _payload.space_left() < p_size) {
+ ERR_PRINT("Buffer payload full! Dropping data.");
+ ERR_FAIL_V(ERR_OUT_OF_MEMORY);
+ }
+ if (p_info && _packets.space_left() < 1) {
+ ERR_PRINT("Too many packets in queue! Dropping data.");
+ ERR_FAIL_V(ERR_OUT_OF_MEMORY);
+ }
+#else
+ ERR_FAIL_COND_V(p_payload && _payload.space_left() < p_size, ERR_OUT_OF_MEMORY);
+ ERR_FAIL_COND_V(p_info && _packets.space_left() < 1, ERR_OUT_OF_MEMORY);
+#endif
+
+ // If p_info is NULL, only the payload is written
+ if (p_info) {
+ _Packet p;
+ p.size = p_size;
+ copymem(&p.info, p_info, sizeof(T));
+ _packets.write(p);
+ }
+
+ // If p_payload is NULL, only the packet information is written.
+ if (p_payload) {
+ _payload.write((const uint8_t *)p_payload, p_size);
+ }
+
+ return OK;
+ }
+
+ Error read_packet(uint8_t *r_payload, int p_bytes, T *r_info, int &r_read) {
+ ERR_FAIL_COND_V(_packets.data_left() < 1, ERR_UNAVAILABLE);
+ _Packet p;
+ _packets.read(&p, 1);
+ ERR_FAIL_COND_V(_payload.data_left() < p.size, ERR_BUG);
+ ERR_FAIL_COND_V(p_bytes < p.size, ERR_OUT_OF_MEMORY);
+
+ r_read = p.size;
+ copymem(r_info, &p.info, sizeof(T));
+ _payload.read(r_payload, p.size);
+ return OK;
+ }
+
+ void discard_payload(int p_size) {
+ _packets.decrease_write(p_size);
+ }
+
+ void resize(int p_pkt_shift, int p_buf_shift) {
+ _packets.resize(p_pkt_shift);
+ _payload.resize(p_buf_shift);
+ }
+
+ int packets_left() const {
+ return _packets.data_left();
+ }
+
+ void clear() {
+ _payload.resize(0);
+ _packets.resize(0);
+ }
+
+ PacketBuffer() {
+ clear();
+ }
+
+ ~PacketBuffer() {
+ clear();
+ }
+};
+
+#endif // PACKET_BUFFER_H
diff --git a/modules/websocket/register_types.cpp b/modules/websocket/register_types.cpp
index 538cd40454..8946faffa9 100644
--- a/modules/websocket/register_types.cpp
+++ b/modules/websocket/register_types.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "register_types.h"
#include "core/error_macros.h"
+#include "core/project_settings.h"
#ifdef JAVASCRIPT_ENABLED
#include "emscripten.h"
#include "emws_client.h"
@@ -41,6 +42,22 @@
#endif
void register_websocket_types() {
+#define _SET_HINT(NAME, _VAL_, _MAX_) \
+ GLOBAL_DEF(NAME, _VAL_); \
+ ProjectSettings::get_singleton()->set_custom_property_info(NAME, PropertyInfo(Variant::INT, NAME, PROPERTY_HINT_RANGE, "2," #_MAX_ ",1,or_greater"));
+
+ // Client buffers project settings
+ _SET_HINT(WSC_IN_BUF, 64, 4096);
+ _SET_HINT(WSC_IN_PKT, 1024, 16384);
+ _SET_HINT(WSC_OUT_BUF, 64, 4096);
+ _SET_HINT(WSC_OUT_PKT, 1024, 16384);
+
+ // Server buffers project settings
+ _SET_HINT(WSS_IN_BUF, 64, 4096);
+ _SET_HINT(WSS_IN_PKT, 1024, 16384);
+ _SET_HINT(WSS_OUT_BUF, 64, 4096);
+ _SET_HINT(WSS_OUT_PKT, 1024, 16384);
+
#ifdef JAVASCRIPT_ENABLED
EM_ASM({
var IDHandler = {};
diff --git a/modules/websocket/websocket_client.cpp b/modules/websocket/websocket_client.cpp
index f9b94dc519..6c5018bb79 100644
--- a/modules/websocket/websocket_client.cpp
+++ b/modules/websocket/websocket_client.cpp
@@ -136,7 +136,7 @@ void WebSocketClient::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_verify_ssl_enabled", "enabled"), &WebSocketClient::set_verify_ssl_enabled);
ClassDB::bind_method(D_METHOD("is_verify_ssl_enabled"), &WebSocketClient::is_verify_ssl_enabled);
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "verify_ssl", PROPERTY_HINT_NONE, "", 0), "set_verify_ssl_enabled", "is_verify_ssl_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "verify_ssl", PROPERTY_HINT_NONE, "", 0), "set_verify_ssl_enabled", "is_verify_ssl_enabled");
ADD_SIGNAL(MethodInfo("data_received"));
ADD_SIGNAL(MethodInfo("connection_established", PropertyInfo(Variant::STRING, "protocol")));
diff --git a/modules/websocket/websocket_macros.h b/modules/websocket/websocket_macros.h
index d27fb4d778..45dd30d0ce 100644
--- a/modules/websocket/websocket_macros.h
+++ b/modules/websocket/websocket_macros.h
@@ -30,6 +30,16 @@
#ifndef WEBSOCKETMACTOS_H
#define WEBSOCKETMACTOS_H
+#define WSC_IN_BUF "network/limits/websocket_client/max_in_buffer_kb"
+#define WSC_IN_PKT "network/limits/websocket_client/max_in_packets"
+#define WSC_OUT_BUF "network/limits/websocket_client/max_out_buffer_kb"
+#define WSC_OUT_PKT "network/limits/websocket_client/max_out_packets"
+
+#define WSS_IN_BUF "network/limits/websocket_server/max_in_buffer_kb"
+#define WSS_IN_PKT "network/limits/websocket_server/max_in_packets"
+#define WSS_OUT_BUF "network/limits/websocket_server/max_out_buffer_kb"
+#define WSS_OUT_PKT "network/limits/websocket_server/max_out_packets"
+
/* clang-format off */
#define GDCICLASS(CNAME) \
public:\
diff --git a/modules/websocket/websocket_multiplayer.cpp b/modules/websocket/websocket_multiplayer.cpp
index 873658559a..9a95c17e47 100644
--- a/modules/websocket/websocket_multiplayer.cpp
+++ b/modules/websocket/websocket_multiplayer.cpp
@@ -100,13 +100,6 @@ int WebSocketMultiplayerPeer::get_available_packet_count() const {
return _incoming_packets.size();
}
-int WebSocketMultiplayerPeer::get_max_packet_size() const {
-
- ERR_FAIL_COND_V(!_is_multiplayer, ERR_UNCONFIGURED);
-
- return MAX_PACKET_SIZE;
-}
-
Error WebSocketMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
r_buffer_size = 0;
diff --git a/modules/websocket/websocket_multiplayer.h b/modules/websocket/websocket_multiplayer.h
index 8edfc5296e..3cba0011fc 100644
--- a/modules/websocket/websocket_multiplayer.h
+++ b/modules/websocket/websocket_multiplayer.h
@@ -51,9 +51,7 @@ protected:
SYS_DEL = 2,
SYS_ID = 3,
- PROTO_SIZE = 9,
- SYS_PACKET_SIZE = 13,
- MAX_PACKET_SIZE = 65536 - 14 // 5 websocket, 9 multiplayer
+ PROTO_SIZE = 9
};
struct Packet {
@@ -93,7 +91,7 @@ public:
/* PacketPeer */
virtual int get_available_packet_count() const;
- virtual int get_max_packet_size() const;
+ virtual int get_max_packet_size() const = 0;
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
diff --git a/modules/websocket/websocket_peer.h b/modules/websocket/websocket_peer.h
index 5918fda3c2..4966cdfc72 100644
--- a/modules/websocket/websocket_peer.h
+++ b/modules/websocket/websocket_peer.h
@@ -32,7 +32,6 @@
#include "core/error_list.h"
#include "core/io/packet_peer.h"
-#include "core/ring_buffer.h"
#include "websocket_macros.h"
class WebSocketPeer : public PacketPeer {