summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/SCsub8
-rw-r--r--modules/bullet/SCsub24
-rw-r--r--modules/bullet/SCsub_with_lib33
-rw-r--r--modules/bullet/area_bullet.cpp4
-rw-r--r--modules/bullet/btRayShape.cpp5
-rw-r--r--modules/bullet/btRayShape.h4
-rw-r--r--modules/bullet/bullet_physics_server.cpp36
-rw-r--r--modules/bullet/bullet_physics_server.h11
-rw-r--r--modules/bullet/collision_object_bullet.cpp25
-rw-r--r--modules/bullet/constraint_bullet.cpp12
-rw-r--r--modules/bullet/constraint_bullet.h4
-rw-r--r--modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml2
-rw-r--r--modules/bullet/doc_classes/BulletPhysicsServer.xml2
-rw-r--r--modules/bullet/godot_motion_state.h4
-rw-r--r--modules/bullet/godot_ray_world_algorithm.cpp17
-rw-r--r--modules/bullet/godot_ray_world_algorithm.h2
-rw-r--r--modules/bullet/godot_result_callbacks.cpp11
-rw-r--r--modules/bullet/godot_result_callbacks.h8
-rw-r--r--modules/bullet/rigid_body_bullet.cpp19
-rw-r--r--modules/bullet/rigid_body_bullet.h10
-rw-r--r--modules/bullet/shape_bullet.cpp26
-rw-r--r--modules/bullet/shape_bullet.h21
-rw-r--r--modules/bullet/space_bullet.cpp40
-rw-r--r--modules/bullet/space_bullet.h8
-rw-r--r--modules/enet/SCsub4
-rw-r--r--modules/enet/doc_classes/NetworkedMultiplayerENet.xml2
-rw-r--r--modules/freetype/SCsub2
-rw-r--r--modules/gdnative/SCsub60
-rw-r--r--modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml2
-rw-r--r--modules/gdnative/doc_classes/GDNative.xml2
-rw-r--r--modules/gdnative/doc_classes/GDNativeLibrary.xml2
-rw-r--r--modules/gdnative/doc_classes/NativeScript.xml38
-rw-r--r--modules/gdnative/doc_classes/PluginScript.xml2
-rw-r--r--modules/gdnative/gdnative.cpp16
-rw-r--r--modules/gdnative/gdnative/pool_arrays.cpp56
-rw-r--r--modules/gdnative/gdnative_api.json201
-rw-r--r--modules/gdnative/gdnative_library_editor_plugin.h2
-rw-r--r--modules/gdnative/include/gdnative/gdnative.h2
-rw-r--r--modules/gdnative/include/gdnative/pool_arrays.h14
-rw-r--r--modules/gdnative/include/gdnative/variant.h2
-rw-r--r--modules/gdnative/include/nativescript/godot_nativescript.h48
-rw-r--r--modules/gdnative/include/pluginscript/godot_pluginscript.h2
-rw-r--r--modules/gdnative/nativescript/godot_nativescript.cpp164
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp274
-rw-r--r--modules/gdnative/nativescript/nativescript.h32
-rw-r--r--modules/gdnative/nativescript/register_types.cpp1
-rw-r--r--modules/gdnative/pluginscript/pluginscript_instance.cpp5
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.cpp1
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.cpp49
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.h4
-rw-r--r--modules/gdscript/doc_classes/GDScript.xml3
-rw-r--r--modules/gdscript/doc_classes/GDScriptFunctionState.xml2
-rw-r--r--modules/gdscript/doc_classes/GDScriptNativeClass.xml2
-rw-r--r--modules/gdscript/gdscript_compiler.cpp40
-rw-r--r--modules/gdscript/gdscript_editor.cpp22
-rw-r--r--modules/gdscript/gdscript_functions.cpp18
-rw-r--r--modules/gdscript/gdscript_parser.cpp84
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml3
-rw-r--r--modules/gridmap/grid_map.h2
-rw-r--r--modules/gridmap/grid_map_editor_plugin.cpp20
-rw-r--r--modules/gridmap/grid_map_editor_plugin.h1
-rwxr-xr-xmodules/mbedtls/SCsub91
-rwxr-xr-x[-rw-r--r--]modules/mbedtls/config.py (renamed from modules/openssl/config.py)0
-rwxr-xr-x[-rw-r--r--]modules/mbedtls/register_types.cpp (renamed from modules/openssl/register_types.cpp)12
-rwxr-xr-x[-rw-r--r--]modules/mbedtls/register_types.h (renamed from modules/openssl/register_types.h)4
-rwxr-xr-xmodules/mbedtls/stream_peer_mbed_tls.cpp325
-rwxr-xr-x[-rw-r--r--]modules/mbedtls/stream_peer_mbed_tls.h (renamed from modules/openssl/stream_peer_openssl.h)63
-rw-r--r--modules/mobile_vr/doc_classes/MobileVRInterface.xml2
-rw-r--r--modules/mobile_vr/mobile_interface.cpp2
-rw-r--r--modules/mono/SCsub27
-rw-r--r--modules/mono/config.py1
-rw-r--r--modules/mono/csharp_script.cpp171
-rw-r--r--modules/mono/csharp_script.h23
-rw-r--r--modules/mono/doc_classes/@C#.xml2
-rw-r--r--modules/mono/doc_classes/CSharpScript.xml2
-rw-r--r--modules/mono/doc_classes/GodotSharp.xml2
-rw-r--r--modules/mono/editor/bindings_generator.cpp202
-rw-r--r--modules/mono/editor/bindings_generator.h12
-rw-r--r--modules/mono/editor/godotsharp_builds.cpp61
-rw-r--r--modules/mono/editor/godotsharp_builds.h16
-rw-r--r--modules/mono/editor/godotsharp_editor.cpp97
-rw-r--r--modules/mono/editor/godotsharp_editor.h9
-rw-r--r--modules/mono/editor/godotsharp_export.cpp166
-rw-r--r--modules/mono/editor/godotsharp_export.h57
-rw-r--r--modules/mono/editor/mono_bottom_panel.cpp12
-rw-r--r--modules/mono/editor/monodevelop_instance.h2
-rw-r--r--modules/mono/glue/builtin_types_glue.h59
-rw-r--r--modules/mono/glue/cs_files/Basis.cs6
-rw-r--r--modules/mono/glue/cs_files/DebuggingUtils.cs4
-rw-r--r--modules/mono/glue/cs_files/Mathf.cs2
-rw-r--r--modules/mono/glue/cs_files/Plane.cs2
-rw-r--r--modules/mono/glue/cs_files/SignalAttribute.cs12
-rwxr-xr-xmodules/mono/glue/cs_files/VERSION.txt1
-rw-r--r--modules/mono/glue/glue_header.h18
-rw-r--r--modules/mono/godotsharp_defs.h3
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp338
-rw-r--r--modules/mono/mono_gd/gd_mono.h63
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp113
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h19
-rw-r--r--modules/mono/mono_gd/gd_mono_class.cpp28
-rw-r--r--modules/mono/mono_gd/gd_mono_class.h8
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp16
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h9
-rw-r--r--modules/mono/mono_gd/gd_mono_method.cpp17
-rw-r--r--modules/mono/mono_gd/gd_mono_method.h3
-rw-r--r--modules/mono/mono_gd/gd_mono_property.cpp2
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp71
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h3
-rw-r--r--modules/mono/signal_awaiter_utils.cpp2
-rw-r--r--modules/openssl/SCsub696
-rw-r--r--modules/openssl/stream_peer_openssl.cpp632
-rw-r--r--modules/regex/doc_classes/RegEx.xml6
-rw-r--r--modules/regex/doc_classes/RegExMatch.xml2
-rw-r--r--modules/stb_vorbis/audio_stream_ogg_vorbis.cpp12
-rw-r--r--modules/stb_vorbis/audio_stream_ogg_vorbis.h4
-rw-r--r--modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml2
-rw-r--r--modules/stb_vorbis/doc_classes/ResourceImporterOGGVorbis.xml2
-rw-r--r--modules/theora/doc_classes/ResourceImporterTheora.xml2
-rw-r--r--modules/theora/doc_classes/VideoStreamTheora.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScript.xml3
-rw-r--r--modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptClassConstant.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptComment.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptCondition.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptConstant.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptConstructor.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptCustomNode.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptDeconstruct.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptEditor.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptEmitSignal.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptExpression.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptFunction.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptFunctionCall.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptFunctionState.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptIndexGet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptIndexSet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptInputAction.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptIterator.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptLocalVar.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptMathConstant.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptNode.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptOperator.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPreload.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPropertyGet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPropertySet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptResourcePath.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptReturn.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSceneNode.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSceneTree.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSelect.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSelf.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSequence.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSubCall.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSwitch.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptTypeCast.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptVariableGet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptVariableSet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptWhile.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptYield.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptYieldSignal.xml2
-rw-r--r--modules/visual_script/visual_script.cpp4
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp16
-rw-r--r--modules/visual_script/visual_script_editor.cpp47
-rw-r--r--modules/visual_script/visual_script_editor.h1
-rw-r--r--modules/visual_script/visual_script_nodes.cpp6
-rw-r--r--modules/webm/doc_classes/ResourceImporterWebm.xml2
-rw-r--r--modules/webm/doc_classes/VideoStreamWebm.xml2
-rw-r--r--modules/webm/libvpx/SCsub48
-rw-r--r--modules/webm/libvpx/yasm_osx_fat.py38
-rw-r--r--modules/websocket/SCsub84
-rw-r--r--modules/websocket/config.py7
-rw-r--r--modules/websocket/emws_client.cpp224
-rw-r--r--modules/websocket/emws_client.h62
-rw-r--r--modules/websocket/emws_peer.cpp173
-rw-r--r--modules/websocket/emws_peer.h85
-rw-r--r--modules/websocket/emws_server.cpp67
-rw-r--r--modules/websocket/emws_server.h58
-rw-r--r--modules/websocket/lws_client.cpp203
-rw-r--r--modules/websocket/lws_client.h61
-rw-r--r--modules/websocket/lws_helper.h214
-rw-r--r--modules/websocket/lws_peer.cpp200
-rw-r--r--modules/websocket/lws_peer.h92
-rw-r--r--modules/websocket/lws_server.cpp177
-rw-r--r--modules/websocket/lws_server.h63
-rw-r--r--modules/websocket/register_types.cpp79
-rw-r--r--modules/websocket/register_types.h31
-rw-r--r--modules/websocket/websocket_client.cpp124
-rw-r--r--modules/websocket/websocket_client.h68
-rw-r--r--modules/websocket/websocket_macros.h63
-rw-r--r--modules/websocket/websocket_multiplayer.cpp361
-rw-r--r--modules/websocket/websocket_multiplayer.h110
-rw-r--r--modules/websocket/websocket_peer.cpp49
-rw-r--r--modules/websocket/websocket_peer.h73
-rw-r--r--modules/websocket/websocket_server.cpp94
-rw-r--r--modules/websocket/websocket_server.h63
199 files changed, 6034 insertions, 2146 deletions
diff --git a/modules/SCsub b/modules/SCsub
index e3c535e981..74a5267355 100644
--- a/modules/SCsub
+++ b/modules/SCsub
@@ -17,6 +17,10 @@ for x in env.module_list:
env_modules.Append(CPPFLAGS=["-DMODULE_" + x.upper() + "_ENABLED"])
SConscript(x + "/SCsub")
-lib = env_modules.add_library("modules", env.modules_sources)
+if env.split_modules:
+ env.split_lib("modules", env_lib = env_modules)
+else:
-env.Prepend(LIBS=[lib])
+ lib = env_modules.add_library("modules", env.modules_sources)
+
+ env.Prepend(LIBS=[lib])
diff --git a/modules/bullet/SCsub b/modules/bullet/SCsub
index 0967bca3f2..d8d0b930a5 100644
--- a/modules/bullet/SCsub
+++ b/modules/bullet/SCsub
@@ -3,12 +3,15 @@
Import('env')
Import('env_modules')
-# build only version 2
-# Bullet 2.87
-
env_bullet = env_modules.Clone()
-bullet_src__2_x = [
+# Thirdparty source files
+
+if env['builtin_bullet']:
+ # Build only version 2 for now (as of 2.87)
+ thirdparty_dir = "#thirdparty/bullet/"
+
+ bullet2_src = [
# BulletCollision
"BulletCollision/BroadphaseCollision/btAxisSweep3.cpp"
, "BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp"
@@ -179,17 +182,10 @@ bullet_src__2_x = [
, "LinearMath/btVector3.cpp"
]
-thirdparty_dir = "#thirdparty/bullet/"
-thirdparty_src = thirdparty_dir + "src/"
+ thirdparty_sources = [thirdparty_dir + file for file in bullet2_src]
-bullet_sources = [thirdparty_src + file for file in bullet_src__2_x]
-
-# include headers
-env_bullet.Append(CPPPATH=[thirdparty_src])
-
-env_bullet.add_source_files(env.modules_sources, bullet_sources)
+ env_bullet.add_source_files(env.modules_sources, thirdparty_sources)
+ env_bullet.Append(CPPPATH=[thirdparty_dir])
# Godot source files
env_bullet.add_source_files(env.modules_sources, "*.cpp")
-
-Export('env')
diff --git a/modules/bullet/SCsub_with_lib b/modules/bullet/SCsub_with_lib
deleted file mode 100644
index b362a686ff..0000000000
--- a/modules/bullet/SCsub_with_lib
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env python
-
-Import('env')
-
-thirdparty_dir = "#thirdparty/bullet/"
-thirdparty_lib = thirdparty_dir + "Win64/lib/"
-
-bullet_libs = [
- "Bullet2FileLoader",
- "Bullet3Collision",
- "Bullet3Common",
- "Bullet3Dynamics",
- "Bullet3Geometry",
- "Bullet3OpenCL_clew",
- "BulletCollision",
- "BulletDynamics",
- "BulletInverseDynamics",
- "BulletSoftBody",
- "LinearMath"
- ]
-
-thirdparty_src = thirdparty_dir + "src/"
-# include headers
-env.Append(CPPPATH=[thirdparty_src])
-
-# lib
-env.Append(LIBPATH=[thirdparty_dir + "/Win64/lib/"])
-
-bullet_libs = [file+'.lib' for file in bullet_libs]
-# LIBS doesn't work in windows
-env.Append(LINKFLAGS=bullet_libs)
-
-env.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp
index 9d46e4fe30..648919e612 100644
--- a/modules/bullet/area_bullet.cpp
+++ b/modules/bullet/area_bullet.cpp
@@ -236,7 +236,7 @@ void AreaBullet::set_param(PhysicsServer::AreaParameter p_param, const Variant &
set_spOv_gravityPointAttenuation(p_value);
break;
default:
- print_line("The Bullet areas dosn't suppot this param: " + itos(p_param));
+ print_line("The Bullet areas doesn't suppot this param: " + itos(p_param));
}
}
@@ -259,7 +259,7 @@ Variant AreaBullet::get_param(PhysicsServer::AreaParameter p_param) const {
case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
return spOv_gravityPointAttenuation;
default:
- print_line("The Bullet areas dosn't suppot this param: " + itos(p_param));
+ print_line("The Bullet areas doesn't suppot this param: " + itos(p_param));
return Variant();
}
}
diff --git a/modules/bullet/btRayShape.cpp b/modules/bullet/btRayShape.cpp
index 4164450cd2..8707096038 100644
--- a/modules/bullet/btRayShape.cpp
+++ b/modules/bullet/btRayShape.cpp
@@ -54,6 +54,11 @@ void btRayShape::setLength(btScalar p_length) {
reload_cache();
}
+void btRayShape::setSlipsOnSlope(bool p_slipsOnSlope) {
+
+ slipsOnSlope = p_slipsOnSlope;
+}
+
btVector3 btRayShape::localGetSupportingVertex(const btVector3 &vec) const {
return localGetSupportingVertexWithoutMargin(vec) + (m_shapeAxis * m_collisionMargin);
}
diff --git a/modules/bullet/btRayShape.h b/modules/bullet/btRayShape.h
index 99a9412dbe..a44c30db4b 100644
--- a/modules/bullet/btRayShape.h
+++ b/modules/bullet/btRayShape.h
@@ -44,6 +44,7 @@ ATTRIBUTE_ALIGNED16(class)
btRayShape : public btConvexInternalShape {
btScalar m_length;
+ bool slipsOnSlope;
/// The default axis is the z
btVector3 m_shapeAxis;
@@ -59,6 +60,9 @@ public:
void setLength(btScalar p_length);
btScalar getLength() const { return m_length; }
+ void setSlipsOnSlope(bool p_slipOnSlope);
+ bool getSlipsOnSlope() const { return slipsOnSlope; }
+
const btTransform &getSupportPoint() const { return m_cacheSupportPoint; }
const btScalar &getScaledLength() const { return m_cacheScaledLength; }
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index 51de4998fa..61ce26e9fd 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -70,8 +70,8 @@
return RID(); \
}
-#define AddJointToSpace(body, joint, disableCollisionsBetweenLinkedBodies) \
- body->get_space()->add_constraint(joint, disableCollisionsBetweenLinkedBodies);
+#define AddJointToSpace(body, joint) \
+ body->get_space()->add_constraint(joint, joint->is_disabled_collisions_between_bodies());
// <--------------- Joint creation asserts
btEmptyShape *BulletPhysicsServer::emptyShape(ShapeBullet::create_shape_empty());
@@ -783,7 +783,7 @@ int BulletPhysicsServer::body_get_max_contacts_reported(RID p_body) const {
return body->get_max_collisions_detection();
}
-void BulletPhysicsServer::body_set_contacts_reported_depth_threshold(RID p_body, float p_treshold) {
+void BulletPhysicsServer::body_set_contacts_reported_depth_threshold(RID p_body, float p_threshold) {
WARN_PRINT("Not supported by bullet and even Godot");
}
@@ -825,12 +825,12 @@ PhysicsDirectBodyState *BulletPhysicsServer::body_get_direct_state(RID p_body) {
return BulletPhysicsDirectBodyState::get_singleton(body);
}
-bool BulletPhysicsServer::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, MotionResult *r_result) {
+bool BulletPhysicsServer::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result) {
RigidBodyBullet *body = rigid_body_owner.get(p_body);
ERR_FAIL_COND_V(!body, false);
ERR_FAIL_COND_V(!body->get_space(), false);
- return body->get_space()->test_body_motion(body, p_from, p_motion, r_result);
+ return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result);
}
RID BulletPhysicsServer::soft_body_create(bool p_init_sleeping) {
@@ -987,6 +987,20 @@ int BulletPhysicsServer::joint_get_solver_priority(RID p_joint) const {
return 0;
}
+void BulletPhysicsServer::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+
+ joint->disable_collisions_between_bodies(p_disable);
+}
+
+bool BulletPhysicsServer::joint_is_disabled_collisions_between_bodies(RID p_joint) const {
+ JointBullet *joint(joint_owner.get(p_joint));
+ ERR_FAIL_COND_V(!joint, false);
+
+ return joint->is_disabled_collisions_between_bodies();
+}
+
RID BulletPhysicsServer::joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) {
RigidBodyBullet *body_A = rigid_body_owner.get(p_body_A);
ERR_FAIL_COND_V(!body_A, RID());
@@ -1003,7 +1017,7 @@ RID BulletPhysicsServer::joint_create_pin(RID p_body_A, const Vector3 &p_local_A
ERR_FAIL_COND_V(body_A == body_B, RID());
JointBullet *joint = bulletnew(PinJointBullet(body_A, p_local_A, body_B, p_local_B));
- AddJointToSpace(body_A, joint, true);
+ AddJointToSpace(body_A, joint);
CreateThenReturnRID(joint_owner, joint);
}
@@ -1071,7 +1085,7 @@ RID BulletPhysicsServer::joint_create_hinge(RID p_body_A, const Transform &p_hin
ERR_FAIL_COND_V(body_A == body_B, RID());
JointBullet *joint = bulletnew(HingeJointBullet(body_A, body_B, p_hinge_A, p_hinge_B));
- AddJointToSpace(body_A, joint, true);
+ AddJointToSpace(body_A, joint);
CreateThenReturnRID(joint_owner, joint);
}
@@ -1091,7 +1105,7 @@ RID BulletPhysicsServer::joint_create_hinge_simple(RID p_body_A, const Vector3 &
ERR_FAIL_COND_V(body_A == body_B, RID());
JointBullet *joint = bulletnew(HingeJointBullet(body_A, body_B, p_pivot_A, p_pivot_B, p_axis_A, p_axis_B));
- AddJointToSpace(body_A, joint, true);
+ AddJointToSpace(body_A, joint);
CreateThenReturnRID(joint_owner, joint);
}
@@ -1143,7 +1157,7 @@ RID BulletPhysicsServer::joint_create_slider(RID p_body_A, const Transform &p_lo
ERR_FAIL_COND_V(body_A == body_B, RID());
JointBullet *joint = bulletnew(SliderJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B));
- AddJointToSpace(body_A, joint, true);
+ AddJointToSpace(body_A, joint);
CreateThenReturnRID(joint_owner, joint);
}
@@ -1177,7 +1191,7 @@ RID BulletPhysicsServer::joint_create_cone_twist(RID p_body_A, const Transform &
}
JointBullet *joint = bulletnew(ConeTwistJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B));
- AddJointToSpace(body_A, joint, true);
+ AddJointToSpace(body_A, joint);
CreateThenReturnRID(joint_owner, joint);
}
@@ -1213,7 +1227,7 @@ RID BulletPhysicsServer::joint_create_generic_6dof(RID p_body_A, const Transform
ERR_FAIL_COND_V(body_A == body_B, RID());
JointBullet *joint = bulletnew(Generic6DOFJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B, true));
- AddJointToSpace(body_A, joint, true);
+ AddJointToSpace(body_A, joint);
CreateThenReturnRID(joint_owner, joint);
}
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index 1c94428a2a..e931915bba 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -154,7 +154,7 @@ public:
/// AREA_PARAM_GRAVITY_VECTOR
/// Otherwise you can set area parameters
virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value);
- virtual Variant area_get_param(RID p_parea, AreaParameter p_param) const;
+ virtual Variant area_get_param(RID p_area, AreaParameter p_param) const;
virtual void area_set_transform(RID p_area, const Transform &p_transform);
virtual Transform area_get_transform(RID p_area) const;
@@ -239,7 +239,7 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts);
virtual int body_get_max_contacts_reported(RID p_body) const;
- virtual void body_set_contacts_reported_depth_threshold(RID p_body, float p_treshold);
+ virtual void body_set_contacts_reported_depth_threshold(RID p_body, float p_threshold);
virtual float body_get_contacts_reported_depth_threshold(RID p_body) const;
virtual void body_set_omit_force_integration(RID p_body, bool p_omit);
@@ -253,7 +253,7 @@ public:
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState *body_get_direct_state(RID p_body);
- virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, MotionResult *r_result = NULL);
+ virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = NULL);
/* SOFT BODY API */
@@ -290,6 +290,9 @@ public:
virtual void joint_set_solver_priority(RID p_joint, int p_priority);
virtual int joint_get_solver_priority(RID p_joint) const;
+ virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable);
+ virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const;
+
virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B);
virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, float p_value);
@@ -301,7 +304,7 @@ public:
virtual void pin_joint_set_local_b(RID p_joint, const Vector3 &p_B);
virtual Vector3 pin_joint_get_local_b(RID p_joint) const;
- virtual RID joint_create_hinge(RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B);
+ virtual RID joint_create_hinge(RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B);
virtual RID joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B);
virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, float p_value);
diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp
index 873c9c31b7..34aff68a4a 100644
--- a/modules/bullet/collision_object_bullet.cpp
+++ b/modules/bullet/collision_object_bullet.cpp
@@ -160,16 +160,13 @@ int CollisionObjectBullet::get_godot_object_flags() const {
void CollisionObjectBullet::set_transform(const Transform &p_global_transform) {
- btTransform btTrans;
- Basis decomposed_basis;
+ set_body_scale(p_global_transform.basis.get_scale());
- Vector3 decomposed_scale = p_global_transform.get_basis().rotref_posscale_decomposition(decomposed_basis);
+ btTransform bt_transform;
+ G_TO_B(p_global_transform, bt_transform);
+ UNSCALE_BT_BASIS(bt_transform);
- G_TO_B(p_global_transform.get_origin(), btTrans.getOrigin());
- G_TO_B(decomposed_basis, btTrans.getBasis());
-
- set_body_scale(decomposed_scale);
- set_transform__bullet(btTrans);
+ set_transform__bullet(bt_transform);
}
Transform CollisionObjectBullet::get_transform() const {
@@ -317,20 +314,22 @@ void RigidCollisionObjectBullet::on_shapes_changed() {
}
// Insert all shapes
-
+ btVector3 body_scale(get_bt_body_scale());
for (i = 0; i < shapes_size; ++i) {
shpWrapper = &shapes[i];
if (shpWrapper->active) {
if (!shpWrapper->bt_shape) {
- shpWrapper->bt_shape = shpWrapper->shape->create_bt_shape(shpWrapper->scale);
+ shpWrapper->bt_shape = shpWrapper->shape->create_bt_shape(shpWrapper->scale * body_scale);
}
- compoundShape->addChildShape(shpWrapper->transform, shpWrapper->bt_shape);
+
+ btTransform scaled_shape_transform(shpWrapper->transform);
+ scaled_shape_transform.getOrigin() *= body_scale;
+ compoundShape->addChildShape(scaled_shape_transform, shpWrapper->bt_shape);
} else {
- compoundShape->addChildShape(shpWrapper->transform, BulletPhysicsServer::get_empty_shape());
+ compoundShape->addChildShape(btTransform(), BulletPhysicsServer::get_empty_shape());
}
}
- compoundShape->setLocalScaling(get_bt_body_scale());
compoundShape->recalculateLocalAabb();
}
diff --git a/modules/bullet/constraint_bullet.cpp b/modules/bullet/constraint_bullet.cpp
index b60e89b6fd..d15fb8de01 100644
--- a/modules/bullet/constraint_bullet.cpp
+++ b/modules/bullet/constraint_bullet.cpp
@@ -39,7 +39,8 @@
ConstraintBullet::ConstraintBullet() :
space(NULL),
- constraint(NULL) {}
+ constraint(NULL),
+ disabled_collisions_between_bodies(true) {}
void ConstraintBullet::setup(btTypedConstraint *p_constraint) {
constraint = p_constraint;
@@ -53,3 +54,12 @@ void ConstraintBullet::set_space(SpaceBullet *p_space) {
void ConstraintBullet::destroy_internal_constraint() {
space->remove_constraint(this);
}
+
+void ConstraintBullet::disable_collisions_between_bodies(const bool p_disabled) {
+ disabled_collisions_between_bodies = p_disabled;
+
+ if (space) {
+ space->remove_constraint(this);
+ space->add_constraint(this, disabled_collisions_between_bodies);
+ }
+}
diff --git a/modules/bullet/constraint_bullet.h b/modules/bullet/constraint_bullet.h
index 23be5a5063..ed3a318cbc 100644
--- a/modules/bullet/constraint_bullet.h
+++ b/modules/bullet/constraint_bullet.h
@@ -49,6 +49,7 @@ class ConstraintBullet : public RIDBullet {
protected:
SpaceBullet *space;
btTypedConstraint *constraint;
+ bool disabled_collisions_between_bodies;
public:
ConstraintBullet();
@@ -57,6 +58,9 @@ public:
virtual void set_space(SpaceBullet *p_space);
virtual void destroy_internal_constraint();
+ void disable_collisions_between_bodies(const bool p_disabled);
+ _FORCE_INLINE_ bool is_disabled_collisions_between_bodies() const { return disabled_collisions_between_bodies; }
+
public:
virtual ~ConstraintBullet() {
bulletdelete(constraint);
diff --git a/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml b/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml
index 941a79e8ea..8c8647e097 100644
--- a/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml
+++ b/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BulletPhysicsDirectBodyState" inherits="PhysicsDirectBodyState" category="Core" version="3.0-beta">
+<class name="BulletPhysicsDirectBodyState" inherits="PhysicsDirectBodyState" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/bullet/doc_classes/BulletPhysicsServer.xml b/modules/bullet/doc_classes/BulletPhysicsServer.xml
index 515f0e292e..8ed84e1dec 100644
--- a/modules/bullet/doc_classes/BulletPhysicsServer.xml
+++ b/modules/bullet/doc_classes/BulletPhysicsServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BulletPhysicsServer" inherits="PhysicsServer" category="Core" version="3.0-beta">
+<class name="BulletPhysicsServer" inherits="PhysicsServer" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/bullet/godot_motion_state.h b/modules/bullet/godot_motion_state.h
index 2ebe368536..fa58e86589 100644
--- a/modules/bullet/godot_motion_state.h
+++ b/modules/bullet/godot_motion_state.h
@@ -41,7 +41,7 @@
class RigidBodyBullet;
-// This clas is responsible to move kinematic actor
+// This class is responsible to move kinematic actor
// and sincronize rendering engine with Bullet
/// DOC:
/// http://www.bulletphysics.org/mediawiki-1.5.8/index.php/MotionStates#What.27s_a_MotionState.3F
@@ -87,7 +87,7 @@ public:
public:
/// Use this function to move kinematic body
- /// -- or set initial transfom before body creation.
+ /// -- or set initial transform before body creation.
void moveBody(const btTransform &newWorldTransform) {
bodyKinematicWorldTransf = newWorldTransform;
}
diff --git a/modules/bullet/godot_ray_world_algorithm.cpp b/modules/bullet/godot_ray_world_algorithm.cpp
index 709eed9e40..53d0ab7e3c 100644
--- a/modules/bullet/godot_ray_world_algorithm.cpp
+++ b/modules/bullet/godot_ray_world_algorithm.cpp
@@ -35,6 +35,8 @@
#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
+#define RAY_STABILITY_MARGIN 0.1
+
/**
@author AndreaCatania
*/
@@ -97,10 +99,17 @@ void GodotRayWorldAlgorithm::processCollision(const btCollisionObjectWrapper *bo
m_world->rayTestSingleInternal(ray_transform, to, other_co_wrapper, btResult);
if (btResult.hasHit()) {
- btVector3 ray_normal(to.getOrigin() - ray_transform.getOrigin());
- ray_normal.normalize();
- ray_normal *= -1;
- resultOut->addContactPoint(ray_normal, btResult.m_hitPointWorld, ray_shape->getScaledLength() * (btResult.m_closestHitFraction - 1));
+
+ btScalar depth(ray_shape->getScaledLength() * (btResult.m_closestHitFraction - 1));
+
+ if (depth >= -RAY_STABILITY_MARGIN)
+ depth = 0;
+
+ if (ray_shape->getSlipsOnSlope())
+ resultOut->addContactPoint(btResult.m_hitNormalWorld, btResult.m_hitPointWorld, depth);
+ else {
+ resultOut->addContactPoint((ray_transform.getOrigin() - to.getOrigin()).normalize(), btResult.m_hitPointWorld, depth);
+ }
}
}
diff --git a/modules/bullet/godot_ray_world_algorithm.h b/modules/bullet/godot_ray_world_algorithm.h
index c716c1d88d..7383dad2bf 100644
--- a/modules/bullet/godot_ray_world_algorithm.h
+++ b/modules/bullet/godot_ray_world_algorithm.h
@@ -49,7 +49,7 @@ class GodotRayWorldAlgorithm : public btActivatingCollisionAlgorithm {
bool m_isSwapped;
public:
- GodotRayWorldAlgorithm(const btDiscreteDynamicsWorld *m_world, btPersistentManifold *mf, const btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, bool isSwapped);
+ GodotRayWorldAlgorithm(const btDiscreteDynamicsWorld *world, btPersistentManifold *mf, const btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, bool isSwapped);
virtual ~GodotRayWorldAlgorithm();
virtual void processCollision(const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut);
diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp
index 8d4ca6d6a7..7c051f8f17 100644
--- a/modules/bullet/godot_result_callbacks.cpp
+++ b/modules/bullet/godot_result_callbacks.cpp
@@ -98,11 +98,16 @@ bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *prox
if (gObj == m_self_object) {
return false;
} else {
- if (m_ignore_areas && gObj->getType() == CollisionObjectBullet::TYPE_AREA) {
+
+ // A kinematic body can't be stopped by a rigid body since the mass of kinematic body is infinite
+ if (m_infinite_inertia && !btObj->isStaticOrKinematicObject())
+ return false;
+
+ if (gObj->getType() == CollisionObjectBullet::TYPE_AREA)
return false;
- } else if (m_self_object->has_collision_exception(gObj)) {
+
+ if (m_self_object->has_collision_exception(gObj))
return false;
- }
}
return true;
} else {
diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h
index b18965a5b8..ed6d4b7d6d 100644
--- a/modules/bullet/godot_result_callbacks.h
+++ b/modules/bullet/godot_result_callbacks.h
@@ -93,12 +93,12 @@ public:
struct GodotKinClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback {
public:
const RigidBodyBullet *m_self_object;
- const bool m_ignore_areas;
+ const bool m_infinite_inertia;
- GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_ignore_areas) :
+ GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_infinite_inertia) :
btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld),
m_self_object(p_self_object),
- m_ignore_areas(p_ignore_areas) {}
+ m_infinite_inertia(p_infinite_inertia) {}
virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
};
@@ -205,6 +205,6 @@ struct GodotDeepPenetrationContactResultCallback : public btManifoldResult {
return m_pointCollisionObject;
}
- virtual void addContactPoint(const btVector3 &normalOnBInWorld, const btVector3 &pointInWorld, btScalar depth);
+ virtual void addContactPoint(const btVector3 &normalOnBInWorld, const btVector3 &pointInWorldOnB, btScalar depth);
};
#endif // GODOT_RESULT_CALLBACKS_H
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index f2115a5d50..75b4cc054a 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -114,10 +114,18 @@ Transform BulletPhysicsDirectBodyState::get_transform() const {
return body->get_transform();
}
+void BulletPhysicsDirectBodyState::add_central_force(const Vector3 &p_force) {
+ body->apply_central_force(p_force);
+}
+
void BulletPhysicsDirectBodyState::add_force(const Vector3 &p_force, const Vector3 &p_pos) {
body->apply_force(p_force, p_pos);
}
+void BulletPhysicsDirectBodyState::add_torque(const Vector3 &p_torque) {
+ body->apply_torque(p_torque);
+}
+
void BulletPhysicsDirectBodyState::apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) {
body->apply_impulse(p_pos, p_j);
}
@@ -690,7 +698,7 @@ void RigidBodyBullet::set_continuous_collision_detection(bool p_enable) {
/// Calculate using the rule writte below the CCD swept sphere radius
/// CCD works on an embedded sphere of radius, make sure this radius
/// is embedded inside the convex objects, preferably smaller:
- /// for an object of dimentions 1 meter, try 0.2
+ /// for an object of dimensions 1 meter, try 0.2
btVector3 center;
btScalar radius;
btBody->getCollisionShape()->getBoundingSphere(center, radius);
@@ -832,7 +840,8 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) {
void RigidBodyBullet::reload_space_override_modificator() {
- if (!is_active())
+ // Make sure that kinematic bodies have their total gravity calculated
+ if (!is_active() && PhysicsServer::BODY_MODE_KINEMATIC != mode)
return;
Vector3 newGravity(space->get_gravity_direction() * space->get_gravity_magnitude());
@@ -955,7 +964,8 @@ void RigidBodyBullet::_internal_set_mass(real_t p_mass) {
const bool isDynamic = p_mass != 0.f;
if (isDynamic) {
- ERR_FAIL_COND(PhysicsServer::BODY_MODE_RIGID != mode && PhysicsServer::BODY_MODE_CHARACTER != mode);
+ if (PhysicsServer::BODY_MODE_RIGID != mode && PhysicsServer::BODY_MODE_CHARACTER != mode)
+ return;
m_isStatic = false;
compoundShape->calculateLocalInertia(p_mass, localInertia);
@@ -975,7 +985,8 @@ void RigidBodyBullet::_internal_set_mass(real_t p_mass) {
}
} else {
- ERR_FAIL_COND(PhysicsServer::BODY_MODE_STATIC != mode && PhysicsServer::BODY_MODE_KINEMATIC != mode);
+ if (PhysicsServer::BODY_MODE_STATIC != mode && PhysicsServer::BODY_MODE_KINEMATIC != mode)
+ return;
m_isStatic = true;
if (PhysicsServer::BODY_MODE_STATIC == mode) {
diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h
index eb9417e391..2d529f6dc7 100644
--- a/modules/bullet/rigid_body_bullet.h
+++ b/modules/bullet/rigid_body_bullet.h
@@ -48,11 +48,11 @@ class GodotMotionState;
class BulletPhysicsDirectBodyState;
/// This class could be used in multi thread with few changes but currently
-/// is setted to be only in one single thread.
+/// is set to be only in one single thread.
///
/// In the system there is only one object at a time that manage all bodies and is
/// created by BulletPhysicsServer and is held by the "singleton" variable of this class
-/// Each time something require it, the body must be setted again.
+/// Each time something require it, the body must be set again.
class BulletPhysicsDirectBodyState : public PhysicsDirectBodyState {
GDCLASS(BulletPhysicsDirectBodyState, PhysicsDirectBodyState)
@@ -110,7 +110,9 @@ public:
virtual void set_transform(const Transform &p_transform);
virtual Transform get_transform() const;
+ virtual void add_central_force(const Vector3 &p_force);
virtual void add_force(const Vector3 &p_force, const Vector3 &p_pos);
+ virtual void add_torque(const Vector3 &p_torque);
virtual void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j);
virtual void apply_torque_impulse(const Vector3 &p_j);
@@ -262,12 +264,12 @@ public:
Variant get_state(PhysicsServer::BodyState p_state) const;
void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse);
- void apply_central_impulse(const Vector3 &p_force);
+ void apply_central_impulse(const Vector3 &p_impulse);
void apply_torque_impulse(const Vector3 &p_impulse);
void apply_force(const Vector3 &p_force, const Vector3 &p_pos);
void apply_central_force(const Vector3 &p_force);
- void apply_torque(const Vector3 &p_force);
+ void apply_torque(const Vector3 &p_torque);
void set_applied_force(const Vector3 &p_force);
Vector3 get_applied_force() const;
diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp
index 27eac4e6ee..5d8d391bd9 100644
--- a/modules/bullet/shape_bullet.cpp
+++ b/modules/bullet/shape_bullet.cpp
@@ -135,8 +135,10 @@ btHeightfieldTerrainShape *ShapeBullet::create_shape_height_field(PoolVector<rea
return bulletnew(btHeightfieldTerrainShape(p_width, p_depth, heightsPtr, ignoredHeightScale, -fieldHeight, fieldHeight, YAxis, PHY_FLOAT, flipQuadEdges));
}
-btRayShape *ShapeBullet::create_shape_ray(real_t p_length) {
- return bulletnew(btRayShape(p_length));
+btRayShape *ShapeBullet::create_shape_ray(real_t p_length, bool p_slips_on_slope) {
+ btRayShape *r(bulletnew(btRayShape(p_length)));
+ r->setSlipsOnSlope(p_slips_on_slope);
+ return r;
}
/* PLANE */
@@ -282,7 +284,7 @@ PhysicsServer::ShapeType ConvexPolygonShapeBullet::get_type() const {
}
void ConvexPolygonShapeBullet::setup(const Vector<Vector3> &p_vertices) {
- // Make a copy of verticies
+ // Make a copy of vertices
const int n_of_vertices = p_vertices.size();
vertices.resize(n_of_vertices);
for (int i = n_of_vertices - 1; 0 <= i; --i) {
@@ -435,25 +437,33 @@ btCollisionShape *HeightMapShapeBullet::create_bt_shape(const btVector3 &p_impli
/* Ray shape */
RayShapeBullet::RayShapeBullet() :
ShapeBullet(),
- length(1) {}
+ length(1),
+ slips_on_slope(false) {}
void RayShapeBullet::set_data(const Variant &p_data) {
- setup(p_data);
+
+ Dictionary d = p_data;
+ setup(d["length"], d["slips_on_slope"]);
}
Variant RayShapeBullet::get_data() const {
- return length;
+
+ Dictionary d;
+ d["length"] = length;
+ d["slips_on_slope"] = slips_on_slope;
+ return d;
}
PhysicsServer::ShapeType RayShapeBullet::get_type() const {
return PhysicsServer::SHAPE_RAY;
}
-void RayShapeBullet::setup(real_t p_length) {
+void RayShapeBullet::setup(real_t p_length, bool p_slips_on_slope) {
length = p_length;
+ slips_on_slope = p_slips_on_slope;
notifyShapeChanged();
}
btCollisionShape *RayShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) {
- return prepare(ShapeBullet::create_shape_ray(length * p_implicit_scale[1] + p_margin));
+ return prepare(ShapeBullet::create_shape_ray(length * p_implicit_scale[1] + p_margin, slips_on_slope));
}
diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h
index 4a03c0f014..2acba90e36 100644
--- a/modules/bullet/shape_bullet.h
+++ b/modules/bullet/shape_bullet.h
@@ -86,7 +86,7 @@ public:
static class btConvexPointCloudShape *create_shape_convex(btAlignedObjectArray<btVector3> &p_vertices, const btVector3 &p_local_scaling = btVector3(1, 1, 1));
static class btScaledBvhTriangleMeshShape *create_shape_concave(btBvhTriangleMeshShape *p_mesh_shape, const btVector3 &p_local_scaling = btVector3(1, 1, 1));
static class btHeightfieldTerrainShape *create_shape_height_field(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size);
- static class btRayShape *create_shape_ray(real_t p_length);
+ static class btRayShape *create_shape_ray(real_t p_length, bool p_slips_on_slope);
};
class PlaneShapeBullet : public ShapeBullet {
@@ -99,7 +99,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_scale, real_t p_margin = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
private:
void setup(const Plane &p_plane);
@@ -116,7 +116,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_scale, real_t p_margin = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
private:
void setup(real_t p_radius);
@@ -133,7 +133,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_scale, real_t p_margin = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
private:
void setup(const Vector3 &p_half_extents);
@@ -152,7 +152,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_scale, real_t p_margin = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
private:
void setup(real_t p_height, real_t p_radius);
@@ -169,7 +169,7 @@ public:
void get_vertices(Vector<Vector3> &out_vertices);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_scale, real_t p_margin = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
private:
void setup(const Vector<Vector3> &p_vertices);
@@ -187,7 +187,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_scale, real_t p_margin = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
private:
void setup(PoolVector<Vector3> p_faces);
@@ -206,7 +206,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_scale, real_t p_margin = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
private:
void setup(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size);
@@ -216,15 +216,16 @@ class RayShapeBullet : public ShapeBullet {
public:
real_t length;
+ bool slips_on_slope;
RayShapeBullet();
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_scale, real_t p_margin = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
private:
- void setup(real_t p_length);
+ void setup(real_t p_length, bool p_slips_on_slope);
};
#endif
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index d60d8ba0e2..e20a79f667 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -116,7 +116,7 @@ bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const V
}
}
-int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *p_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask) {
+int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask) {
if (p_result_max <= 0)
return 0;
@@ -138,7 +138,7 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra
collision_object.setCollisionShape(btConvex);
collision_object.setWorldTransform(bt_xform);
- GodotAllContactResultCallback btQuery(&collision_object, p_results, p_result_max, &p_exclude);
+ GodotAllContactResultCallback btQuery(&collision_object, r_results, p_result_max, &p_exclude);
btQuery.m_collisionFilterGroup = 0;
btQuery.m_collisionFilterMask = p_collision_mask;
btQuery.m_closestDistanceThreshold = 0;
@@ -628,7 +628,7 @@ void SpaceBullet::destroy_world() {
void SpaceBullet::check_ghost_overlaps() {
- /// Algorith support variables
+ /// Algorithm support variables
btConvexShape *other_body_shape;
btConvexShape *area_shape;
btGjkPairDetector::ClosestPointInput gjk_input;
@@ -804,8 +804,7 @@ static Ref<SpatialMaterial> red_mat;
static Ref<SpatialMaterial> blue_mat;
#endif
-#define IGNORE_AREAS_TRUE true
-bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, PhysicsServer::MotionResult *r_result) {
+bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result) {
#if debug_test_motion
/// Yes I know this is not good, but I've used it as fast debugging hack.
@@ -839,16 +838,6 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f
}
#endif
- ///// Release all generated manifolds
- //{
- // if(p_body->get_kinematic_utilities()){
- // for(int i= p_body->get_kinematic_utilities()->m_generatedManifold.size()-1; 0<=i; --i){
- // dispatcher->releaseManifold( p_body->get_kinematic_utilities()->m_generatedManifold[i] );
- // }
- // p_body->get_kinematic_utilities()->m_generatedManifold.clear();
- // }
- //}
-
btTransform body_safe_position;
G_TO_B(p_from, body_safe_position);
UNSCALE_BT_BASIS(body_safe_position);
@@ -857,7 +846,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f
btVector3 recover_initial_position(0, 0, 0);
{ /// Phase one - multi shapes depenetration using margin
for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) {
- if (!recover_from_penetration(p_body, body_safe_position, RECOVERING_MOVEMENT_SCALE, recover_initial_position)) {
+ if (!recover_from_penetration(p_body, body_safe_position, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, recover_initial_position)) {
break;
}
}
@@ -900,7 +889,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f
btTransform shape_world_to(shape_world_from);
shape_world_to.getOrigin() += motion;
- GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, IGNORE_AREAS_TRUE);
+ GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, p_infinite_inertia);
btResult.m_collisionFilterGroup = p_body->get_collision_layer();
btResult.m_collisionFilterMask = p_body->get_collision_mask();
@@ -926,7 +915,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f
real_t l_penetration_distance = 1e20;
for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) {
- l_has_penetration = recover_from_penetration(p_body, body_safe_position, RECOVERING_MOVEMENT_SCALE, delta_recover_movement, &r_recover_result);
+ l_has_penetration = recover_from_penetration(p_body, body_safe_position, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, delta_recover_movement, &r_recover_result);
if (r_result) {
#if PERFORM_INITIAL_UNSTACK
@@ -955,15 +944,6 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f
r_result->collider_shape = r_recover_result.other_compound_shape_index;
r_result->collision_local_shape = r_recover_result.local_shape_most_recovered;
- //{ /// Add manifold point to manage collisions
- // btPersistentManifold* manifold = dynamicsWorld->getDispatcher()->getNewManifold(p_body->getBtBody(), btRigid);
- // btManifoldPoint manifoldPoint(result_callabck.m_pointWorld, result_callabck.m_pointWorld, result_callabck.m_pointNormalWorld, result_callabck.m_penetration_distance);
- // manifoldPoint.m_index0 = r_result->collision_local_shape;
- // manifoldPoint.m_index1 = r_result->collider_shape;
- // manifold->addManifoldPoint(manifoldPoint);
- // p_body->get_kinematic_utilities()->m_generatedManifold.push_back(manifold);
- //}
-
#if debug_test_motion
Vector3 sup_line2;
B_TO_G(motion, sup_line2);
@@ -979,6 +959,8 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f
} else {
if (!l_has_penetration)
break;
+ else
+ has_penetration = true;
}
}
}
@@ -1020,7 +1002,7 @@ public:
}
};
-bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) {
+bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) {
RecoverPenetrationBroadPhaseCallback recover_broad_result(p_body->get_bt_collision_object(), p_body->get_collision_layer(), p_body->get_collision_mask());
@@ -1051,7 +1033,7 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran
for (int i = recover_broad_result.result_collision_objects.size() - 1; 0 <= i; --i) {
btCollisionObject *otherObject = recover_broad_result.result_collision_objects[i];
- if (!p_body->get_bt_collision_object()->checkCollideWith(otherObject) || !otherObject->checkCollideWith(p_body->get_bt_collision_object()))
+ if (!p_body->get_bt_collision_object()->checkCollideWith(otherObject) || !otherObject->checkCollideWith(p_body->get_bt_collision_object()) || (p_infinite_inertia && !otherObject->isStaticOrKinematicObject()))
continue;
if (otherObject->getCollisionShape()->isCompound()) {
diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h
index 0aeb407dcc..a6c2786878 100644
--- a/modules/bullet/space_bullet.h
+++ b/modules/bullet/space_bullet.h
@@ -172,7 +172,7 @@ public:
void update_gravity();
- bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, PhysicsServer::MotionResult *r_result);
+ bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result);
private:
void create_empty_world(bool p_create_soft_world);
@@ -199,12 +199,12 @@ private:
local_shape_most_recovered(0) {}
};
- bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_from, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL);
+ bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL);
/// This is an API that recover a kinematic object from penetration
/// This allow only Convex Convex test and it always use GJK algorithm, With this API we don't benefit of Bullet special accelerated functions
- bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL);
+ bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL);
/// This is an API that recover a kinematic object from penetration
/// Using this we leave Bullet to select the best algorithm, For example GJK in case we have Convex Convex, or a Bullet accelerated algorithm
- bool RFP_convex_world_test(const btConvexShape *p_shapeA, const btCollisionShape *p_shapeB, btCollisionObject *p_objectA, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL);
+ bool RFP_convex_world_test(const btConvexShape *p_shapeA, const btCollisionShape *p_shapeB, btCollisionObject *p_objectA, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL);
};
#endif
diff --git a/modules/enet/SCsub b/modules/enet/SCsub
index 4790c5099f..7caeafa1d6 100644
--- a/modules/enet/SCsub
+++ b/modules/enet/SCsub
@@ -3,10 +3,10 @@
Import('env')
Import('env_modules')
-# Thirdparty source files
-
env_enet = env_modules.Clone()
+# Thirdparty source files
+
if env['builtin_enet']:
thirdparty_dir = "#thirdparty/enet/"
thirdparty_sources = [
diff --git a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
index 00162d6e60..55a7a1ac77 100644
--- a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
+++ b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NetworkedMultiplayerENet" inherits="NetworkedMultiplayerPeer" category="Core" version="3.0-beta">
+<class name="NetworkedMultiplayerENet" inherits="NetworkedMultiplayerPeer" category="Core" version="3.1-dev">
<brief_description>
PacketPeer implementation using the ENet library.
</brief_description>
diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub
index f69b632e76..a34a650a4d 100644
--- a/modules/freetype/SCsub
+++ b/modules/freetype/SCsub
@@ -87,6 +87,6 @@ if env['builtin_freetype']:
# Godot source files
env.add_source_files(env.modules_sources, "*.cpp")
-env.Append(CCFLAGS=['-DFREETYPE_ENABLED'])
+env.Append(CCFLAGS=['-DFREETYPE_ENABLED', '-DFT_CONFIG_OPTION_USE_PNG'])
Export('env')
diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub
index c92c3f30a2..acfb83bc10 100644
--- a/modules/gdnative/SCsub
+++ b/modules/gdnative/SCsub
@@ -28,7 +28,7 @@ def _build_gdnative_api_struct_header(api):
'\textern const godot_gdnative_ext_{0}_api_struct *_gdnative_wrapper_{0}_api_struct;'.format(name))
gdnative_api_init_macro.append('\t_gdnative_wrapper_api_struct = options->api_struct;')
- gdnative_api_init_macro.append('\tfor (int i = 0; i < _gdnative_wrapper_api_struct->num_extensions; i++) { ')
+ gdnative_api_init_macro.append('\tfor (unsigned int i = 0; i < _gdnative_wrapper_api_struct->num_extensions; i++) { ')
gdnative_api_init_macro.append('\t\tswitch (_gdnative_wrapper_api_struct->extensions[i]->type) {')
for name in api['extensions']:
@@ -66,19 +66,30 @@ def _build_gdnative_api_struct_header(api):
out += ['};', '']
- for name in api['extensions']:
- out += [
- 'typedef struct godot_gdnative_ext_' + name + '_api_struct {',
+
+ def generate_extension_struct(name, ext, include_version=True):
+ ret_val = []
+ if ext['next']:
+ ret_val += generate_extension_struct(name, ext['next'])
+
+ ret_val += [
+ 'typedef struct godot_gdnative_ext_' + name + ('' if not include_version else ('_{0}_{1}'.format(ext['version']['major'], ext['version']['minor']))) + '_api_struct {',
'\tunsigned int type;',
'\tgodot_gdnative_api_version version;',
'\tconst godot_gdnative_api_struct *next;'
]
- for funcdef in api['extensions'][name]['api']:
+ for funcdef in ext['api']:
args = ', '.join(['%s%s' % (_spaced(t), n) for t, n in funcdef['arguments']])
- out.append('\t%s(*%s)(%s);' % (_spaced(funcdef['return_type']), funcdef['name'], args))
+ ret_val.append('\t%s(*%s)(%s);' % (_spaced(funcdef['return_type']), funcdef['name'], args))
+
+ ret_val += ['} godot_gdnative_ext_' + name + ('' if not include_version else ('_{0}_{1}'.format(ext['version']['major'], ext['version']['minor']))) + '_api_struct;', '']
+
+ return ret_val
- out += ['} godot_gdnative_ext_' + name + '_api_struct;', '']
+
+ for name in api['extensions']:
+ out += generate_extension_struct(name, api['extensions'][name], False)
out += [
'typedef struct godot_gdnative_core_api_struct {',
@@ -113,18 +124,35 @@ def _build_gdnative_api_struct_source(api):
''
]
- for name in api['extensions']:
- out += [
- 'extern const godot_gdnative_ext_' + name + '_api_struct api_extension_' + name + '_struct = {',
- '\tGDNATIVE_EXT_' + api['extensions'][name]['type'] + ',',
- '\t{' + str(api['extensions'][name]['version']['major']) + ', ' + str(api['extensions'][name]['version']['minor']) + '},',
- '\tNULL,'
+ def get_extension_struct_name(name, ext, include_version=True):
+ return 'godot_gdnative_ext_' + name + ('' if not include_version else ('_{0}_{1}'.format(ext['version']['major'], ext['version']['minor']))) + '_api_struct'
+
+ def get_extension_struct_instance_name(name, ext, include_version=True):
+ return 'api_extension_' + name + ('' if not include_version else ('_{0}_{1}'.format(ext['version']['major'], ext['version']['minor']))) + '_struct'
+
+ def get_extension_struct_definition(name, ext, include_version=True):
+
+ ret_val = []
+
+ if ext['next']:
+ ret_val += get_extension_struct_definition(name, ext['next'])
+
+ ret_val += [
+ 'extern const ' + get_extension_struct_name(name, ext, include_version) + ' ' + get_extension_struct_instance_name(name, ext, include_version) + ' = {',
+ '\tGDNATIVE_EXT_' + ext['type'] + ',',
+ '\t{' + str(ext['version']['major']) + ', ' + str(ext['version']['minor']) + '},',
+ '\t' + ('NULL' if not ext['next'] else ('(const godot_gdnative_api_struct *)&' + get_extension_struct_instance_name(name, ext['next']))) + ','
]
- for funcdef in api['extensions'][name]['api']:
- out.append('\t%s,' % funcdef['name'])
+ for funcdef in ext['api']:
+ ret_val.append('\t%s,' % funcdef['name'])
+
+ ret_val += ['};\n']
- out += ['};\n']
+ return ret_val
+
+ for name in api['extensions']:
+ out += get_extension_struct_definition(name, api['extensions'][name], False)
out += ['', 'const godot_gdnative_api_struct *gdnative_extensions_pointers[] = {']
diff --git a/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml b/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml
index e4ffa76d36..998460eee1 100644
--- a/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml
+++ b/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ARVRInterfaceGDNative" inherits="ARVRInterface" category="Core" version="3.0-beta">
+<class name="ARVRInterfaceGDNative" inherits="ARVRInterface" category="Core" version="3.1-dev">
<brief_description>
GDNative wrapper for an ARVR interface
</brief_description>
diff --git a/modules/gdnative/doc_classes/GDNative.xml b/modules/gdnative/doc_classes/GDNative.xml
index 83953cef49..4e87cbf450 100644
--- a/modules/gdnative/doc_classes/GDNative.xml
+++ b/modules/gdnative/doc_classes/GDNative.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GDNative" inherits="Reference" category="Core" version="3.0-beta">
+<class name="GDNative" inherits="Reference" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gdnative/doc_classes/GDNativeLibrary.xml b/modules/gdnative/doc_classes/GDNativeLibrary.xml
index 14bd0e9654..ca1bae0598 100644
--- a/modules/gdnative/doc_classes/GDNativeLibrary.xml
+++ b/modules/gdnative/doc_classes/GDNativeLibrary.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GDNativeLibrary" inherits="Resource" category="Core" version="3.0-beta">
+<class name="GDNativeLibrary" inherits="Resource" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gdnative/doc_classes/NativeScript.xml b/modules/gdnative/doc_classes/NativeScript.xml
index 3f6025d02f..6a71cd8d4d 100644
--- a/modules/gdnative/doc_classes/NativeScript.xml
+++ b/modules/gdnative/doc_classes/NativeScript.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NativeScript" inherits="Script" category="Core" version="3.0-beta">
+<class name="NativeScript" inherits="Script" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
@@ -9,10 +9,46 @@
<demos>
</demos>
<methods>
+ <method name="get_class_documentation" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ Returns the documentation string that was previously set with [code]godot_nativescript_set_class_documentation[/code].
+ </description>
+ </method>
+ <method name="get_method_documentation" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="method" type="String">
+ </argument>
+ <description>
+ Returns the documentation string that was previously set with [code]godot_nativescript_set_method_documentation[/code].
+ </description>
+ </method>
+ <method name="get_property_documentation" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="path" type="String">
+ </argument>
+ <description>
+ Returns the documentation string that was previously set with [code]godot_nativescript_set_property_documentation[/code].
+ </description>
+ </method>
+ <method name="get_signal_documentation" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="signal_name" type="String">
+ </argument>
+ <description>
+ Returns the documentation string that was previously set with [code]godot_nativescript_set_signal_documentation[/code].
+ </description>
+ </method>
<method name="new" qualifiers="vararg">
<return type="Object">
</return>
<description>
+ Constructs a new object of the base type with a script of this type already attached.
+ [i]Note[/i]: Any arguments passed to this function will be ignored and not passed to the native constructor function. This will change with in a future API extension.
</description>
</method>
</methods>
diff --git a/modules/gdnative/doc_classes/PluginScript.xml b/modules/gdnative/doc_classes/PluginScript.xml
index 1a2141247a..3783d9d0a4 100644
--- a/modules/gdnative/doc_classes/PluginScript.xml
+++ b/modules/gdnative/doc_classes/PluginScript.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PluginScript" inherits="Script" category="Core" version="3.0-beta">
+<class name="PluginScript" inherits="Script" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp
index 1379083b42..42c3028f2c 100644
--- a/modules/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative.cpp
@@ -181,13 +181,23 @@ bool GDNative::initialize() {
godot_gdnative_init_fn library_init_fpointer;
library_init_fpointer = (godot_gdnative_init_fn)library_init;
+ static uint64_t core_api_hash = 0;
+ static uint64_t editor_api_hash = 0;
+ static uint64_t no_api_hash = 0;
+
+ if (!(core_api_hash || editor_api_hash || no_api_hash)) {
+ core_api_hash = ClassDB::get_api_hash(ClassDB::API_CORE);
+ editor_api_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR);
+ no_api_hash = ClassDB::get_api_hash(ClassDB::API_NONE);
+ }
+
godot_gdnative_init_options options;
options.api_struct = &api_struct;
options.in_editor = Engine::get_singleton()->is_editor_hint();
- options.core_api_hash = ClassDB::get_api_hash(ClassDB::API_CORE);
- options.editor_api_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR);
- options.no_api_hash = ClassDB::get_api_hash(ClassDB::API_NONE);
+ options.core_api_hash = core_api_hash;
+ options.editor_api_hash = editor_api_hash;
+ options.no_api_hash = no_api_hash;
options.report_version_mismatch = &_gdnative_report_version_mismatch;
options.report_loading_error = &_gdnative_report_loading_error;
options.gd_native_library = (godot_object *)(get_library().ptr());
diff --git a/modules/gdnative/gdnative/pool_arrays.cpp b/modules/gdnative/gdnative/pool_arrays.cpp
index 6e014905a3..6688be1a0d 100644
--- a/modules/gdnative/gdnative/pool_arrays.cpp
+++ b/modules/gdnative/gdnative/pool_arrays.cpp
@@ -700,6 +700,10 @@ void GDAPI godot_pool_color_array_destroy(godot_pool_color_array *p_self) {
// read accessor functions
//
+godot_pool_byte_array_read_access GDAPI *godot_pool_byte_array_read_access_copy(const godot_pool_byte_array_read_access *p_other) {
+ PoolVector<uint8_t>::Read *other = (PoolVector<uint8_t>::Read *)p_other;
+ return (godot_pool_byte_array_read_access *)memnew(PoolVector<uint8_t>::Read(*other));
+}
const uint8_t GDAPI *godot_pool_byte_array_read_access_ptr(const godot_pool_byte_array_read_access *p_read) {
const PoolVector<uint8_t>::Read *read = (const PoolVector<uint8_t>::Read *)p_read;
return read->ptr();
@@ -713,6 +717,10 @@ void GDAPI godot_pool_byte_array_read_access_destroy(godot_pool_byte_array_read_
memdelete((PoolVector<uint8_t>::Read *)p_read);
}
+godot_pool_int_array_read_access GDAPI *godot_pool_int_array_read_access_copy(const godot_pool_int_array_read_access *p_other) {
+ PoolVector<godot_int>::Read *other = (PoolVector<godot_int>::Read *)p_other;
+ return (godot_pool_int_array_read_access *)memnew(PoolVector<godot_int>::Read(*other));
+}
const godot_int GDAPI *godot_pool_int_array_read_access_ptr(const godot_pool_int_array_read_access *p_read) {
const PoolVector<godot_int>::Read *read = (const PoolVector<godot_int>::Read *)p_read;
return read->ptr();
@@ -726,6 +734,10 @@ void GDAPI godot_pool_int_array_read_access_destroy(godot_pool_int_array_read_ac
memdelete((PoolVector<godot_int>::Read *)p_read);
}
+godot_pool_real_array_read_access GDAPI *godot_pool_real_array_read_access_copy(const godot_pool_real_array_read_access *p_other) {
+ PoolVector<godot_real>::Read *other = (PoolVector<godot_real>::Read *)p_other;
+ return (godot_pool_real_array_read_access *)memnew(PoolVector<godot_real>::Read(*other));
+}
const godot_real GDAPI *godot_pool_real_array_read_access_ptr(const godot_pool_real_array_read_access *p_read) {
const PoolVector<godot_real>::Read *read = (const PoolVector<godot_real>::Read *)p_read;
return read->ptr();
@@ -739,6 +751,10 @@ void GDAPI godot_pool_real_array_read_access_destroy(godot_pool_real_array_read_
memdelete((PoolVector<godot_real>::Read *)p_read);
}
+godot_pool_string_array_read_access GDAPI *godot_pool_string_array_read_access_copy(const godot_pool_string_array_read_access *p_other) {
+ PoolVector<String>::Read *other = (PoolVector<String>::Read *)p_other;
+ return (godot_pool_string_array_read_access *)memnew(PoolVector<String>::Read(*other));
+}
const godot_string GDAPI *godot_pool_string_array_read_access_ptr(const godot_pool_string_array_read_access *p_read) {
const PoolVector<String>::Read *read = (const PoolVector<String>::Read *)p_read;
return (const godot_string *)read->ptr();
@@ -752,6 +768,10 @@ void GDAPI godot_pool_string_array_read_access_destroy(godot_pool_string_array_r
memdelete((PoolVector<String>::Read *)p_read);
}
+godot_pool_vector2_array_read_access GDAPI *godot_pool_vector2_array_read_access_copy(const godot_pool_vector2_array_read_access *p_other) {
+ PoolVector<Vector2>::Read *other = (PoolVector<Vector2>::Read *)p_other;
+ return (godot_pool_vector2_array_read_access *)memnew(PoolVector<Vector2>::Read(*other));
+}
const godot_vector2 GDAPI *godot_pool_vector2_array_read_access_ptr(const godot_pool_vector2_array_read_access *p_read) {
const PoolVector<Vector2>::Read *read = (const PoolVector<Vector2>::Read *)p_read;
return (const godot_vector2 *)read->ptr();
@@ -765,6 +785,10 @@ void GDAPI godot_pool_vector2_array_read_access_destroy(godot_pool_vector2_array
memdelete((PoolVector<Vector2>::Read *)p_read);
}
+godot_pool_vector3_array_read_access GDAPI *godot_pool_vector3_array_read_access_copy(const godot_pool_vector3_array_read_access *p_other) {
+ PoolVector<Vector3>::Read *other = (PoolVector<Vector3>::Read *)p_other;
+ return (godot_pool_vector3_array_read_access *)memnew(PoolVector<Vector3>::Read(*other));
+}
const godot_vector3 GDAPI *godot_pool_vector3_array_read_access_ptr(const godot_pool_vector3_array_read_access *p_read) {
const PoolVector<Vector3>::Read *read = (const PoolVector<Vector3>::Read *)p_read;
return (const godot_vector3 *)read->ptr();
@@ -778,6 +802,10 @@ void GDAPI godot_pool_vector3_array_read_access_destroy(godot_pool_vector3_array
memdelete((PoolVector<Vector2>::Read *)p_read);
}
+godot_pool_color_array_read_access GDAPI *godot_pool_color_array_read_access_copy(const godot_pool_color_array_read_access *p_other) {
+ PoolVector<Color>::Read *other = (PoolVector<Color>::Read *)p_other;
+ return (godot_pool_color_array_read_access *)memnew(PoolVector<Color>::Read(*other));
+}
const godot_color GDAPI *godot_pool_color_array_read_access_ptr(const godot_pool_color_array_read_access *p_read) {
const PoolVector<Color>::Read *read = (const PoolVector<Color>::Read *)p_read;
return (const godot_color *)read->ptr();
@@ -795,6 +823,10 @@ void GDAPI godot_pool_color_array_read_access_destroy(godot_pool_color_array_rea
// write accessor functions
//
+godot_pool_byte_array_write_access GDAPI *godot_pool_byte_array_write_access_copy(const godot_pool_byte_array_write_access *p_other) {
+ PoolVector<uint8_t>::Write *other = (PoolVector<uint8_t>::Write *)p_other;
+ return (godot_pool_byte_array_write_access *)memnew(PoolVector<uint8_t>::Write(*other));
+}
uint8_t GDAPI *godot_pool_byte_array_write_access_ptr(const godot_pool_byte_array_write_access *p_write) {
PoolVector<uint8_t>::Write *write = (PoolVector<uint8_t>::Write *)p_write;
return write->ptr();
@@ -808,6 +840,10 @@ void GDAPI godot_pool_byte_array_write_access_destroy(godot_pool_byte_array_writ
memdelete((PoolVector<uint8_t>::Write *)p_write);
}
+godot_pool_int_array_write_access GDAPI *godot_pool_int_array_write_access_copy(const godot_pool_int_array_write_access *p_other) {
+ PoolVector<godot_int>::Write *other = (PoolVector<godot_int>::Write *)p_other;
+ return (godot_pool_int_array_write_access *)memnew(PoolVector<godot_int>::Write(*other));
+}
godot_int GDAPI *godot_pool_int_array_write_access_ptr(const godot_pool_int_array_write_access *p_write) {
PoolVector<godot_int>::Write *write = (PoolVector<godot_int>::Write *)p_write;
return write->ptr();
@@ -821,6 +857,10 @@ void GDAPI godot_pool_int_array_write_access_destroy(godot_pool_int_array_write_
memdelete((PoolVector<godot_int>::Write *)p_write);
}
+godot_pool_real_array_write_access GDAPI *godot_pool_real_array_write_access_copy(const godot_pool_real_array_write_access *p_other) {
+ PoolVector<godot_real>::Write *other = (PoolVector<godot_real>::Write *)p_other;
+ return (godot_pool_real_array_write_access *)memnew(PoolVector<godot_real>::Write(*other));
+}
godot_real GDAPI *godot_pool_real_array_write_access_ptr(const godot_pool_real_array_write_access *p_write) {
PoolVector<godot_real>::Write *write = (PoolVector<godot_real>::Write *)p_write;
return write->ptr();
@@ -834,6 +874,10 @@ void GDAPI godot_pool_real_array_write_access_destroy(godot_pool_real_array_writ
memdelete((PoolVector<godot_real>::Write *)p_write);
}
+godot_pool_string_array_write_access GDAPI *godot_pool_string_array_write_access_copy(const godot_pool_string_array_write_access *p_other) {
+ PoolVector<String>::Write *other = (PoolVector<String>::Write *)p_other;
+ return (godot_pool_string_array_write_access *)memnew(PoolVector<String>::Write(*other));
+}
godot_string GDAPI *godot_pool_string_array_write_access_ptr(const godot_pool_string_array_write_access *p_write) {
PoolVector<String>::Write *write = (PoolVector<String>::Write *)p_write;
return (godot_string *)write->ptr();
@@ -847,6 +891,10 @@ void GDAPI godot_pool_string_array_write_access_destroy(godot_pool_string_array_
memdelete((PoolVector<String>::Write *)p_write);
}
+godot_pool_vector2_array_write_access GDAPI *godot_pool_vector2_array_write_access_copy(const godot_pool_vector2_array_write_access *p_other) {
+ PoolVector<Vector2>::Write *other = (PoolVector<Vector2>::Write *)p_other;
+ return (godot_pool_vector2_array_write_access *)memnew(PoolVector<Vector2>::Write(*other));
+}
godot_vector2 GDAPI *godot_pool_vector2_array_write_access_ptr(const godot_pool_vector2_array_write_access *p_write) {
PoolVector<Vector2>::Write *write = (PoolVector<Vector2>::Write *)p_write;
return (godot_vector2 *)write->ptr();
@@ -860,6 +908,10 @@ void GDAPI godot_pool_vector2_array_write_access_destroy(godot_pool_vector2_arra
memdelete((PoolVector<Vector2>::Write *)p_write);
}
+godot_pool_vector3_array_write_access GDAPI *godot_pool_vector3_array_write_access_copy(const godot_pool_vector3_array_write_access *p_other) {
+ PoolVector<Vector3>::Write *other = (PoolVector<Vector3>::Write *)p_other;
+ return (godot_pool_vector3_array_write_access *)memnew(PoolVector<Vector3>::Write(*other));
+}
godot_vector3 GDAPI *godot_pool_vector3_array_write_access_ptr(const godot_pool_vector3_array_write_access *p_write) {
PoolVector<Vector3>::Write *write = (PoolVector<Vector3>::Write *)p_write;
return (godot_vector3 *)write->ptr();
@@ -873,6 +925,10 @@ void GDAPI godot_pool_vector3_array_write_access_destroy(godot_pool_vector3_arra
memdelete((PoolVector<Vector3>::Write *)p_write);
}
+godot_pool_color_array_write_access GDAPI *godot_pool_color_array_write_access_copy(const godot_pool_color_array_write_access *p_other) {
+ PoolVector<Color>::Write *other = (PoolVector<Color>::Write *)p_other;
+ return (godot_pool_color_array_write_access *)memnew(PoolVector<Color>::Write(*other));
+}
godot_color GDAPI *godot_pool_color_array_write_access_ptr(const godot_pool_color_array_write_access *p_write) {
PoolVector<Color>::Write *write = (PoolVector<Color>::Write *)p_write;
return (godot_color *)write->ptr();
diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json
index 6e3cf16758..a8919f7130 100644
--- a/modules/gdnative/gdnative_api.json
+++ b/modules/gdnative/gdnative_api.json
@@ -5,6 +5,7 @@
"major": 1,
"minor": 0
},
+ "next": null,
"api": [
{
"name": "godot_color_new_rgba",
@@ -2090,6 +2091,13 @@
]
},
{
+ "name": "godot_pool_byte_array_read_access_copy",
+ "return_type": "godot_pool_byte_array_read_access *",
+ "arguments": [
+ ["const godot_pool_byte_array_read_access *", "p_read"]
+ ]
+ },
+ {
"name": "godot_pool_byte_array_read_access_ptr",
"return_type": "const uint8_t *",
"arguments": [
@@ -2112,6 +2120,13 @@
]
},
{
+ "name": "godot_pool_int_array_read_access_copy",
+ "return_type": "godot_pool_int_array_read_access *",
+ "arguments": [
+ ["const godot_pool_int_array_read_access *", "p_read"]
+ ]
+ },
+ {
"name": "godot_pool_int_array_read_access_ptr",
"return_type": "const godot_int *",
"arguments": [
@@ -2134,6 +2149,13 @@
]
},
{
+ "name": "godot_pool_real_array_read_access_copy",
+ "return_type": "godot_pool_real_array_read_access *",
+ "arguments": [
+ ["const godot_pool_real_array_read_access *", "p_read"]
+ ]
+ },
+ {
"name": "godot_pool_real_array_read_access_ptr",
"return_type": "const godot_real *",
"arguments": [
@@ -2156,6 +2178,13 @@
]
},
{
+ "name": "godot_pool_string_array_read_access_copy",
+ "return_type": "godot_pool_string_array_read_access *",
+ "arguments": [
+ ["const godot_pool_string_array_read_access *", "p_read"]
+ ]
+ },
+ {
"name": "godot_pool_string_array_read_access_ptr",
"return_type": "const godot_string *",
"arguments": [
@@ -2178,6 +2207,13 @@
]
},
{
+ "name": "godot_pool_vector2_array_read_access_copy",
+ "return_type": "godot_pool_vector2_array_read_access *",
+ "arguments": [
+ ["const godot_pool_vector2_array_read_access *", "p_read"]
+ ]
+ },
+ {
"name": "godot_pool_vector2_array_read_access_ptr",
"return_type": "const godot_vector2 *",
"arguments": [
@@ -2200,6 +2236,13 @@
]
},
{
+ "name": "godot_pool_vector3_array_read_access_copy",
+ "return_type": "godot_pool_vector3_array_read_access *",
+ "arguments": [
+ ["const godot_pool_vector3_array_read_access *", "p_read"]
+ ]
+ },
+ {
"name": "godot_pool_vector3_array_read_access_ptr",
"return_type": "const godot_vector3 *",
"arguments": [
@@ -2222,6 +2265,13 @@
]
},
{
+ "name": "godot_pool_color_array_read_access_copy",
+ "return_type": "godot_pool_color_array_read_access *",
+ "arguments": [
+ ["const godot_pool_color_array_read_access *", "p_read"]
+ ]
+ },
+ {
"name": "godot_pool_color_array_read_access_ptr",
"return_type": "const godot_color *",
"arguments": [
@@ -2244,6 +2294,13 @@
]
},
{
+ "name": "godot_pool_byte_array_write_access_copy",
+ "return_type": "godot_pool_byte_array_write_access *",
+ "arguments": [
+ ["const godot_pool_byte_array_write_access *", "p_write"]
+ ]
+ },
+ {
"name": "godot_pool_byte_array_write_access_ptr",
"return_type": "uint8_t *",
"arguments": [
@@ -2266,6 +2323,13 @@
]
},
{
+ "name": "godot_pool_int_array_write_access_copy",
+ "return_type": "godot_pool_int_array_write_access *",
+ "arguments": [
+ ["const godot_pool_int_array_write_access *", "p_write"]
+ ]
+ },
+ {
"name": "godot_pool_int_array_write_access_ptr",
"return_type": "godot_int *",
"arguments": [
@@ -2288,6 +2352,13 @@
]
},
{
+ "name": "godot_pool_real_array_write_access_copy",
+ "return_type": "godot_pool_real_array_write_access *",
+ "arguments": [
+ ["const godot_pool_real_array_write_access *", "p_write"]
+ ]
+ },
+ {
"name": "godot_pool_real_array_write_access_ptr",
"return_type": "godot_real *",
"arguments": [
@@ -2310,6 +2381,13 @@
]
},
{
+ "name": "godot_pool_string_array_write_access_copy",
+ "return_type": "godot_pool_string_array_write_access *",
+ "arguments": [
+ ["const godot_pool_string_array_write_access *", "p_write"]
+ ]
+ },
+ {
"name": "godot_pool_string_array_write_access_ptr",
"return_type": "godot_string *",
"arguments": [
@@ -2332,6 +2410,13 @@
]
},
{
+ "name": "godot_pool_vector2_array_write_access_copy",
+ "return_type": "godot_pool_vector2_array_write_access *",
+ "arguments": [
+ ["const godot_pool_vector2_array_write_access *", "p_write"]
+ ]
+ },
+ {
"name": "godot_pool_vector2_array_write_access_ptr",
"return_type": "godot_vector2 *",
"arguments": [
@@ -2354,6 +2439,13 @@
]
},
{
+ "name": "godot_pool_vector3_array_write_access_copy",
+ "return_type": "godot_pool_vector3_array_write_access *",
+ "arguments": [
+ ["const godot_pool_vector3_array_write_access *", "p_write"]
+ ]
+ },
+ {
"name": "godot_pool_vector3_array_write_access_ptr",
"return_type": "godot_vector3 *",
"arguments": [
@@ -2376,6 +2468,13 @@
]
},
{
+ "name": "godot_pool_color_array_write_access_copy",
+ "return_type": "godot_pool_color_array_write_access *",
+ "arguments": [
+ ["const godot_pool_color_array_write_access *", "p_write"]
+ ]
+ },
+ {
"name": "godot_pool_color_array_write_access_ptr",
"return_type": "godot_color *",
"arguments": [
@@ -3865,7 +3964,7 @@
"name": "godot_variant_new_bool",
"return_type": "void",
"arguments": [
- ["godot_variant *", "p_v"],
+ ["godot_variant *", "r_dest"],
["const godot_bool", "p_b"]
]
},
@@ -5664,6 +5763,104 @@
"major": 1,
"minor": 0
},
+ "next": {
+ "type": "NATIVESCRIPT",
+ "version": {
+ "major": 1,
+ "minor": 1
+ },
+ "next": null,
+ "api": [
+ {
+ "name": "godot_nativescript_set_method_argument_information",
+ "return_type": "void",
+ "arguments": [
+ ["void *", "p_gdnative_handle"],
+ ["const char *", "p_name"],
+ ["const char *", "p_function_name"],
+ ["int", "p_num_args"],
+ ["const godot_method_arg *", "p_args"]
+ ]
+ },
+ {
+ "name": "godot_nativescript_set_class_documentation",
+ "return_type": "void",
+ "arguments": [
+ ["void *", "p_gdnative_handle"],
+ ["const char *", "p_name"],
+ ["godot_string", "p_documentation"]
+ ]
+ },
+ {
+ "name": "godot_nativescript_set_method_documentation",
+ "return_type": "void",
+ "arguments": [
+ ["void *", "p_gdnative_handle"],
+ ["const char *", "p_name"],
+ ["const char *", "p_function_name"],
+ ["godot_string", "p_documentation"]
+ ]
+ },
+ {
+ "name": "godot_nativescript_set_property_documentation",
+ "return_type": "void",
+ "arguments": [
+ ["void *", "p_gdnative_handle"],
+ ["const char *", "p_name"],
+ ["const char *", "p_path"],
+ ["godot_string", "p_documentation"]
+ ]
+ },
+ {
+ "name": "godot_nativescript_set_signal_documentation",
+ "return_type": "void",
+ "arguments": [
+ ["void *", "p_gdnative_handle"],
+ ["const char *", "p_name"],
+ ["const char *", "p_signal_name"],
+ ["godot_string", "p_documentation"]
+ ]
+ },
+ {
+ "name": "godot_nativescript_set_type_tag",
+ "return_type": "void",
+ "arguments": [
+ ["void *", "p_gdnative_handle"],
+ ["const char *", "p_name"],
+ ["const void *", "p_type_tag"]
+ ]
+ },
+ {
+ "name": "godot_nativescript_get_type_tag",
+ "return_type": "const void *",
+ "arguments": [
+ ["const godot_object *", "p_object"]
+ ]
+ },
+ {
+ "name": "godot_nativescript_register_instance_binding_data_functions",
+ "return_type": "int",
+ "arguments": [
+ ["godot_instance_binding_functions", "p_binding_functions"]
+ ]
+ },
+ {
+ "name": "godot_nativescript_unregister_instance_binding_data_functions",
+ "return_type": "void",
+ "arguments": [
+ ["int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_nativescript_get_instance_binding_data",
+ "return_type": "void *",
+ "arguments": [
+ ["int", "p_idx"],
+ ["godot_object *", "p_object"]
+ ]
+ }
+ ]
+ },
"api": [
{
"name": "godot_nativescript_register_class",
@@ -5734,6 +5931,7 @@
"major": 1,
"minor": 0
},
+ "next": null,
"api": [
{
"name": "godot_pluginscript_register_language",
@@ -5750,6 +5948,7 @@
"major": 1,
"minor": 0
},
+ "next": null,
"api": [
{
"name": "godot_arvr_register_interface",
diff --git a/modules/gdnative/gdnative_library_editor_plugin.h b/modules/gdnative/gdnative_library_editor_plugin.h
index 94bc2adc7d..04d2911d8b 100644
--- a/modules/gdnative/gdnative_library_editor_plugin.h
+++ b/modules/gdnative/gdnative_library_editor_plugin.h
@@ -79,7 +79,7 @@ protected:
void _on_library_selected(const String &file);
void _on_dependencies_selected(const PoolStringArray &files);
void _on_filter_selected(int id);
- void _on_item_collapsed(Object *item);
+ void _on_item_collapsed(Object *p_item);
void _on_item_activated();
void _on_create_new_entry();
void _set_target_value(const String &section, const String &target, Variant file);
diff --git a/modules/gdnative/include/gdnative/gdnative.h b/modules/gdnative/include/gdnative/gdnative.h
index 56d3779d34..4cf6e99b06 100644
--- a/modules/gdnative/include/gdnative/gdnative.h
+++ b/modules/gdnative/include/gdnative/gdnative.h
@@ -70,7 +70,7 @@ typedef enum {
GODOT_OK,
GODOT_FAILED, ///< Generic fail error
GODOT_ERR_UNAVAILABLE, ///< What is requested is unsupported/unavailable
- GODOT_ERR_UNCONFIGURED, ///< The object being used hasnt been properly set up yet
+ GODOT_ERR_UNCONFIGURED, ///< The object being used hasn't been properly set up yet
GODOT_ERR_UNAUTHORIZED, ///< Missing credentials for requested resource
GODOT_ERR_PARAMETER_RANGE_ERROR, ///< Parameter given out of range (5)
GODOT_ERR_OUT_OF_MEMORY, ///< Out of memory
diff --git a/modules/gdnative/include/gdnative/pool_arrays.h b/modules/gdnative/include/gdnative/pool_arrays.h
index 69a93725a8..1210039e34 100644
--- a/modules/gdnative/include/gdnative/pool_arrays.h
+++ b/modules/gdnative/include/gdnative/pool_arrays.h
@@ -383,30 +383,37 @@ void GDAPI godot_pool_color_array_destroy(godot_pool_color_array *p_self);
// read accessor functions
//
+godot_pool_byte_array_read_access GDAPI *godot_pool_byte_array_read_access_copy(const godot_pool_byte_array_read_access *p_other);
const uint8_t GDAPI *godot_pool_byte_array_read_access_ptr(const godot_pool_byte_array_read_access *p_read);
void GDAPI godot_pool_byte_array_read_access_operator_assign(godot_pool_byte_array_read_access *p_read, godot_pool_byte_array_read_access *p_other);
void GDAPI godot_pool_byte_array_read_access_destroy(godot_pool_byte_array_read_access *p_read);
+godot_pool_int_array_read_access GDAPI *godot_pool_int_array_read_access_copy(const godot_pool_int_array_read_access *p_other);
const godot_int GDAPI *godot_pool_int_array_read_access_ptr(const godot_pool_int_array_read_access *p_read);
void GDAPI godot_pool_int_array_read_access_operator_assign(godot_pool_int_array_read_access *p_read, godot_pool_int_array_read_access *p_other);
void GDAPI godot_pool_int_array_read_access_destroy(godot_pool_int_array_read_access *p_read);
+godot_pool_real_array_read_access GDAPI *godot_pool_real_array_read_access_copy(const godot_pool_real_array_read_access *p_other);
const godot_real GDAPI *godot_pool_real_array_read_access_ptr(const godot_pool_real_array_read_access *p_read);
void GDAPI godot_pool_real_array_read_access_operator_assign(godot_pool_real_array_read_access *p_read, godot_pool_real_array_read_access *p_other);
void GDAPI godot_pool_real_array_read_access_destroy(godot_pool_real_array_read_access *p_read);
+godot_pool_string_array_read_access GDAPI *godot_pool_string_array_read_access_copy(const godot_pool_string_array_read_access *p_other);
const godot_string GDAPI *godot_pool_string_array_read_access_ptr(const godot_pool_string_array_read_access *p_read);
void GDAPI godot_pool_string_array_read_access_operator_assign(godot_pool_string_array_read_access *p_read, godot_pool_string_array_read_access *p_other);
void GDAPI godot_pool_string_array_read_access_destroy(godot_pool_string_array_read_access *p_read);
+godot_pool_vector2_array_read_access GDAPI *godot_pool_vector2_array_read_access_copy(const godot_pool_vector2_array_read_access *p_other);
const godot_vector2 GDAPI *godot_pool_vector2_array_read_access_ptr(const godot_pool_vector2_array_read_access *p_read);
void GDAPI godot_pool_vector2_array_read_access_operator_assign(godot_pool_vector2_array_read_access *p_read, godot_pool_vector2_array_read_access *p_other);
void GDAPI godot_pool_vector2_array_read_access_destroy(godot_pool_vector2_array_read_access *p_read);
+godot_pool_vector3_array_read_access GDAPI *godot_pool_vector3_array_read_access_copy(const godot_pool_vector3_array_read_access *p_other);
const godot_vector3 GDAPI *godot_pool_vector3_array_read_access_ptr(const godot_pool_vector3_array_read_access *p_read);
void GDAPI godot_pool_vector3_array_read_access_operator_assign(godot_pool_vector3_array_read_access *p_read, godot_pool_vector3_array_read_access *p_other);
void GDAPI godot_pool_vector3_array_read_access_destroy(godot_pool_vector3_array_read_access *p_read);
+godot_pool_color_array_read_access GDAPI *godot_pool_color_array_read_access_copy(const godot_pool_color_array_read_access *p_other);
const godot_color GDAPI *godot_pool_color_array_read_access_ptr(const godot_pool_color_array_read_access *p_read);
void GDAPI godot_pool_color_array_read_access_operator_assign(godot_pool_color_array_read_access *p_read, godot_pool_color_array_read_access *p_other);
void GDAPI godot_pool_color_array_read_access_destroy(godot_pool_color_array_read_access *p_read);
@@ -415,30 +422,37 @@ void GDAPI godot_pool_color_array_read_access_destroy(godot_pool_color_array_rea
// write accessor functions
//
+godot_pool_byte_array_write_access GDAPI *godot_pool_byte_array_write_access_copy(const godot_pool_byte_array_write_access *p_other);
uint8_t GDAPI *godot_pool_byte_array_write_access_ptr(const godot_pool_byte_array_write_access *p_write);
void GDAPI godot_pool_byte_array_write_access_operator_assign(godot_pool_byte_array_write_access *p_write, godot_pool_byte_array_write_access *p_other);
void GDAPI godot_pool_byte_array_write_access_destroy(godot_pool_byte_array_write_access *p_write);
+godot_pool_int_array_write_access GDAPI *godot_pool_int_array_write_access_copy(const godot_pool_int_array_write_access *p_other);
godot_int GDAPI *godot_pool_int_array_write_access_ptr(const godot_pool_int_array_write_access *p_write);
void GDAPI godot_pool_int_array_write_access_operator_assign(godot_pool_int_array_write_access *p_write, godot_pool_int_array_write_access *p_other);
void GDAPI godot_pool_int_array_write_access_destroy(godot_pool_int_array_write_access *p_write);
+godot_pool_real_array_write_access GDAPI *godot_pool_real_array_write_access_copy(const godot_pool_real_array_write_access *p_other);
godot_real GDAPI *godot_pool_real_array_write_access_ptr(const godot_pool_real_array_write_access *p_write);
void GDAPI godot_pool_real_array_write_access_operator_assign(godot_pool_real_array_write_access *p_write, godot_pool_real_array_write_access *p_other);
void GDAPI godot_pool_real_array_write_access_destroy(godot_pool_real_array_write_access *p_write);
+godot_pool_string_array_write_access GDAPI *godot_pool_string_array_write_access_copy(const godot_pool_string_array_write_access *p_other);
godot_string GDAPI *godot_pool_string_array_write_access_ptr(const godot_pool_string_array_write_access *p_write);
void GDAPI godot_pool_string_array_write_access_operator_assign(godot_pool_string_array_write_access *p_write, godot_pool_string_array_write_access *p_other);
void GDAPI godot_pool_string_array_write_access_destroy(godot_pool_string_array_write_access *p_write);
+godot_pool_vector2_array_write_access GDAPI *godot_pool_vector2_array_write_access_copy(const godot_pool_vector2_array_write_access *p_other);
godot_vector2 GDAPI *godot_pool_vector2_array_write_access_ptr(const godot_pool_vector2_array_write_access *p_write);
void GDAPI godot_pool_vector2_array_write_access_operator_assign(godot_pool_vector2_array_write_access *p_write, godot_pool_vector2_array_write_access *p_other);
void GDAPI godot_pool_vector2_array_write_access_destroy(godot_pool_vector2_array_write_access *p_write);
+godot_pool_vector3_array_write_access GDAPI *godot_pool_vector3_array_write_access_copy(const godot_pool_vector3_array_write_access *p_other);
godot_vector3 GDAPI *godot_pool_vector3_array_write_access_ptr(const godot_pool_vector3_array_write_access *p_write);
void GDAPI godot_pool_vector3_array_write_access_operator_assign(godot_pool_vector3_array_write_access *p_write, godot_pool_vector3_array_write_access *p_other);
void GDAPI godot_pool_vector3_array_write_access_destroy(godot_pool_vector3_array_write_access *p_write);
+godot_pool_color_array_write_access GDAPI *godot_pool_color_array_write_access_copy(const godot_pool_color_array_write_access *p_other);
godot_color GDAPI *godot_pool_color_array_write_access_ptr(const godot_pool_color_array_write_access *p_write);
void GDAPI godot_pool_color_array_write_access_operator_assign(godot_pool_color_array_write_access *p_write, godot_pool_color_array_write_access *p_other);
void GDAPI godot_pool_color_array_write_access_destroy(godot_pool_color_array_write_access *p_write);
diff --git a/modules/gdnative/include/gdnative/variant.h b/modules/gdnative/include/gdnative/variant.h
index d2e8246bfb..6779dc4092 100644
--- a/modules/gdnative/include/gdnative/variant.h
+++ b/modules/gdnative/include/gdnative/variant.h
@@ -135,7 +135,7 @@ void GDAPI godot_variant_new_copy(godot_variant *r_dest, const godot_variant *p_
void GDAPI godot_variant_new_nil(godot_variant *r_dest);
-void GDAPI godot_variant_new_bool(godot_variant *p_v, const godot_bool p_b);
+void GDAPI godot_variant_new_bool(godot_variant *r_dest, const godot_bool p_b);
void GDAPI godot_variant_new_uint(godot_variant *r_dest, const uint64_t p_i);
void GDAPI godot_variant_new_int(godot_variant *r_dest, const int64_t p_i);
void GDAPI godot_variant_new_real(godot_variant *r_dest, const double p_r);
diff --git a/modules/gdnative/include/nativescript/godot_nativescript.h b/modules/gdnative/include/nativescript/godot_nativescript.h
index fdd2a65bb2..747328bc41 100644
--- a/modules/gdnative/include/nativescript/godot_nativescript.h
+++ b/modules/gdnative/include/nativescript/godot_nativescript.h
@@ -50,7 +50,7 @@ typedef enum {
GODOT_PROPERTY_HINT_RANGE, ///< hint_text = "min,max,step,slider; //slider is optional"
GODOT_PROPERTY_HINT_EXP_RANGE, ///< hint_text = "min,max,step", exponential edit
GODOT_PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
- GODOT_PROPERTY_HINT_EXP_EASING, /// exponential easing funciton (Math::ease)
+ GODOT_PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease)
GODOT_PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer)
GODOT_PROPERTY_HINT_SPRITE_FRAME,
GODOT_PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer)
@@ -185,6 +185,52 @@ void GDAPI godot_nativescript_register_signal(void *p_gdnative_handle, const cha
void GDAPI *godot_nativescript_get_userdata(godot_object *p_instance);
+/*
+ *
+ *
+ * NativeScript 1.1
+ *
+ *
+ */
+
+// method registering with argument names
+
+typedef struct {
+ godot_string name;
+
+ godot_variant_type type;
+ godot_property_hint hint;
+ godot_string hint_string;
+} godot_method_arg;
+
+void GDAPI godot_nativescript_set_method_argument_information(void *p_gdnative_handle, const char *p_name, const char *p_function_name, int p_num_args, const godot_method_arg *p_args);
+
+// documentation
+
+void GDAPI godot_nativescript_set_class_documentation(void *p_gdnative_handle, const char *p_name, godot_string p_documentation);
+void GDAPI godot_nativescript_set_method_documentation(void *p_gdnative_handle, const char *p_name, const char *p_function_name, godot_string p_documentation);
+void GDAPI godot_nativescript_set_property_documentation(void *p_gdnative_handle, const char *p_name, const char *p_path, godot_string p_documentation);
+void GDAPI godot_nativescript_set_signal_documentation(void *p_gdnative_handle, const char *p_name, const char *p_signal_name, godot_string p_documentation);
+
+// type tag API
+
+void GDAPI godot_nativescript_set_type_tag(void *p_gdnative_handle, const char *p_name, const void *p_type_tag);
+const void GDAPI *godot_nativescript_get_type_tag(const godot_object *p_object);
+
+// instance binding API
+
+typedef struct {
+ void *(*alloc_instance_binding_data)(void *, godot_object *);
+ void (*free_instance_binding_data)(void *, void *);
+ void *data;
+ void (*free_func)(void *);
+} godot_instance_binding_functions;
+
+int GDAPI godot_nativescript_register_instance_binding_data_functions(godot_instance_binding_functions p_binding_functions);
+void GDAPI godot_nativescript_unregister_instance_binding_data_functions(int p_idx);
+
+void GDAPI *godot_nativescript_get_instance_binding_data(int p_idx, godot_object *p_object);
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/pluginscript/godot_pluginscript.h b/modules/gdnative/include/pluginscript/godot_pluginscript.h
index 671be3bbb9..d1671c014e 100644
--- a/modules/gdnative/include/pluginscript/godot_pluginscript.h
+++ b/modules/gdnative/include/pluginscript/godot_pluginscript.h
@@ -64,7 +64,7 @@ typedef struct {
//this is used by script languages that keep a reference counter of their own
//you can make make Ref<> not die when it reaches zero, so deleting the reference
//depends entirely from the script.
- // Note: You can set thoses function pointer to NULL if not needed.
+ // Note: You can set those function pointer to NULL if not needed.
void (*refcount_incremented)(godot_pluginscript_instance_data *p_data);
bool (*refcount_decremented)(godot_pluginscript_instance_data *p_data); // return true if it can die
} godot_pluginscript_instance_desc;
diff --git a/modules/gdnative/nativescript/godot_nativescript.cpp b/modules/gdnative/nativescript/godot_nativescript.cpp
index b4f7e1555e..aea595d0f0 100644
--- a/modules/gdnative/nativescript/godot_nativescript.cpp
+++ b/modules/gdnative/nativescript/godot_nativescript.cpp
@@ -106,7 +106,7 @@ void GDAPI godot_nativescript_register_method(void *p_gdnative_handle, const cha
Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name);
if (!E) {
- ERR_EXPLAIN("Attempt to register method on non-existant class!");
+ ERR_EXPLAIN("Attempted to register method on non-existent class!");
ERR_FAIL();
}
@@ -125,7 +125,7 @@ void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const c
Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name);
if (!E) {
- ERR_EXPLAIN("Attempt to register method on non-existant class!");
+ ERR_EXPLAIN("Attempted to register method on non-existent class!");
ERR_FAIL();
}
@@ -150,7 +150,7 @@ void GDAPI godot_nativescript_register_signal(void *p_gdnative_handle, const cha
Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name);
if (!E) {
- ERR_EXPLAIN("Attempt to register method on non-existant class!");
+ ERR_EXPLAIN("Attempted to register method on non-existent class!");
ERR_FAIL();
}
@@ -201,6 +201,164 @@ void GDAPI *godot_nativescript_get_userdata(godot_object *p_instance) {
return NULL;
}
+/*
+ *
+ *
+ * NativeScript 1.1
+ *
+ *
+ */
+
+void GDAPI godot_nativescript_set_method_argument_information(void *p_gdnative_handle, const char *p_name, const char *p_function_name, int p_num_args, const godot_method_arg *p_args) {
+ String *s = (String *)p_gdnative_handle;
+
+ Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name);
+
+ if (!E) {
+ ERR_EXPLAIN("Attempted to add argument information for a method on a non-existent class!");
+ ERR_FAIL();
+ }
+
+ Map<StringName, NativeScriptDesc::Method>::Element *method = E->get().methods.find(p_function_name);
+ if (!method) {
+ ERR_EXPLAIN("Attempted to add argument information to non-existent method!");
+ ERR_FAIL();
+ }
+
+ MethodInfo *method_information = &method->get().info;
+
+ List<PropertyInfo> args;
+
+ for (int i = 0; i < p_num_args; i++) {
+ godot_method_arg arg = p_args[i];
+ String name = *(String *)&arg.name;
+ String hint_string = *(String *)&arg.hint_string;
+
+ Variant::Type type = (Variant::Type)arg.type;
+ PropertyHint hint = (PropertyHint)arg.hint;
+
+ args.push_back(PropertyInfo(type, p_name, hint, hint_string));
+ }
+
+ method_information->arguments = args;
+}
+
+void GDAPI godot_nativescript_set_class_documentation(void *p_gdnative_handle, const char *p_name, godot_string p_documentation) {
+ String *s = (String *)p_gdnative_handle;
+
+ Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name);
+
+ if (!E) {
+ ERR_EXPLAIN("Attempted to add documentation to a non-existent class!");
+ ERR_FAIL();
+ }
+
+ E->get().documentation = *(String *)&p_documentation;
+}
+
+void GDAPI godot_nativescript_set_method_documentation(void *p_gdnative_handle, const char *p_name, const char *p_function_name, godot_string p_documentation) {
+ String *s = (String *)p_gdnative_handle;
+
+ Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name);
+
+ if (!E) {
+ ERR_EXPLAIN("Attempted to add documentation to a method on a non-existent class!");
+ ERR_FAIL();
+ }
+
+ Map<StringName, NativeScriptDesc::Method>::Element *method = E->get().methods.find(p_function_name);
+ if (!method) {
+ ERR_EXPLAIN("Attempted to add documentatino to non-existent method!");
+ ERR_FAIL();
+ }
+
+ method->get().documentation = *(String *)&p_documentation;
+}
+
+void GDAPI godot_nativescript_set_property_documentation(void *p_gdnative_handle, const char *p_name, const char *p_path, godot_string p_documentation) {
+ String *s = (String *)p_gdnative_handle;
+
+ Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name);
+
+ if (!E) {
+ ERR_EXPLAIN("Attempted to add documentation to a property on a non-existent class!");
+ ERR_FAIL();
+ }
+
+ OrderedHashMap<StringName, NativeScriptDesc::Property>::Element property = E->get().properties.find(p_path);
+ if (!property) {
+ ERR_EXPLAIN("Attempted to add documentation to non-existent property!");
+ ERR_FAIL();
+ }
+
+ property.get().documentation = *(String *)&p_documentation;
+}
+
+void GDAPI godot_nativescript_set_signal_documentation(void *p_gdnative_handle, const char *p_name, const char *p_signal_name, godot_string p_documentation) {
+ String *s = (String *)p_gdnative_handle;
+
+ Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name);
+
+ if (!E) {
+ ERR_EXPLAIN("Attempted to add documentation to a signal on a non-existent class!");
+ ERR_FAIL();
+ }
+
+ Map<StringName, NativeScriptDesc::Signal>::Element *signal = E->get().signals_.find(p_signal_name);
+ if (!signal) {
+ ERR_EXPLAIN("Attempted to add documentation to non-existent signal!");
+ ERR_FAIL();
+ }
+
+ signal->get().documentation = *(String *)&p_documentation;
+}
+
+void GDAPI godot_nativescript_set_type_tag(void *p_gdnative_handle, const char *p_name, const void *p_type_tag) {
+ String *s = (String *)p_gdnative_handle;
+
+ Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name);
+
+ if (!E) {
+ ERR_EXPLAIN("Attempted to set type tag on a non-existent class!");
+ ERR_FAIL();
+ }
+
+ E->get().type_tag = p_type_tag;
+}
+
+const void GDAPI *godot_nativescript_get_type_tag(const godot_object *p_object) {
+
+ const Object *o = (Object *)p_object;
+
+ if (!o->get_script_instance()) {
+ ERR_EXPLAIN("Attempted to get type tag on an object without a script!");
+ ERR_FAIL_V(NULL);
+ } else {
+ NativeScript *script = Object::cast_to<NativeScript>(o->get_script_instance()->get_script().ptr());
+ if (!script) {
+ ERR_EXPLAIN("Attempted to get type tag on an object without a nativescript attached");
+ ERR_FAIL_V(NULL);
+ }
+
+ if (script->get_script_desc())
+ return script->get_script_desc()->type_tag;
+ }
+
+ return NULL;
+}
+
#ifdef __cplusplus
}
#endif
+
+int GDAPI godot_nativescript_register_instance_binding_data_functions(godot_instance_binding_functions p_binding_functions) {
+ return NativeScriptLanguage::get_singleton()->register_binding_functions(p_binding_functions);
+}
+
+void GDAPI godot_nativescript_unregister_instance_binding_data_functions(int p_idx) {
+ NativeScriptLanguage::get_singleton()->unregister_binding_functions(p_idx);
+}
+
+void GDAPI *godot_nativescript_get_instance_binding_data(int p_idx, godot_object *p_object) {
+ return NativeScriptLanguage::get_singleton()->get_instance_binding_data(p_idx, (Object *)p_object);
+}
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index e9e3180835..f2e9bef467 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -68,6 +68,11 @@ void NativeScript::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_library", "library"), &NativeScript::set_library);
ClassDB::bind_method(D_METHOD("get_library"), &NativeScript::get_library);
+ ClassDB::bind_method(D_METHOD("get_class_documentation"), &NativeScript::get_class_documentation);
+ ClassDB::bind_method(D_METHOD("get_method_documentation", "method"), &NativeScript::get_method_documentation);
+ 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");
@@ -373,6 +378,86 @@ void NativeScript::get_script_property_list(List<PropertyInfo> *p_list) const {
}
}
+String NativeScript::get_class_documentation() const {
+ NativeScriptDesc *script_data = get_script_desc();
+
+ if (!script_data) {
+ ERR_EXPLAIN("Attempt to get class documentation on invalid NativeScript");
+ ERR_FAIL_V("");
+ }
+
+ return script_data->documentation;
+}
+
+String NativeScript::get_method_documentation(const StringName &p_method) const {
+ NativeScriptDesc *script_data = get_script_desc();
+
+ if (!script_data) {
+ ERR_EXPLAIN("Attempt to get method documentation on invalid NativeScript");
+ ERR_FAIL_V("");
+ }
+
+ while (script_data) {
+
+ Map<StringName, NativeScriptDesc::Method>::Element *method = script_data->methods.find(p_method);
+
+ if (method) {
+ return method->get().documentation;
+ }
+
+ script_data = script_data->base_data;
+ }
+
+ ERR_EXPLAIN("Attempt to get method documentation for non-existent method");
+ ERR_FAIL_V("");
+}
+
+String NativeScript::get_signal_documentation(const StringName &p_signal_name) const {
+ NativeScriptDesc *script_data = get_script_desc();
+
+ if (!script_data) {
+ ERR_EXPLAIN("Attempt to get signal documentation on invalid NativeScript");
+ ERR_FAIL_V("");
+ }
+
+ while (script_data) {
+
+ Map<StringName, NativeScriptDesc::Signal>::Element *signal = script_data->signals_.find(p_signal_name);
+
+ if (signal) {
+ return signal->get().documentation;
+ }
+
+ script_data = script_data->base_data;
+ }
+
+ ERR_EXPLAIN("Attempt to get signal documentation for non-existent signal");
+ ERR_FAIL_V("");
+}
+
+String NativeScript::get_property_documentation(const StringName &p_path) const {
+ NativeScriptDesc *script_data = get_script_desc();
+
+ if (!script_data) {
+ ERR_EXPLAIN("Attempt to get property documentation on invalid NativeScript");
+ ERR_FAIL_V("");
+ }
+
+ while (script_data) {
+
+ OrderedHashMap<StringName, NativeScriptDesc::Property>::Element property = script_data->properties.find(p_path);
+
+ if (property) {
+ return property.get().documentation;
+ }
+
+ script_data = script_data->base_data;
+ }
+
+ ERR_EXPLAIN("Attempt to get property documentation for non-existent signal");
+ ERR_FAIL_V("");
+}
+
Variant NativeScript::_new(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
if (lib_path.empty() || class_name.empty() || library.is_null()) {
@@ -398,6 +483,11 @@ Variant NativeScript::_new(const Variant **p_args, int p_argcount, Variant::Call
owner = memnew(Reference);
}
+ if (!owner) {
+ r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ return Variant();
+ }
+
Reference *r = Object::cast_to<Reference>(owner);
if (r) {
ref = REF(r);
@@ -605,7 +695,7 @@ Variant::Type NativeScriptInstance::get_property_type(const StringName &p_name,
}
void NativeScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
- script->get_method_list(p_list);
+ script->get_script_method_list(p_list);
}
bool NativeScriptInstance::has_method(const StringName &p_method) const {
@@ -793,11 +883,52 @@ NativeScriptLanguage *NativeScriptLanguage::singleton;
void NativeScriptLanguage::_unload_stuff(bool p_reload) {
for (Map<String, Map<StringName, NativeScriptDesc> >::Element *L = library_classes.front(); L; L = L->next()) {
- if (p_reload && !library_gdnatives[L->key()]->get_library()->is_reloadable()) {
- continue;
+ String lib_path = L->key();
+ Map<StringName, NativeScriptDesc> classes = L->get();
+
+ if (p_reload) {
+
+ Map<String, Ref<GDNative> >::Element *E = library_gdnatives.find(lib_path);
+ Ref<GDNative> gdn;
+
+ if (E) {
+ gdn = E->get();
+ }
+
+ bool should_reload = false;
+
+ if (gdn.is_valid()) {
+ Ref<GDNativeLibrary> lib = gdn->get_library();
+ if (lib.is_valid()) {
+ should_reload = lib->is_reloadable();
+ }
+ }
+
+ if (!should_reload) {
+ continue;
+ }
}
- for (Map<StringName, NativeScriptDesc>::Element *C = L->get().front(); C; C = C->next()) {
+ Map<String, Ref<GDNative> >::Element *E = library_gdnatives.find(lib_path);
+ Ref<GDNative> gdn;
+
+ if (E) {
+ gdn = E->get();
+ }
+
+ if (gdn.is_valid() && gdn->get_library().is_valid()) {
+ Ref<GDNativeLibrary> lib = gdn->get_library();
+ void *terminate_fn;
+ Error err = gdn->get_symbol(lib->get_symbol_prefix() + _terminate_call_name, terminate_fn, true);
+
+ if (err == OK) {
+ void (*terminate)(void *) = (void (*)(void *))terminate_fn;
+
+ terminate((void *)&lib_path);
+ }
+ }
+
+ for (Map<StringName, NativeScriptDesc>::Element *C = classes.front(); C; C = C->next()) {
// free property stuff first
for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element P = C->get().properties.front(); P; P = P.next()) {
@@ -835,12 +966,14 @@ NativeScriptLanguage::~NativeScriptLanguage() {
for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
- L->get()->terminate();
- NSL->library_classes.clear();
- NSL->library_gdnatives.clear();
- NSL->library_script_users.clear();
+ if (L->get().is_valid())
+ L->get()->terminate();
}
+ NSL->library_classes.clear();
+ NSL->library_gdnatives.clear();
+ NSL->library_script_users.clear();
+
#ifndef NO_THREADS
memdelete(mutex);
#endif
@@ -902,7 +1035,7 @@ Ref<Script> NativeScriptLanguage::get_template(const String &p_class_name, const
return Ref<NativeScript>(s);
}
bool NativeScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const {
- return false;
+ return true;
}
Script *NativeScriptLanguage::create_script() const {
@@ -982,6 +1115,116 @@ int NativeScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, in
return 0;
}
+int NativeScriptLanguage::register_binding_functions(godot_instance_binding_functions p_binding_functions) {
+
+ // find index
+
+ int idx = -1;
+
+ for (int i = 0; i < binding_functions.size(); i++) {
+ if (!binding_functions[i].first) {
+ // free, we'll take it
+ idx = i;
+ break;
+ }
+ }
+
+ if (idx == -1) {
+ idx = binding_functions.size();
+ binding_functions.resize(idx + 1);
+ }
+
+ // set the functions
+ binding_functions[idx].first = true;
+ binding_functions[idx].second = p_binding_functions;
+
+ return idx;
+}
+
+void NativeScriptLanguage::unregister_binding_functions(int p_idx) {
+ ERR_FAIL_INDEX(p_idx, binding_functions.size());
+
+ for (Set<Vector<void *> *>::Element *E = binding_instances.front(); E; E = E->next()) {
+ Vector<void *> &binding_data = *E->get();
+
+ if (binding_data[p_idx] && binding_functions[p_idx].second.free_instance_binding_data)
+ binding_functions[p_idx].second.free_instance_binding_data(binding_functions[p_idx].second.data, binding_data[p_idx]);
+ }
+
+ binding_functions[p_idx].first = false;
+
+ if (binding_functions[p_idx].second.free_func)
+ binding_functions[p_idx].second.free_func(binding_functions[p_idx].second.data);
+}
+
+void *NativeScriptLanguage::get_instance_binding_data(int p_idx, Object *p_object) {
+ ERR_FAIL_INDEX_V(p_idx, binding_functions.size(), NULL);
+
+ if (!binding_functions[p_idx].first) {
+ ERR_EXPLAIN("Tried to get binding data for a nativescript binding that does not exist");
+ ERR_FAIL_V(NULL);
+ }
+
+ Vector<void *> *binding_data = (Vector<void *> *)p_object->get_script_instance_binding(lang_idx);
+
+ if (!binding_data)
+ return NULL; // should never happen.
+
+ if (binding_data->size() <= p_idx) {
+ // okay, add new elements here.
+ int old_size = binding_data->size();
+
+ binding_data->resize(p_idx + 1);
+
+ for (int i = old_size; i <= p_idx; i++) {
+ (*binding_data)[i] = NULL;
+ }
+ }
+
+ if (!(*binding_data)[p_idx]) {
+ // no binding data yet, soooooo alloc new one \o/
+ (*binding_data)[p_idx] = binding_functions[p_idx].second.alloc_instance_binding_data(binding_functions[p_idx].second.data, (godot_object *)p_object);
+ }
+
+ return (*binding_data)[p_idx];
+}
+
+void *NativeScriptLanguage::alloc_instance_binding_data(Object *p_object) {
+
+ Vector<void *> *binding_data = new Vector<void *>;
+
+ binding_data->resize(binding_functions.size());
+
+ for (int i = 0; i < binding_functions.size(); i++) {
+ (*binding_data)[i] = NULL;
+ }
+
+ binding_instances.insert(binding_data);
+
+ return (void *)binding_data;
+}
+
+void NativeScriptLanguage::free_instance_binding_data(void *p_data) {
+
+ if (!p_data)
+ return;
+
+ Vector<void *> &binding_data = *(Vector<void *> *)p_data;
+
+ for (int i = 0; i < binding_data.size(); i++) {
+ if (!binding_data[i])
+ continue;
+
+ if (binding_functions[i].first && binding_functions[i].second.free_instance_binding_data) {
+ binding_functions[i].second.free_instance_binding_data(binding_functions[i].second.data, binding_data[i]);
+ }
+ }
+
+ binding_instances.erase(&binding_data);
+
+ delete &binding_data;
+}
+
#ifndef NO_THREADS
void NativeScriptLanguage::defer_init_library(Ref<GDNativeLibrary> lib, NativeScript *script) {
MutexLock lock(mutex);
@@ -1056,6 +1299,11 @@ void NativeScriptLanguage::unregister_script(NativeScript *script) {
void NativeScriptLanguage::call_libraries_cb(const StringName &name) {
// library_gdnatives is modified only from the main thread, so it's safe not to use mutex here
for (Map<String, Ref<GDNative> >::Element *L = library_gdnatives.front(); L; L = L->next()) {
+
+ if (L->get().is_null()) {
+ continue;
+ }
+
if (L->get()->is_initialized()) {
void *proc_ptr;
@@ -1118,6 +1366,10 @@ void NativeReloadNode::_notification(int p_what) {
Ref<GDNative> gdn = L->get();
+ if (gdn.is_null()) {
+ continue;
+ }
+
if (!gdn->get_library()->is_reloadable()) {
continue;
}
@@ -1142,6 +1394,10 @@ void NativeReloadNode::_notification(int p_what) {
Ref<GDNative> gdn = L->get();
+ if (gdn.is_null()) {
+ continue;
+ }
+
if (!gdn->get_library()->is_reloadable()) {
continue;
}
diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h
index ac94c84bc4..17b6ddc747 100644
--- a/modules/gdnative/nativescript/nativescript.h
+++ b/modules/gdnative/nativescript/nativescript.h
@@ -53,6 +53,7 @@ struct NativeScriptDesc {
godot_instance_method method;
MethodInfo info;
int rpc_mode;
+ String documentation;
};
struct Property {
godot_property_set_func setter;
@@ -60,12 +61,16 @@ struct NativeScriptDesc {
PropertyInfo info;
Variant default_value;
int rset_mode;
+ String documentation;
};
struct Signal {
MethodInfo signal;
+ String documentation;
};
+ String documentation;
+
Map<StringName, Method> methods;
OrderedHashMap<StringName, Property> properties;
Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals
@@ -75,6 +80,8 @@ struct NativeScriptDesc {
godot_instance_create_func create_func;
godot_instance_destroy_func destroy_func;
+ const void *type_tag;
+
bool is_tool;
inline NativeScriptDesc() :
@@ -82,7 +89,9 @@ struct NativeScriptDesc {
properties(),
signals_(),
base(),
- base_native_type() {
+ base_native_type(),
+ documentation(),
+ type_tag(NULL) {
zeromem(&create_func, sizeof(godot_instance_create_func));
zeromem(&destroy_func, sizeof(godot_instance_destroy_func));
}
@@ -154,6 +163,11 @@ public:
virtual void get_script_method_list(List<MethodInfo> *p_list) const;
virtual void get_script_property_list(List<PropertyInfo> *p_list) const;
+ String get_class_documentation() const;
+ String get_method_documentation(const StringName &p_method) const;
+ String get_signal_documentation(const StringName &p_signal_name) const;
+ String get_property_documentation(const StringName &p_path) const;
+
Variant _new(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
NativeScript();
@@ -204,6 +218,7 @@ class NativeScriptLanguage : public ScriptLanguage {
private:
static NativeScriptLanguage *singleton;
+ int lang_idx;
void _unload_stuff(bool p_reload = false);
@@ -222,6 +237,9 @@ private:
void call_libraries_cb(const StringName &name);
+ Vector<Pair<bool, godot_instance_binding_functions> > binding_functions;
+ Set<Vector<void *> *> binding_instances;
+
public:
// These two maps must only be touched on the main thread
Map<String, Map<StringName, NativeScriptDesc> > library_classes;
@@ -232,6 +250,8 @@ public:
const StringName _init_call_type = "nativescript_init";
const StringName _init_call_name = "nativescript_init";
+ const StringName _terminate_call_name = "nativescript_terminate";
+
const StringName _noarg_call_type = "nativescript_no_arg";
const StringName _frame_call_name = "nativescript_frame";
@@ -250,6 +270,8 @@ public:
void _hacky_api_anchor();
+ _FORCE_INLINE_ void set_language_index(int p_idx) { lang_idx = p_idx; }
+
#ifndef NO_THREADS
virtual void thread_enter();
virtual void thread_exit();
@@ -293,6 +315,14 @@ public:
virtual void profiling_stop();
virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max);
virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max);
+
+ int register_binding_functions(godot_instance_binding_functions p_binding_functions);
+ void unregister_binding_functions(int p_idx);
+
+ void *get_instance_binding_data(int p_idx, Object *p_object);
+
+ virtual void *alloc_instance_binding_data(Object *p_object);
+ virtual void free_instance_binding_data(void *p_data);
};
inline NativeScriptDesc *NativeScript::get_script_desc() const {
diff --git a/modules/gdnative/nativescript/register_types.cpp b/modules/gdnative/nativescript/register_types.cpp
index cb55a13b3e..9a0e764391 100644
--- a/modules/gdnative/nativescript/register_types.cpp
+++ b/modules/gdnative/nativescript/register_types.cpp
@@ -47,6 +47,7 @@ void register_nativescript_types() {
ClassDB::register_class<NativeScript>();
+ native_script_language->set_language_index(ScriptServer::get_language_count());
ScriptServer::register_language(native_script_language);
resource_saver_gdns = memnew(ResourceFormatSaverNativeScript);
diff --git a/modules/gdnative/pluginscript/pluginscript_instance.cpp b/modules/gdnative/pluginscript/pluginscript_instance.cpp
index 52d112bc93..931ab0bfe4 100644
--- a/modules/gdnative/pluginscript/pluginscript_instance.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_instance.cpp
@@ -84,8 +84,9 @@ Variant PluginScriptInstance::call(const StringName &p_method, const Variant **p
godot_variant ret = _desc->call_method(
_data, (godot_string_name *)&p_method, (const godot_variant **)p_args,
p_argcount, (godot_variant_call_error *)&r_error);
- Variant *var_ret = (Variant *)&ret;
- return *var_ret;
+ Variant var_ret = *(Variant *)&ret;
+ godot_variant_destroy(&ret);
+ return var_ret;
}
#if 0 // TODO: Don't rely on default implementations provided by ScriptInstance ?
diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp
index 8101ebc6f3..8018178bd5 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_language.cpp
@@ -103,6 +103,7 @@ Ref<Script> PluginScriptLanguage::get_template(const String &p_class_name, const
if (_desc.get_template_source_code) {
godot_string src = _desc.get_template_source_code(_data, (godot_string *)&p_class_name, (godot_string *)&p_base_class_name);
script->set_source_code(*(String *)&src);
+ godot_string_destroy(&src);
}
return script;
}
diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp
index b4525ff8aa..5ae7926f1b 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_script.cpp
@@ -131,13 +131,10 @@ ScriptInstance *PluginScript::instance_create(Object *p_this) {
#endif
}
- PluginScript *top = this;
- // TODO: can be optimized by storing a PluginScript::_base_parent direct pointer
- while (top->_ref_base_parent.is_valid())
- top = top->_ref_base_parent.ptr();
- if (top->_native_parent) {
- if (!ClassDB::is_parent_class(p_this->get_class_name(), top->_native_parent)) {
- String msg = "Script inherits from native type '" + String(top->_native_parent) + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'";
+ StringName base_type = get_instance_base_type();
+ if (base_type) {
+ if (!ClassDB::is_parent_class(p_this->get_class_name(), base_type)) {
+ String msg = "Script inherits from native type '" + String(base_type) + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'";
// TODO: implement PluginscriptLanguage::debug_break_parse
// if (ScriptDebugger::get_singleton()) {
// _language->debug_break_parse(get_path(), 0, msg);
@@ -210,29 +207,31 @@ Error PluginScript::reload(bool p_keep_state) {
// TODO: GDscript uses `ScriptDebugger` here to jump into the parsing error
return err;
}
+
+ // Script's parent is passed as base_name which can make reference to a
+ // ClassDB name (i.e. `Node2D`) or a resource path (i.e. `res://foo/bar.gd`)
+ StringName *base_name = (StringName *)&manifest.base;
+ if (*base_name) {
+
+ if (ClassDB::class_exists(*base_name)) {
+ _native_parent = *base_name;
+ } else {
+ Ref<Script> res = ResourceLoader::load(*base_name);
+ if (res.is_valid()) {
+ _ref_base_parent = res;
+ } else {
+ String name = *(StringName *)&manifest.name;
+ ERR_EXPLAIN(_path + ": Script '" + name + "' has an invalid parent '" + *base_name + "'.");
+ ERR_FAIL_V(ERR_PARSE_ERROR);
+ }
+ }
+ }
+
_valid = true;
// Use the manifest to configure this script object
_data = manifest.data;
_name = *(StringName *)&manifest.name;
_tool = manifest.is_tool;
- // Base name is either another PluginScript or a regular class accessible
- // through ClassDB
- StringName *base_name = (StringName *)&manifest.base;
- for (SelfList<PluginScript> *e = _language->_script_list.first(); e != NULL; e = e->next()) {
- if (e->self()->_name == *base_name) {
- // Found you, base is a PluginScript !
- _ref_base_parent = Ref<PluginScript>(e->self());
- break;
- }
- }
- if (!_ref_base_parent.is_valid()) {
- // Base is a native ClassDB
- if (!ClassDB::class_exists(*base_name)) {
- ERR_EXPLAIN("Unknown script '" + String(_name) + "' parent '" + String(*base_name) + "'.");
- ERR_FAIL_V(ERR_PARSE_ERROR);
- }
- _native_parent = *base_name;
- }
Dictionary *members = (Dictionary *)&manifest.member_lines;
for (const Variant *key = members->next(); key != NULL; key = members->next(key)) {
diff --git a/modules/gdnative/pluginscript/pluginscript_script.h b/modules/gdnative/pluginscript/pluginscript_script.h
index 6b343ad844..1be9e907c2 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.h
+++ b/modules/gdnative/pluginscript/pluginscript_script.h
@@ -53,7 +53,7 @@ private:
bool _tool;
bool _valid;
- Ref<PluginScript> _ref_base_parent;
+ Ref<Script> _ref_base_parent;
StringName _native_parent;
SelfList<PluginScript> _script_list;
@@ -112,7 +112,7 @@ public:
virtual void update_exports();
virtual void get_script_method_list(List<MethodInfo> *r_methods) const;
- virtual void get_script_property_list(List<PropertyInfo> *r_propertieslist) const;
+ virtual void get_script_property_list(List<PropertyInfo> *r_properties) const;
virtual int get_member_line(const StringName &p_member) const;
diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml
index cc617c5c67..0dc69c3688 100644
--- a/modules/gdscript/doc_classes/GDScript.xml
+++ b/modules/gdscript/doc_classes/GDScript.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GDScript" inherits="Script" category="Core" version="3.0-beta">
+<class name="GDScript" inherits="Script" category="Core" version="3.1-dev">
<brief_description>
A script implemented in the GDScript programming language.
</brief_description>
@@ -8,6 +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>
+ http://docs.godotengine.org/en/3.0/getting_started/scripting/gdscript/index.html
</tutorials>
<demos>
</demos>
diff --git a/modules/gdscript/doc_classes/GDScriptFunctionState.xml b/modules/gdscript/doc_classes/GDScriptFunctionState.xml
index 465a4f438b..254d968e1b 100644
--- a/modules/gdscript/doc_classes/GDScriptFunctionState.xml
+++ b/modules/gdscript/doc_classes/GDScriptFunctionState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GDScriptFunctionState" inherits="Reference" category="Core" version="3.0-beta">
+<class name="GDScriptFunctionState" inherits="Reference" category="Core" version="3.1-dev">
<brief_description>
State of a function call after yielding.
</brief_description>
diff --git a/modules/gdscript/doc_classes/GDScriptNativeClass.xml b/modules/gdscript/doc_classes/GDScriptNativeClass.xml
index 948254e0ad..1abcc4762f 100644
--- a/modules/gdscript/doc_classes/GDScriptNativeClass.xml
+++ b/modules/gdscript/doc_classes/GDScriptNativeClass.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GDScriptNativeClass" inherits="Reference" category="Core" version="3.0-beta">
+<class name="GDScriptNativeClass" inherits="Reference" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index f380bedf7f..048948dada 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -37,6 +37,9 @@ bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringN
if (!codegen.function_node || codegen.function_node->_static)
return false;
+ if (codegen.stack_identifiers.has(p_name))
+ return false; //shadowed
+
return _is_class_member_property(codegen.script, p_name);
}
@@ -178,12 +181,20 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
//wait, identifier could be a local variable or something else... careful here, must reference properly
//as stack may be more interesting to work with
- //This could be made much simpler by just indexing "self", but done this way (with custom self-addressing modes) increases peformance a lot.
+ //This could be made much simpler by just indexing "self", but done this way (with custom self-addressing modes) increases performance a lot.
const GDScriptParser::IdentifierNode *in = static_cast<const GDScriptParser::IdentifierNode *>(p_expression);
StringName identifier = in->name;
+ // TRY STACK!
+ if (!p_initializer && codegen.stack_identifiers.has(identifier)) {
+
+ int pos = codegen.stack_identifiers[identifier];
+ return pos | (GDScriptFunction::ADDR_TYPE_STACK_VARIABLE << GDScriptFunction::ADDR_BITS);
+ }
+
+ // TRY CLASS MEMBER
if (_is_class_member_property(codegen, identifier)) {
//get property
codegen.opcodes.push_back(GDScriptFunction::OPCODE_GET_MEMBER); // perform operator
@@ -194,12 +205,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
return dst_addr;
}
- // TRY STACK!
- if (!p_initializer && codegen.stack_identifiers.has(identifier)) {
-
- int pos = codegen.stack_identifiers[identifier];
- return pos | (GDScriptFunction::ADDR_TYPE_STACK_VARIABLE << GDScriptFunction::ADDR_BITS);
- }
//TRY MEMBERS!
if (!codegen.function_node || !codegen.function_node->_static) {
@@ -1336,10 +1341,12 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo
const GDScriptParser::LocalVarNode *lv = static_cast<const GDScriptParser::LocalVarNode *>(s);
- if (_is_class_member_property(codegen, lv->name)) {
- _set_error("Name for local variable '" + String(lv->name) + "' can't shadow class property of the same name.", lv);
- return ERR_ALREADY_EXISTS;
- }
+ // since we are using properties now for most class access, allow shadowing of class members to make user's life easier.
+ //
+ //if (_is_class_member_property(codegen, lv->name)) {
+ // _set_error("Name for local variable '" + String(lv->name) + "' can't shadow class property of the same name.", lv);
+ // return ERR_ALREADY_EXISTS;
+ //}
codegen.add_stack_identifier(lv->name, p_stack_level++);
codegen.alloc_stack(p_stack_level);
@@ -1376,10 +1383,13 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
if (p_func) {
for (int i = 0; i < p_func->arguments.size(); i++) {
- if (_is_class_member_property(p_script, p_func->arguments[i])) {
- _set_error("Name for argument '" + String(p_func->arguments[i]) + "' can't shadow class property of the same name.", p_func);
- return ERR_ALREADY_EXISTS;
- }
+ // since we are using properties now for most class access, allow shadowing of class members to make user's life easier.
+ //
+ //if (_is_class_member_property(p_script, p_func->arguments[i])) {
+ // _set_error("Name for argument '" + String(p_func->arguments[i]) + "' can't shadow class property of the same name.", p_func);
+ // return ERR_ALREADY_EXISTS;
+ //}
+
codegen.add_stack_identifier(p_func->arguments[i], i);
#ifdef TOOLS_ENABLED
argnames.push_back(p_func->arguments[i]);
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index bcfe8525b4..db3787470f 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -369,8 +369,8 @@ void GDScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const
mi.name = "yield";
mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object"));
mi.arguments.push_back(PropertyInfo(Variant::STRING, "signal"));
- mi.default_arguments.push_back(Variant::NIL);
- mi.default_arguments.push_back(Variant::STRING);
+ mi.default_arguments.push_back(Variant());
+ mi.default_arguments.push_back(String());
mi.return_val = PropertyInfo(Variant::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, "GDScriptFunctionState");
p_functions->push_back(mi);
}
@@ -410,13 +410,11 @@ String GDScriptLanguage::make_function(const String &p_class, const String &p_na
String s = "func " + p_name + "(";
if (p_args.size()) {
- s += " ";
for (int i = 0; i < p_args.size(); i++) {
if (i > 0)
s += ", ";
s += p_args[i].get_slice(":", 0);
}
- s += " ";
}
s += "):\n" + _get_indentation() + "pass # replace with function body\n";
@@ -491,8 +489,8 @@ static Ref<Reference> _get_parent_class(GDScriptCompletionContext &context) {
path = context.base_path.plus_file(path);
}
- if (ScriptCodeCompletionCache::get_sigleton())
- script = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(path);
+ if (ScriptCodeCompletionCache::get_singleton())
+ script = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(path);
else
script = ResourceLoader::load(path);
@@ -765,8 +763,8 @@ static bool _guess_expression_type(GDScriptCompletionContext &context, const GDS
//print_line("is a script");
Ref<Script> scr;
- if (ScriptCodeCompletionCache::get_sigleton())
- scr = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(script);
+ if (ScriptCodeCompletionCache::get_singleton())
+ scr = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(script);
else
scr = ResourceLoader::load(script);
@@ -1301,8 +1299,8 @@ static bool _guess_identifier_type(GDScriptCompletionContext &context, int p_lin
//print_line("is a script");
Ref<Script> scr;
- if (ScriptCodeCompletionCache::get_sigleton())
- scr = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(script);
+ if (ScriptCodeCompletionCache::get_singleton())
+ scr = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(script);
else
scr = ResourceLoader::load(script);
@@ -2450,8 +2448,10 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base
} break;
case GDScriptParser::COMPLETION_RESOURCE_PATH: {
- if (EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))
+ if (EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths")) {
get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), options);
+ r_forced = true;
+ }
} break;
case GDScriptParser::COMPLETION_ASSIGN: {
#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index f15f2197da..278585cb01 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -358,13 +358,16 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
r_ret = Math::dectime((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
} break;
case MATH_RANDOMIZE: {
+ VALIDATE_ARG_COUNT(0);
Math::randomize();
r_ret = Variant();
} break;
case MATH_RAND: {
+ VALIDATE_ARG_COUNT(0);
r_ret = Math::rand();
} break;
case MATH_RANDF: {
+ VALIDATE_ARG_COUNT(0);
r_ret = Math::randf();
} break;
case MATH_RANDOM: {
@@ -593,7 +596,13 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
r_ret = String(result);
} break;
case TEXT_STR: {
+ if (p_arg_count < 1) {
+ r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ r_ret = Variant();
+ return;
+ }
String str;
for (int i = 0; i < p_arg_count; i++) {
@@ -1180,6 +1189,7 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
} break;
case PRINT_STACK: {
+ VALIDATE_ARG_COUNT(0);
ScriptLanguage *script = GDScriptLanguage::get_singleton();
for (int i = 0; i < script->debug_get_stack_level_count(); i++) {
@@ -1483,7 +1493,7 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
return mi;
} break;
case MATH_INVERSE_LERP: {
- MethodInfo mi("inverse_lerp", PropertyInfo(Variant::REAL, "from"), PropertyInfo(Variant::REAL, "to"), PropertyInfo(Variant::REAL, "value"));
+ MethodInfo mi("inverse_lerp", PropertyInfo(Variant::REAL, "from"), PropertyInfo(Variant::REAL, "to"), PropertyInfo(Variant::REAL, "weight"));
mi.return_val.type = Variant::REAL;
return mi;
} break;
@@ -1579,12 +1589,12 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
return mi;
} break;
case LOGIC_CLAMP: {
- MethodInfo mi("clamp", PropertyInfo(Variant::REAL, "val"), PropertyInfo(Variant::REAL, "min"), PropertyInfo(Variant::REAL, "max"));
+ MethodInfo mi("clamp", PropertyInfo(Variant::REAL, "value"), PropertyInfo(Variant::REAL, "min"), PropertyInfo(Variant::REAL, "max"));
mi.return_val.type = Variant::REAL;
return mi;
} break;
case LOGIC_NEAREST_PO2: {
- MethodInfo mi("nearest_po2", PropertyInfo(Variant::INT, "val"));
+ MethodInfo mi("nearest_po2", PropertyInfo(Variant::INT, "value"));
mi.return_val.type = Variant::INT;
return mi;
} break;
@@ -1760,12 +1770,14 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
case COLOR8: {
MethodInfo mi("Color8", PropertyInfo(Variant::INT, "r8"), PropertyInfo(Variant::INT, "g8"), PropertyInfo(Variant::INT, "b8"), PropertyInfo(Variant::INT, "a8"));
+ mi.default_arguments.push_back(255);
mi.return_val.type = Variant::COLOR;
return mi;
} break;
case COLORN: {
MethodInfo mi("ColorN", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::REAL, "alpha"));
+ mi.default_arguments.push_back(1.0f);
mi.return_val.type = Variant::COLOR;
return mi;
} break;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 2a6d37812e..ac7fd94141 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -95,8 +95,6 @@ bool GDScriptParser::_enter_indent_block(BlockNode *p_block) {
int indent = tokenizer->get_token_line_indent();
int current = tab_level.back()->get();
if (indent <= current) {
- print_line("current: " + itos(current) + " indent: " + itos(indent));
- print_line("less than current");
return false;
}
@@ -458,9 +456,9 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (!validating) {
//this can be too slow for just validating code
- if (for_completion && ScriptCodeCompletionCache::get_sigleton()) {
- res = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(path);
- } else {
+ if (for_completion && ScriptCodeCompletionCache::get_singleton() && FileAccess::exists(path)) {
+ res = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(path);
+ } else if (!for_completion || FileAccess::exists(path)) {
res = ResourceLoader::load(path);
}
if (!res.is_valid()) {
@@ -578,18 +576,47 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (identifier == StringName()) {
- _set_error("Built-in type constant expected after '.'");
+ _set_error("Built-in type constant or static function expected after '.'");
return NULL;
}
if (!Variant::has_numeric_constant(bi_type, identifier)) {
- _set_error("Static constant '" + identifier.operator String() + "' not present in built-in type " + Variant::get_type_name(bi_type) + ".");
- return NULL;
- }
+ if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_OPEN &&
+ Variant::is_method_const(bi_type, identifier) &&
+ Variant::get_method_return_type(bi_type, identifier) == bi_type) {
+
+ tokenizer->advance();
+
+ OperatorNode *construct = alloc_node<OperatorNode>();
+ construct->op = OperatorNode::OP_CALL;
+
+ TypeNode *tn = alloc_node<TypeNode>();
+ tn->vtype = bi_type;
+ construct->arguments.push_back(tn);
+
+ OperatorNode *op = alloc_node<OperatorNode>();
+ op->op = OperatorNode::OP_CALL;
+ op->arguments.push_back(construct);
+
+ IdentifierNode *id = alloc_node<IdentifierNode>();
+ id->name = identifier;
+ op->arguments.push_back(id);
- ConstantNode *cn = alloc_node<ConstantNode>();
- cn->value = Variant::get_numeric_constant_value(bi_type, identifier);
- expr = cn;
+ if (!_parse_arguments(op, op->arguments, p_static, true))
+ return NULL;
+
+ expr = op;
+ } else {
+
+ _set_error("Static constant '" + identifier.operator String() + "' not present in built-in type " + Variant::get_type_name(bi_type) + ".");
+ return NULL;
+ }
+ } else {
+
+ ConstantNode *cn = alloc_node<ConstantNode>();
+ cn->value = Variant::get_numeric_constant_value(bi_type, identifier);
+ expr = cn;
+ }
} else if (tokenizer->get_token(1) == GDScriptTokenizer::TK_PARENTHESIS_OPEN && tokenizer->is_token_literal()) {
// We check with is_token_literal, as this allows us to use match/sync/etc. as a name
@@ -1518,11 +1545,11 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to
String errwhere;
if (op->arguments[0]->type == Node::TYPE_TYPE) {
TypeNode *tn = static_cast<TypeNode *>(op->arguments[0]);
- errwhere = "'" + Variant::get_type_name(tn->vtype) + "'' constructor";
+ errwhere = "'" + Variant::get_type_name(tn->vtype) + "' constructor";
} else {
GDScriptFunctions::Function func = static_cast<BuiltInFunctionNode *>(op->arguments[0])->function;
- errwhere = String("'") + GDScriptFunctions::get_func_name(func) + "'' intrinsic function";
+ errwhere = String("'") + GDScriptFunctions::get_func_name(func) + "' intrinsic function";
}
switch (ce.error) {
@@ -4071,7 +4098,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
ConstantNode *cn = static_cast<ConstantNode *>(subexpr);
if (cn->value.get_type() == Variant::NIL) {
- _set_error("Can't accept a null constant expression for infering export type.");
+ _set_error("Can't accept a null constant expression for inferring export type.");
return;
}
member._export.type = cn->value.get_type();
@@ -4207,7 +4234,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
} break;
case GDScriptTokenizer::TK_PR_ENUM: {
- //mutiple constant declarations..
+ //multiple constant declarations..
int last_assign = -1; // Incremented by 1 right before the assingment.
String enum_name;
@@ -4358,8 +4385,6 @@ Error GDScriptParser::_parse(const String &p_base_path) {
base_path = p_base_path;
- clear();
-
//assume class
ClassNode *main_class = alloc_node<ClassNode>();
main_class->initializer = alloc_node<BlockNode>();
@@ -4384,17 +4409,7 @@ Error GDScriptParser::_parse(const String &p_base_path) {
Error GDScriptParser::parse_bytecode(const Vector<uint8_t> &p_bytecode, const String &p_base_path, const String &p_self_path) {
- for_completion = false;
- validating = false;
- completion_type = COMPLETION_NONE;
- completion_node = NULL;
- completion_class = NULL;
- completion_function = NULL;
- completion_block = NULL;
- completion_found = false;
- current_block = NULL;
- current_class = NULL;
- current_function = NULL;
+ clear();
self_path = p_self_path;
GDScriptTokenizerBuffer *tb = memnew(GDScriptTokenizerBuffer);
@@ -4408,16 +4423,7 @@ Error GDScriptParser::parse_bytecode(const Vector<uint8_t> &p_bytecode, const St
Error GDScriptParser::parse(const String &p_code, const String &p_base_path, bool p_just_validate, const String &p_self_path, bool p_for_completion) {
- completion_type = COMPLETION_NONE;
- completion_node = NULL;
- completion_class = NULL;
- completion_function = NULL;
- completion_block = NULL;
- completion_found = false;
- current_block = NULL;
- current_class = NULL;
-
- current_function = NULL;
+ clear();
self_path = p_self_path;
GDScriptTokenizerText *tt = memnew(GDScriptTokenizerText);
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index f814304180..36d4d7cb59 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GridMap" inherits="Spatial" category="Core" version="3.0-beta">
+<class name="GridMap" inherits="Spatial" category="Core" version="3.1-dev">
<brief_description>
Node for 3D tile-based maps.
</brief_description>
@@ -10,6 +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>
+ http://docs.godotengine.org/en/3.0/tutorials/3d/using_gridmaps.html
</tutorials>
<demos>
</demos>
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index b17fe43ae8..ed36751fc8 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -247,7 +247,7 @@ public:
int get_cell_item(int p_x, int p_y, int p_z) const;
int get_cell_item_orientation(int p_x, int p_y, int p_z) const;
- Vector3 world_to_map(const Vector3 &p_pos) const;
+ Vector3 world_to_map(const Vector3 &p_world_pos) const;
Vector3 map_to_world(int p_x, int p_y, int p_z) const;
void set_clip(bool p_enabled, bool p_clip_above = true, int p_floor = 0, Vector3::Axis p_axis = Vector3::AXIS_X);
diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp
index 7b7bc0fa2a..34d51b51e2 100644
--- a/modules/gridmap/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/grid_map_editor_plugin.cpp
@@ -99,6 +99,20 @@ void GridMapEditor::_menu_option(int p_option) {
int idx = options->get_popup()->get_item_index(MENU_OPTION_X_AXIS + i);
options->get_popup()->set_item_checked(idx, i == new_axis);
}
+
+ if (edit_axis != new_axis) {
+ int item1 = options->get_popup()->get_item_id(MENU_OPTION_NEXT_LEVEL);
+ int item2 = options->get_popup()->get_item_id(MENU_OPTION_PREV_LEVEL);
+ if (edit_axis == Vector3::AXIS_Y) {
+ options->get_popup()->set_item_text(item1, TTR("Next Plane"));
+ options->get_popup()->set_item_text(item2, TTR("Previous Plane"));
+ spin_box_label->set_text(TTR("Plane:"));
+ } else if (new_axis == Vector3::AXIS_Y) {
+ options->get_popup()->set_item_text(item1, TTR("Next Floor"));
+ options->get_popup()->set_item_text(item2, TTR("Previous Floor"));
+ spin_box_label->set_text(TTR("Floor:"));
+ }
+ }
edit_axis = Vector3::Axis(new_axis);
update_grid();
_update_clip();
@@ -998,9 +1012,9 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
spatial_editor_hb->set_alignment(BoxContainer::ALIGN_END);
SpatialEditor::get_singleton()->add_control_to_menu_panel(spatial_editor_hb);
- Label *fl = memnew(Label);
- fl->set_text(TTR("Floor:"));
- spatial_editor_hb->add_child(fl);
+ spin_box_label = memnew(Label);
+ spin_box_label->set_text(TTR("Floor:"));
+ spatial_editor_hb->add_child(spin_box_label);
floor = memnew(SpinBox);
floor->set_min(-32767);
diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h
index 3fc92bf7aa..9651770528 100644
--- a/modules/gridmap/grid_map_editor_plugin.h
+++ b/modules/gridmap/grid_map_editor_plugin.h
@@ -82,6 +82,7 @@ class GridMapEditor : public VBoxContainer {
ConfirmationDialog *settings_dialog;
VBoxContainer *settings_vbc;
SpinBox *settings_pick_distance;
+ Label *spin_box_label;
struct SetItem {
diff --git a/modules/mbedtls/SCsub b/modules/mbedtls/SCsub
new file mode 100755
index 0000000000..b846ae38ad
--- /dev/null
+++ b/modules/mbedtls/SCsub
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+
+Import('env')
+Import('env_modules')
+
+env_mbed_tls = env_modules.Clone()
+
+if env['builtin_mbedtls']:
+ # Thirdparty source files
+ thirdparty_sources = [
+ "aes.c",
+ "aesni.c",
+ "arc4.c",
+ "asn1parse.c",
+ "asn1write.c",
+ "base64.c",
+ "bignum.c",
+ "blowfish.c",
+ "camellia.c",
+ "ccm.c",
+ "certs.c",
+ "cipher.c",
+ "cipher_wrap.c",
+ "cmac.c",
+ "ctr_drbg.c",
+ "debug.c",
+ "des.c",
+ "dhm.c",
+ "ecdh.c",
+ "ecdsa.c",
+ "ecjpake.c",
+ "ecp.c",
+ "ecp_curves.c",
+ "entropy.c",
+ "entropy_poll.c",
+ "error.c",
+ "gcm.c",
+ "havege.c",
+ "hmac_drbg.c",
+ "md2.c",
+ "md4.c",
+ "md5.c",
+ "md.c",
+ "md_wrap.c",
+ "memory_buffer_alloc.c",
+ "net_sockets.c",
+ "oid.c",
+ "padlock.c",
+ "pem.c",
+ "pk.c",
+ "pkcs11.c",
+ "pkcs12.c",
+ "pkcs5.c",
+ "pkparse.c",
+ "pk_wrap.c",
+ "pkwrite.c",
+ "platform.c",
+ "ripemd160.c",
+ "rsa.c",
+ "rsa_internal.c",
+ "sha1.c",
+ "sha256.c",
+ "sha512.c",
+ "ssl_cache.c",
+ "ssl_ciphersuites.c",
+ "ssl_cli.c",
+ "ssl_cookie.c",
+ "ssl_srv.c",
+ "ssl_ticket.c",
+ "ssl_tls.c",
+ "threading.c",
+ "timing.c",
+ "version.c",
+ "version_features.c",
+ "x509.c",
+ "x509_create.c",
+ "x509_crl.c",
+ "x509_crt.c",
+ "x509_csr.c",
+ "x509write_crt.c",
+ "x509write_csr.c",
+ "xtea.c"
+ ]
+
+ thirdparty_dir = "#thirdparty/mbedtls/library/"
+ thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+ env_mbed_tls.add_source_files(env.modules_sources, thirdparty_sources)
+ env_mbed_tls.Append(CPPPATH=["#thirdparty/mbedtls/include/"])
+
+# Module sources
+env_mbed_tls.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/openssl/config.py b/modules/mbedtls/config.py
index 5f133eba90..5f133eba90 100644..100755
--- a/modules/openssl/config.py
+++ b/modules/mbedtls/config.py
diff --git a/modules/openssl/register_types.cpp b/modules/mbedtls/register_types.cpp
index 916acc260e..8548275eec 100644..100755
--- a/modules/openssl/register_types.cpp
+++ b/modules/mbedtls/register_types.cpp
@@ -30,15 +30,15 @@
#include "register_types.h"
-#include "stream_peer_openssl.h"
+#include "stream_peer_mbed_tls.h"
-void register_openssl_types() {
+void register_mbedtls_types() {
- ClassDB::register_class<StreamPeerOpenSSL>();
- StreamPeerOpenSSL::initialize_ssl();
+ ClassDB::register_class<StreamPeerMbedTLS>();
+ StreamPeerMbedTLS::initialize_ssl();
}
-void unregister_openssl_types() {
+void unregister_mbedtls_types() {
- StreamPeerOpenSSL::finalize_ssl();
+ StreamPeerMbedTLS::finalize_ssl();
}
diff --git a/modules/openssl/register_types.h b/modules/mbedtls/register_types.h
index 94d917ca81..3da0b1f1a0 100644..100755
--- a/modules/openssl/register_types.h
+++ b/modules/mbedtls/register_types.h
@@ -28,5 +28,5 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-void register_openssl_types();
-void unregister_openssl_types();
+void register_mbedtls_types();
+void unregister_mbedtls_types();
diff --git a/modules/mbedtls/stream_peer_mbed_tls.cpp b/modules/mbedtls/stream_peer_mbed_tls.cpp
new file mode 100755
index 0000000000..4135eb40ff
--- /dev/null
+++ b/modules/mbedtls/stream_peer_mbed_tls.cpp
@@ -0,0 +1,325 @@
+/*************************************************************************/
+/* stream_peer_openssl.cpp */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+
+#include "stream_peer_mbed_tls.h"
+
+static void my_debug(void *ctx, int level,
+ const char *file, int line,
+ const char *str) {
+
+ printf("%s:%04d: %s", file, line, str);
+ fflush(stdout);
+}
+
+void _print_error(int ret) {
+ printf("mbedtls error: returned -0x%x\n\n", -ret);
+ fflush(stdout);
+}
+
+int StreamPeerMbedTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) {
+
+ if (buf == NULL || len <= 0) return 0;
+
+ StreamPeerMbedTLS *sp = (StreamPeerMbedTLS *)ctx;
+
+ ERR_FAIL_COND_V(sp == NULL, 0);
+
+ int sent;
+ Error err = sp->base->put_partial_data((const uint8_t *)buf, len, sent);
+ if (err != OK) {
+ return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
+ }
+ if (sent == 0) {
+ return MBEDTLS_ERR_SSL_WANT_WRITE;
+ }
+ return sent;
+}
+
+int StreamPeerMbedTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) {
+
+ if (buf == NULL || len <= 0) return 0;
+
+ StreamPeerMbedTLS *sp = (StreamPeerMbedTLS *)ctx;
+
+ ERR_FAIL_COND_V(sp == NULL, 0);
+
+ int got;
+ Error err = sp->base->get_partial_data((uint8_t *)buf, len, got);
+ if (err != OK) {
+ return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
+ }
+ if (got == 0) {
+ return MBEDTLS_ERR_SSL_WANT_READ;
+ }
+ return got;
+}
+
+Error StreamPeerMbedTLS::connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs, const String &p_for_hostname) {
+
+ base = p_base;
+ int ret = 0;
+ int authmode = p_validate_certs ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_NONE;
+
+ mbedtls_ssl_init(&ssl);
+ mbedtls_ssl_config_init(&conf);
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+ mbedtls_entropy_init(&entropy);
+
+ ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
+ if (ret != 0) {
+ ERR_PRINTS(" failed\n ! mbedtls_ctr_drbg_seed returned an error" + itos(ret));
+ return FAILED;
+ }
+
+ mbedtls_ssl_config_defaults(&conf,
+ MBEDTLS_SSL_IS_CLIENT,
+ MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT);
+
+ mbedtls_ssl_conf_authmode(&conf, authmode);
+ mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
+ mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
+ mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
+ mbedtls_ssl_setup(&ssl, &conf);
+ mbedtls_ssl_set_hostname(&ssl, p_for_hostname.utf8().get_data());
+
+ mbedtls_ssl_set_bio(&ssl, this, bio_send, bio_recv, NULL);
+
+ while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ ERR_PRINTS("TLS handshake error: " + itos(ret));
+ _print_error(ret);
+ status = STATUS_ERROR_HOSTNAME_MISMATCH;
+ return FAILED;
+ }
+ }
+
+ connected = true;
+ status = STATUS_CONNECTED;
+
+ return OK;
+}
+
+Error StreamPeerMbedTLS::accept_stream(Ref<StreamPeer> p_base) {
+
+ return ERR_UNAVAILABLE;
+}
+
+Error StreamPeerMbedTLS::put_data(const uint8_t *p_data, int p_bytes) {
+
+ ERR_FAIL_COND_V(!connected, ERR_UNCONFIGURED);
+
+ Error err;
+ int sent = 0;
+
+ while (p_bytes > 0) {
+ err = put_partial_data(p_data, p_bytes, sent);
+
+ if (err != OK) {
+ return err;
+ }
+
+ p_data += sent;
+ p_bytes -= sent;
+ }
+
+ return OK;
+}
+
+Error StreamPeerMbedTLS::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) {
+
+ ERR_FAIL_COND_V(!connected, ERR_UNCONFIGURED);
+
+ r_sent = 0;
+
+ if (p_bytes == 0)
+ return OK;
+
+ int ret = mbedtls_ssl_write(&ssl, p_data, p_bytes);
+ if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+ ret = 0; // non blocking io
+ } else if (ret <= 0) {
+ _print_error(ret);
+ disconnect_from_stream();
+ return ERR_CONNECTION_ERROR;
+ }
+
+ r_sent = ret;
+ return OK;
+}
+
+Error StreamPeerMbedTLS::get_data(uint8_t *p_buffer, int p_bytes) {
+
+ ERR_FAIL_COND_V(!connected, ERR_UNCONFIGURED);
+
+ Error err;
+
+ int got = 0;
+ while (p_bytes > 0) {
+
+ err = get_partial_data(p_buffer, p_bytes, got);
+
+ if (err != OK) {
+ return err;
+ }
+
+ p_buffer += got;
+ p_bytes -= got;
+ }
+
+ return OK;
+}
+
+Error StreamPeerMbedTLS::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) {
+
+ ERR_FAIL_COND_V(!connected, ERR_UNCONFIGURED);
+
+ r_received = 0;
+
+ int ret = mbedtls_ssl_read(&ssl, p_buffer, p_bytes);
+ if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+ ret = 0; // non blocking io
+ } else if (ret <= 0) {
+ _print_error(ret);
+ disconnect_from_stream();
+ return ERR_CONNECTION_ERROR;
+ }
+
+ r_received = ret;
+ return OK;
+}
+
+void StreamPeerMbedTLS::poll() {
+
+ ERR_FAIL_COND(!connected);
+ ERR_FAIL_COND(!base.is_valid());
+
+ int ret = mbedtls_ssl_read(&ssl, NULL, 0);
+
+ if (ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ _print_error(ret);
+ disconnect_from_stream();
+ return;
+ }
+}
+
+int StreamPeerMbedTLS::get_available_bytes() const {
+
+ ERR_FAIL_COND_V(!connected, 0);
+
+ return mbedtls_ssl_get_bytes_avail(&ssl);
+}
+StreamPeerMbedTLS::StreamPeerMbedTLS() {
+
+ connected = false;
+ status = STATUS_DISCONNECTED;
+}
+
+StreamPeerMbedTLS::~StreamPeerMbedTLS() {
+ disconnect_from_stream();
+}
+
+void StreamPeerMbedTLS::disconnect_from_stream() {
+
+ if (!connected)
+ return;
+
+ mbedtls_ssl_free(&ssl);
+ mbedtls_ssl_config_free(&conf);
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&entropy);
+
+ base = Ref<StreamPeer>();
+ connected = false;
+ status = STATUS_DISCONNECTED;
+}
+
+StreamPeerMbedTLS::Status StreamPeerMbedTLS::get_status() const {
+
+ return status;
+}
+
+StreamPeerSSL *StreamPeerMbedTLS::_create_func() {
+
+ return memnew(StreamPeerMbedTLS);
+}
+
+mbedtls_x509_crt StreamPeerMbedTLS::cacert;
+
+void StreamPeerMbedTLS::_load_certs(const PoolByteArray &p_array) {
+ int arr_len = p_array.size();
+ PoolByteArray::Read r = p_array.read();
+ int err = mbedtls_x509_crt_parse(&cacert, &r[0], arr_len);
+ if (err != 0) {
+ WARN_PRINTS("Error parsing some certificates: " + itos(err));
+ }
+}
+
+void StreamPeerMbedTLS::initialize_ssl() {
+
+ _create = _create_func;
+ load_certs_func = _load_certs;
+
+ mbedtls_x509_crt_init(&cacert);
+
+#ifdef DEBUG_ENABLED
+ mbedtls_debug_set_threshold(1);
+#endif
+
+ String certs_path = GLOBAL_DEF("network/ssl/certificates", "");
+ ProjectSettings::get_singleton()->set_custom_property_info("network/ssl/certificates", PropertyInfo(Variant::STRING, "network/ssl/certificates", PROPERTY_HINT_FILE, "*.crt"));
+
+ if (certs_path != "") {
+
+ FileAccess *f = FileAccess::open(certs_path, FileAccess::READ);
+ if (f) {
+ PoolByteArray arr;
+ int flen = f->get_len();
+ arr.resize(flen + 1);
+ {
+ PoolByteArray::Write w = arr.write();
+ f->get_buffer(w.ptr(), flen);
+ w[flen] = 0; //end f string
+ }
+
+ memdelete(f);
+
+ _load_certs(arr);
+ print_line("Loaded certs from '" + certs_path);
+ }
+ }
+
+ available = true;
+}
+
+void StreamPeerMbedTLS::finalize_ssl() {
+
+ mbedtls_x509_crt_free(&cacert);
+}
diff --git a/modules/openssl/stream_peer_openssl.h b/modules/mbedtls/stream_peer_mbed_tls.h
index 29c8647e58..ce17614d85 100644..100755
--- a/modules/openssl/stream_peer_openssl.h
+++ b/modules/mbedtls/stream_peer_mbed_tls.h
@@ -35,63 +35,42 @@
#include "os/file_access.h"
#include "project_settings.h"
-#include "thirdparty/misc/curl_hostcheck.h"
-
-#include <openssl/bio.h> // BIO objects for I/O
-#include <openssl/err.h> // Error reporting
-#include <openssl/ssl.h> // SSL and SSL_CTX for SSL connections
-#include <openssl/x509v3.h>
+#include "mbedtls/config.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/net.h"
+#include "mbedtls/ssl.h"
#include <stdio.h>
+#include <stdlib.h>
-class StreamPeerOpenSSL : public StreamPeerSSL {
+class StreamPeerMbedTLS : public StreamPeerSSL {
private:
- static int _bio_create(BIO *b);
- static int _bio_destroy(BIO *b);
- static int _bio_read(BIO *b, char *buf, int len);
- static int _bio_write(BIO *b, const char *buf, int len);
- static long _bio_ctrl(BIO *b, int cmd, long num, void *ptr);
- static int _bio_gets(BIO *b, char *buf, int len);
- static int _bio_puts(BIO *b, const char *str);
-
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
- static BIO_METHOD *_bio_method;
-#else
- static BIO_METHOD _bio_method;
-#endif
- static BIO_METHOD *_get_bio_method();
-
- static bool _match_host_name(const char *name, const char *hostname);
- static Error _match_common_name(const char *hostname, const X509 *server_cert);
- static Error _match_subject_alternative_name(const char *hostname, const X509 *server_cert);
-
- static int _cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg);
-
Status status;
String hostname;
- int max_cert_chain_depth;
- SSL_CTX *ctx;
- SSL *ssl;
- BIO *bio;
+
bool connected;
- int flags;
- bool use_blocking;
- bool validate_certs;
- bool validate_hostname;
Ref<StreamPeer> base;
static StreamPeerSSL *_create_func();
- void _print_error(int err);
-
- static Vector<X509 *> certs;
-
static void _load_certs(const PoolByteArray &p_array);
+ static int bio_recv(void *ctx, unsigned char *buf, size_t len);
+ static int bio_send(void *ctx, const unsigned char *buf, size_t len);
+
protected:
+ static mbedtls_x509_crt cacert;
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_ssl_context ssl;
+ mbedtls_ssl_config conf;
+
static void _bind_methods();
public:
+ virtual void poll();
virtual Error accept_stream(Ref<StreamPeer> p_base);
virtual Error connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs = false, const String &p_for_hostname = String());
virtual Status get_status() const;
@@ -109,8 +88,8 @@ public:
static void initialize_ssl();
static void finalize_ssl();
- StreamPeerOpenSSL();
- ~StreamPeerOpenSSL();
+ StreamPeerMbedTLS();
+ ~StreamPeerMbedTLS();
};
#endif // STREAM_PEER_SSL_H
diff --git a/modules/mobile_vr/doc_classes/MobileVRInterface.xml b/modules/mobile_vr/doc_classes/MobileVRInterface.xml
index 5d3da0672e..d3f2548320 100644
--- a/modules/mobile_vr/doc_classes/MobileVRInterface.xml
+++ b/modules/mobile_vr/doc_classes/MobileVRInterface.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MobileVRInterface" inherits="ARVRInterface" category="Core" version="3.0-beta">
+<class name="MobileVRInterface" inherits="ARVRInterface" category="Core" version="3.1-dev">
<brief_description>
Generic mobile VR implementation
</brief_description>
diff --git a/modules/mobile_vr/mobile_interface.cpp b/modules/mobile_vr/mobile_interface.cpp
index 07a81e07b0..6b1c7eb279 100644
--- a/modules/mobile_vr/mobile_interface.cpp
+++ b/modules/mobile_vr/mobile_interface.cpp
@@ -345,7 +345,7 @@ Transform MobileVRInterface::get_transform_for_eye(ARVRInterface::Eyes p_eye, co
if (initialized) {
float world_scale = arvr_server->get_world_scale();
- // we don't need to check for the existance of our HMD, doesn't effect our values...
+ // we don't need to check for the existence of our HMD, doesn't effect our values...
// note * 0.01 to convert cm to m and * 0.5 as we're moving half in each direction...
if (p_eye == ARVRInterface::EYE_LEFT) {
transform_for_eye.origin.x = -(intraocular_dist * 0.01 * 0.5 * world_scale);
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
index 63fae194f4..a1dfcf6377 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -31,11 +31,18 @@ def make_cs_files_header(src, dst):
if i > 0:
header.write(', ')
header.write(byte_to_str(buf[buf_idx]))
- inserted_files += '\tr_files.insert(\"' + file + '\", ' \
+ inserted_files += '\tr_files.insert("' + file + '", ' \
'CompressedFile(_cs_' + name + '_compressed_size, ' \
'_cs_' + name + '_uncompressed_size, ' \
'_cs_' + name + '_compressed));\n'
header.write(' };\n')
+ version_file = os.path.join(src, 'VERSION.txt')
+ with open(version_file, 'r') as content_file:
+ try:
+ glue_version = int(content_file.read()) # make sure the format is valid
+ header.write('\n#define CS_GLUE_VERSION UINT32_C(' + str(glue_version) + ')\n')
+ except ValueError:
+ raise ValueError('Invalid C# glue version in: ' + version_file)
header.write('\nstruct CompressedFile\n' '{\n'
'\tint compressed_size;\n' '\tint uncompressed_size;\n' '\tconst unsigned char* data;\n'
'\n\tCompressedFile(int p_comp_size, int p_uncomp_size, const unsigned char* p_data)\n'
@@ -57,10 +64,10 @@ if env['tools']:
vars = Variables()
vars.Add(BoolVariable('mono_glue', 'Build with the mono glue sources', True))
vars.Add(BoolVariable('xbuild_fallback', 'If MSBuild is not found, fallback to xbuild', False))
-vars.Update(env)
+vars.Update(env_mono)
# Glue sources
-if env['mono_glue']:
+if env_mono['mono_glue']:
env_mono.add_source_files(env.modules_sources, 'glue/*.cpp')
else:
env_mono.Append(CPPDEFINES=['MONO_GLUE_DISABLED'])
@@ -80,23 +87,23 @@ def find_msbuild_unix(filename):
import sys
hint_dirs = ['/opt/novell/mono/bin']
- if sys.platform == "darwin":
+ if sys.platform == 'darwin':
hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current/bin'] + hint_dirs
for hint_dir in hint_dirs:
hint_path = os.path.join(hint_dir, filename)
if os.path.isfile(hint_path):
return hint_path
- elif os.path.isfile(hint_path + ".exe"):
- return hint_path + ".exe"
+ elif os.path.isfile(hint_path + '.exe'):
+ return hint_path + '.exe'
- for hint_dir in os.environ["PATH"].split(os.pathsep):
+ for hint_dir in os.environ['PATH'].split(os.pathsep):
hint_dir = hint_dir.strip('"')
hint_path = os.path.join(hint_dir, filename)
if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
return hint_path
- if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK):
- return hint_path + ".exe"
+ if os.path.isfile(hint_path + '.exe') and os.access(hint_path + '.exe', os.X_OK):
+ return hint_path + '.exe'
return None
@@ -152,7 +159,7 @@ def mono_build_solution(source, target, env):
xbuild_fallback = env['xbuild_fallback']
if xbuild_fallback and os.name == 'nt':
- print("Option 'xbuild_fallback' not supported on Windows")
+ print('Option \'xbuild_fallback\' not supported on Windows')
xbuild_fallback = False
if xbuild_fallback:
diff --git a/modules/mono/config.py b/modules/mono/config.py
index 7805b35983..331449a13f 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -160,6 +160,7 @@ def configure(env):
mono_so_name = ''
tmpenv = Environment()
+ tmpenv.AppendENVPath('PKG_CONFIG_PATH', os.getenv('PKG_CONFIG_PATH'))
tmpenv.ParseConfig('pkg-config monosgen-2 --libs-only-L')
for hint_dir in tmpenv['LIBPATH']:
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 7df2043a62..525b918b1f 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -118,6 +118,8 @@ void CSharpLanguage::init() {
#ifdef TOOLS_ENABLED
EditorNode::add_init_callback(&gdsharp_editor_init_callback);
+
+ GLOBAL_DEF("mono/export/include_scripts_content", true);
#endif
}
@@ -176,7 +178,7 @@ void CSharpLanguage::get_reserved_words(List<String> *p_words) const {
"fixed",
"float",
"for",
- "forech",
+ "foreach",
"goto",
"if",
"implicit",
@@ -222,14 +224,17 @@ void CSharpLanguage::get_reserved_words(List<String> *p_words) const {
"ushort",
"using",
"virtual",
- "volatile",
"void",
+ "volatile",
"while",
// Contextual keywords. Not reserved words, but I guess we should include
// them because this seems to be used only for syntax highlighting.
"add",
+ "alias",
"ascending",
+ "async",
+ "await",
"by",
"descending",
"dynamic",
@@ -238,10 +243,10 @@ void CSharpLanguage::get_reserved_words(List<String> *p_words) const {
"get",
"global",
"group",
- "in",
"into",
"join",
"let",
+ "nameof",
"on",
"orderby",
"partial",
@@ -250,6 +255,7 @@ void CSharpLanguage::get_reserved_words(List<String> *p_words) const {
"set",
"value",
"var",
+ "when",
"where",
"yield",
0
@@ -447,9 +453,10 @@ String CSharpLanguage::_get_indentation() const {
Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() {
+#ifdef DEBUG_ENABLED
// Printing an error here will result in endless recursion, so we must be careful
- if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_api_assembly() || !GDMonoUtils::mono_cache.corlib_cache_updated)
+ if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_core_api_assembly() || !GDMonoUtils::mono_cache.corlib_cache_updated)
return Vector<StackInfo>();
MonoObject *stack_trace = mono_object_new(mono_domain_get(), CACHED_CLASS(System_Diagnostics_StackTrace)->get_mono_ptr());
@@ -463,8 +470,12 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info()
si = stack_trace_get_info(stack_trace);
return si;
+#else
+ return Vector<StackInfo>();
+#endif
}
+#ifdef DEBUG_ENABLED
Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObject *p_stack_trace) {
// Printing an error here could result in endless recursion, so we must be careful
@@ -514,6 +525,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
return si;
}
+#endif
void CSharpLanguage::frame() {
@@ -711,8 +723,10 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) {
for (Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) {
Ref<CSharpScript> scr = E->key();
+ scr->signals_invalidated = true;
scr->exports_invalidated = true;
scr->reload(p_soft_reload);
+ scr->update_signals();
scr->update_exports();
//restore state if saved
@@ -745,8 +759,10 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) {
//if instance states were saved, set them!
}
- if (Engine::get_singleton()->is_editor_hint())
+ if (Engine::get_singleton()->is_editor_hint()) {
EditorNode::get_singleton()->get_property_editor()->update_tree();
+ NodeDock::singleton->update_lists();
+ }
}
#endif
@@ -941,19 +957,6 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) {
#endif
}
-void CSharpInstance::_ml_call_reversed(MonoObject *p_mono_object, GDMonoClass *p_klass, const StringName &p_method, const Variant **p_args, int p_argcount) {
-
- GDMonoClass *base = p_klass->get_parent_class();
- if (base && base != script->native)
- _ml_call_reversed(p_mono_object, base, p_method, p_args, p_argcount);
-
- GDMonoMethod *method = p_klass->get_method(p_method, p_argcount);
-
- if (method) {
- method->invoke(p_mono_object, p_args);
- }
-}
-
CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const Ref<MonoGCHandle> &p_gchandle) {
CSharpInstance *instance = memnew(CSharpInstance);
@@ -1022,6 +1025,8 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) {
if (ret && GDMonoMarshal::unbox<MonoBoolean>(ret) == true)
return true;
+
+ break;
}
top = top->get_parent_class();
@@ -1044,7 +1049,7 @@ bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const {
if (field) {
MonoObject *value = field->get_value(mono_object);
- r_ret = GDMonoMarshal::mono_object_to_variant(value, field->get_type());
+ r_ret = GDMonoMarshal::mono_object_to_variant(value);
return true;
}
@@ -1057,7 +1062,7 @@ bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const {
r_ret = Variant();
GDMonoUtils::print_unhandled_exception(exc);
} else {
- r_ret = GDMonoMarshal::mono_object_to_variant(value, property->get_type());
+ r_ret = GDMonoMarshal::mono_object_to_variant(value);
}
return true;
}
@@ -1082,6 +1087,8 @@ bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const {
r_ret = GDMonoMarshal::mono_object_to_variant(ret);
return true;
}
+
+ break;
}
top = top->get_parent_class();
@@ -1133,10 +1140,13 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args,
MonoObject *mono_object = get_mono_object();
- ERR_FAIL_NULL_V(mono_object, Variant());
+ if (!mono_object) {
+ r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ ERR_FAIL_V(Variant());
+ }
if (!script.is_valid())
- return Variant();
+ ERR_FAIL_V(Variant());
GDMonoClass *top = script->script_class;
@@ -1146,8 +1156,10 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args,
if (method) {
MonoObject *return_value = method->invoke(mono_object, p_args);
+ r_error.error = Variant::CallError::CALL_OK;
+
if (return_value) {
- return GDMonoMarshal::mono_object_to_variant(return_value, method->get_return_type());
+ return GDMonoMarshal::mono_object_to_variant(return_value);
} else {
return Variant();
}
@@ -1179,8 +1191,10 @@ void CSharpInstance::_call_multilevel(MonoObject *p_mono_object, const StringNam
while (top && top != script->native) {
GDMonoMethod *method = top->get_method(p_method, p_argcount);
- if (method)
+ if (method) {
method->invoke(p_mono_object, p_args);
+ return;
+ }
top = top->get_parent_class();
}
@@ -1188,13 +1202,9 @@ void CSharpInstance::_call_multilevel(MonoObject *p_mono_object, const StringNam
void CSharpInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) {
- if (script.is_valid()) {
- MonoObject *mono_object = get_mono_object();
-
- ERR_FAIL_NULL(mono_object);
+ // Sorry, the method is the one that controls the call order
- _ml_call_reversed(mono_object, script->script_class, p_method, p_args, p_argcount);
- }
+ call_multilevel(p_method, p_args, p_argcount);
}
void CSharpInstance::_reference_owner_unsafe() {
@@ -1541,6 +1551,75 @@ bool CSharpScript::_update_exports() {
return false;
}
+bool CSharpScript::_update_signals() {
+ if (!valid)
+ return false;
+
+ bool changed = false;
+
+ if (signals_invalidated) {
+ signals_invalidated = false;
+
+ GDMonoClass *top = script_class;
+
+ _signals.clear();
+ changed = true; // TODO Do a real check for change
+
+ while (top && top != native) {
+ const Vector<GDMonoClass *> &delegates = top->get_all_delegates();
+ for (int i = delegates.size() - 1; i >= 0; --i) {
+ Vector<Argument> parameters;
+
+ GDMonoClass *delegate = delegates[i];
+
+ if (_get_signal(top, delegate, parameters)) {
+ _signals[delegate->get_name()] = parameters;
+ }
+ }
+
+ top = top->get_parent_class();
+ }
+ }
+
+ return changed;
+}
+
+bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> &params) {
+ if (p_delegate->has_attribute(CACHED_CLASS(SignalAttribute))) {
+ MonoType *raw_type = GDMonoClass::get_raw_type(p_delegate);
+
+ if (mono_type_get_type(raw_type) == MONO_TYPE_CLASS) {
+ // Arguments are accessibles as arguments of .Invoke method
+ GDMonoMethod *invoke = p_delegate->get_method("Invoke", -1);
+
+ Vector<StringName> names;
+ Vector<ManagedType> types;
+ invoke->get_parameter_names(names);
+ invoke->get_parameter_types(types);
+
+ if (names.size() == types.size()) {
+ for (int i = 0; i < names.size(); ++i) {
+ Argument arg;
+ arg.name = names[i];
+ arg.type = GDMonoMarshal::managed_to_variant_type(types[i]);
+
+ if (arg.type == Variant::NIL) {
+ ERR_PRINTS("Unknown type of signal parameter: " + arg.name + " in " + p_class->get_full_name());
+ return false;
+ }
+
+ params.push_back(arg);
+ }
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+#ifdef TOOLS_ENABLED
bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported) {
StringName name = p_member->get_name();
@@ -1611,6 +1690,7 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p
return true;
}
+#endif
void CSharpScript::_clear() {
@@ -1633,7 +1713,7 @@ Variant CSharpScript::call(const StringName &p_method, const Variant **p_args, i
MonoObject *result = method->invoke(NULL, p_args);
if (result) {
- return GDMonoMarshal::mono_object_to_variant(result, method->get_return_type());
+ return GDMonoMarshal::mono_object_to_variant(result);
} else {
return Variant();
}
@@ -1860,12 +1940,15 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) {
PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(CSharpLanguage::get_singleton(), Ref<Script>(this), p_this));
placeholders.insert(si);
_update_exports();
+ _update_signals();
return si;
#else
return NULL;
#endif
}
+ update_signals();
+
if (native) {
String native_name = native->get_name();
if (!ClassDB::is_parent_class(p_this->get_class_name(), native_name)) {
@@ -2029,6 +2112,31 @@ void CSharpScript::update_exports() {
#endif
}
+bool CSharpScript::has_script_signal(const StringName &p_signal) const {
+ if (_signals.has(p_signal))
+ return true;
+
+ return false;
+}
+
+void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
+ for (const Map<StringName, Vector<Argument> >::Element *E = _signals.front(); E; E = E->next()) {
+ MethodInfo mi;
+
+ mi.name = E->key();
+ for (int i = 0; i < E->get().size(); i++) {
+ PropertyInfo arg;
+ arg.name = E->get()[i].name;
+ mi.arguments.push_back(arg);
+ }
+ r_signals->push_back(mi);
+ }
+}
+
+void CSharpScript::update_signals() {
+ _update_signals();
+}
+
Ref<Script> CSharpScript::get_base_script() const {
// TODO search in metadata file once we have it, not important any way?
@@ -2093,6 +2201,7 @@ CSharpScript::CSharpScript() :
#ifdef TOOLS_ENABLED
source_changed_cache = false;
exports_invalidated = true;
+ signals_invalidated = true;
#endif
_resource_path_changed();
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 3ce8a9b64e..1f609627de 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -85,13 +85,20 @@ class CSharpScript : public Script {
SelfList<CSharpScript> script_list;
+ struct Argument {
+ String name;
+ Variant::Type type;
+ };
+
+ Map<StringName, Vector<Argument> > _signals;
+ bool signals_invalidated;
+
#ifdef TOOLS_ENABLED
List<PropertyInfo> exported_members_cache; // members_cache
Map<StringName, Variant> exported_members_defval_cache; // member_default_values_cache
Set<PlaceHolderScriptInstance *> placeholders;
bool source_changed_cache;
bool exports_invalidated;
-
void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames);
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder);
#endif
@@ -104,8 +111,13 @@ class CSharpScript : public Script {
void _clear();
+ bool _update_signals();
+ bool _get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> &params);
+
bool _update_exports();
+#ifdef TOOLS_ENABLED
bool _get_member_export(GDMonoClass *p_class, GDMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported);
+#endif
CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error);
Variant _new(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
@@ -135,8 +147,9 @@ public:
virtual Error reload(bool p_keep_state = false);
- /* TODO */ virtual bool has_script_signal(const StringName &p_signal) const { return false; }
- /* TODO */ virtual void get_script_signal_list(List<MethodInfo> *r_signals) const {}
+ virtual bool has_script_signal(const StringName &p_signal) const;
+ virtual void get_script_signal_list(List<MethodInfo> *r_signals) const;
+ virtual void update_signals();
/* TODO */ virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const;
virtual void get_script_property_list(List<PropertyInfo> *p_list) const;
@@ -170,8 +183,6 @@ class CSharpInstance : public ScriptInstance {
bool base_ref;
bool ref_dying;
- void _ml_call_reversed(MonoObject *p_mono_object, GDMonoClass *klass, const StringName &p_method, const Variant **p_args, int p_argcount);
-
void _reference_owner_unsafe();
void _unreference_owner_unsafe();
@@ -335,7 +346,9 @@ public:
virtual void *alloc_instance_binding_data(Object *p_object);
virtual void free_instance_binding_data(void *p_data);
+#ifdef DEBUG_ENABLED
Vector<StackInfo> stack_trace_get_info(MonoObject *p_stack_trace);
+#endif
CSharpLanguage();
~CSharpLanguage();
diff --git a/modules/mono/doc_classes/@C#.xml b/modules/mono/doc_classes/@C#.xml
index 5fcbf36a2b..0c2bb948ea 100644
--- a/modules/mono/doc_classes/@C#.xml
+++ b/modules/mono/doc_classes/@C#.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="@C#" category="Core" version="3.0-beta">
+<class name="@C#" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/mono/doc_classes/CSharpScript.xml b/modules/mono/doc_classes/CSharpScript.xml
index 853ef28731..9bd57f1d4d 100644
--- a/modules/mono/doc_classes/CSharpScript.xml
+++ b/modules/mono/doc_classes/CSharpScript.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSharpScript" inherits="Script" category="Core" version="3.0-beta">
+<class name="CSharpScript" inherits="Script" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/mono/doc_classes/GodotSharp.xml b/modules/mono/doc_classes/GodotSharp.xml
index 2696a0bb4b..51f07523e7 100644
--- a/modules/mono/doc_classes/GodotSharp.xml
+++ b/modules/mono/doc_classes/GodotSharp.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GodotSharp" inherits="Object" category="Core" version="3.0-beta">
+<class name="GodotSharp" inherits="Object" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 800e3b723b..315c1e2f1c 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -70,8 +70,6 @@
#define LOCAL_RET "ret"
-#define CS_CLASS_NATIVECALLS "NativeCalls"
-#define CS_CLASS_NATIVECALLS_EDITOR "EditorNativeCalls"
#define CS_FIELD_MEMORYOWN "memoryOwn"
#define CS_PARAM_METHODBIND "method"
#define CS_PARAM_INSTANCE "ptr"
@@ -105,6 +103,8 @@
#define C_METHOD_MANAGED_TO_DICT C_NS_MONOMARSHAL "::mono_object_to_Dictionary"
#define C_METHOD_MANAGED_FROM_DICT C_NS_MONOMARSHAL "::Dictionary_to_mono_object"
+#define BINDINGS_GENERATOR_VERSION UINT32_C(1)
+
const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN = "\t%0 %1_in = %1;\n";
bool BindingsGenerator::verbose_output = false;
@@ -250,8 +250,15 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
const TypeInterface *return_type = _get_type_by_name_or_placeholder(imethod.return_type);
- String im_sig = "IntPtr " CS_PARAM_METHODBIND ", IntPtr " CS_PARAM_INSTANCE;
- String im_unique_sig = imethod.return_type.operator String() + ",IntPtr,IntPtr";
+ String im_sig;
+ String im_unique_sig;
+
+ if (p_itype.is_object_type) {
+ im_sig += "IntPtr " CS_PARAM_METHODBIND ", ";
+ im_unique_sig += imethod.return_type.operator String() + ",IntPtr,IntPtr";
+ }
+
+ im_sig += "IntPtr " CS_PARAM_INSTANCE;
// Get arguments information
int i = 0;
@@ -263,25 +270,37 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
im_sig += " arg";
im_sig += itos(i + 1);
- im_unique_sig += ",";
- im_unique_sig += get_unique_sig(*arg_type);
+ if (p_itype.is_object_type) {
+ im_unique_sig += ",";
+ im_unique_sig += get_unique_sig(*arg_type);
+ }
i++;
}
- // godot_icall_{argc}_{icallcount}
- String icall_method = ICALL_PREFIX + itos(imethod.arguments.size()) + "_" + itos(method_icalls.size());
+ String icall_method = ICALL_PREFIX;
+
+ if (p_itype.is_object_type) {
+ icall_method += itos(imethod.arguments.size()) + "_" + itos(method_icalls.size()); // godot_icall_{argc}_{icallcount}
+ } else {
+ icall_method += p_itype.name + "_" + imethod.name; // godot_icall_{Type}_{method}
+ }
InternalCall im_icall = InternalCall(p_itype.api_type, icall_method, return_type->im_type_out, im_sig, im_unique_sig);
- List<InternalCall>::Element *match = method_icalls.find(im_icall);
+ if (p_itype.is_object_type) {
+ List<InternalCall>::Element *match = method_icalls.find(im_icall);
- if (match) {
- if (p_itype.api_type != ClassDB::API_EDITOR)
- match->get().editor_only = false;
- method_icalls_map.insert(&E->get(), &match->get());
+ if (match) {
+ if (p_itype.api_type != ClassDB::API_EDITOR)
+ match->get().editor_only = false;
+ method_icalls_map.insert(&E->get(), &match->get());
+ } else {
+ List<InternalCall>::Element *added = method_icalls.push_back(im_icall);
+ method_icalls_map.insert(&E->get(), &added->get());
+ }
} else {
- List<InternalCall>::Element *added = method_icalls.push_back(im_icall);
+ List<InternalCall>::Element *added = builtin_method_icalls.push_back(im_icall);
method_icalls_map.insert(&E->get(), &added->get());
}
}
@@ -510,7 +529,15 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo
"using System.Collections.Generic;\n"
"\n");
cs_icalls_content.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
- cs_icalls_content.push_back(INDENT1 "internal static class " CS_CLASS_NATIVECALLS "\n" INDENT1 OPEN_BLOCK);
+ cs_icalls_content.push_back(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS "\n" INDENT1 OPEN_BLOCK);
+
+ cs_icalls_content.push_back(INDENT2 "internal static ulong godot_api_hash = ");
+ cs_icalls_content.push_back(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + ";\n");
+ cs_icalls_content.push_back(INDENT2 "internal static uint bindings_version = ");
+ cs_icalls_content.push_back(String::num_uint64(BINDINGS_GENERATOR_VERSION) + ";\n");
+ cs_icalls_content.push_back(INDENT2 "internal static uint cs_glue_version = ");
+ cs_icalls_content.push_back(String::num_uint64(CS_GLUE_VERSION) + ";\n");
+ cs_icalls_content.push_back("\n");
#define ADD_INTERNAL_CALL(m_icall) \
if (!m_icall.editor_only) { \
@@ -525,12 +552,14 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo
ADD_INTERNAL_CALL(E->get());
for (const List<InternalCall>::Element *E = method_icalls.front(); E; E = E->next())
ADD_INTERNAL_CALL(E->get());
+ for (const List<InternalCall>::Element *E = builtin_method_icalls.front(); E; E = E->next())
+ ADD_INTERNAL_CALL(E->get());
#undef ADD_INTERNAL_CALL
cs_icalls_content.push_back(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
- String internal_methods_file = path_join(core_dir, CS_CLASS_NATIVECALLS ".cs");
+ String internal_methods_file = path_join(core_dir, BINDINGS_CLASS_NATIVECALLS ".cs");
Error err = _save_file(internal_methods_file, cs_icalls_content);
if (err != OK)
@@ -605,7 +634,15 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir,
"using System.Collections.Generic;\n"
"\n");
cs_icalls_content.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
- cs_icalls_content.push_back(INDENT1 "internal static class " CS_CLASS_NATIVECALLS_EDITOR "\n" INDENT1 OPEN_BLOCK);
+ cs_icalls_content.push_back(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS_EDITOR "\n" INDENT1 OPEN_BLOCK);
+
+ cs_icalls_content.push_back(INDENT2 "internal static ulong godot_api_hash = ");
+ cs_icalls_content.push_back(String::num_uint64(GDMono::get_singleton()->get_api_editor_hash()) + ";\n");
+ cs_icalls_content.push_back(INDENT2 "internal static uint bindings_version = ");
+ cs_icalls_content.push_back(String::num_uint64(BINDINGS_GENERATOR_VERSION) + ";\n");
+ cs_icalls_content.push_back(INDENT2 "internal static uint cs_glue_version = ");
+ cs_icalls_content.push_back(String::num_uint64(CS_GLUE_VERSION) + ";\n");
+ cs_icalls_content.push_back("\n");
#define ADD_INTERNAL_CALL(m_icall) \
if (m_icall.editor_only) { \
@@ -616,6 +653,8 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir,
cs_icalls_content.push_back(m_icall.im_sig + ");\n"); \
}
+ // No need to add builtin_method_icalls. Builtin types are core only
+
for (const List<InternalCall>::Element *E = editor_custom_icalls.front(); E; E = E->next())
ADD_INTERNAL_CALL(E->get());
for (const List<InternalCall>::Element *E = method_icalls.front(); E; E = E->next())
@@ -625,7 +664,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir,
cs_icalls_content.push_back(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
- String internal_methods_file = path_join(core_dir, CS_CLASS_NATIVECALLS_EDITOR ".cs");
+ String internal_methods_file = path_join(core_dir, BINDINGS_CLASS_NATIVECALLS_EDITOR ".cs");
Error err = _save_file(internal_methods_file, cs_icalls_content);
if (err != OK)
@@ -694,9 +733,9 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.push_back(itype.is_singleton ? "static class " : "class ");
output.push_back(itype.proxy_name);
- if (itype.is_singleton || !itype.is_object_type) {
+ if (itype.is_singleton) {
output.push_back("\n");
- } else if (!is_derived_type) {
+ } else if (!is_derived_type || !itype.is_object_type /* assuming only object types inherit */) {
output.push_back(" : IDisposable\n");
} else if (obj_types.has(itype.base_name)) {
output.push_back(" : ");
@@ -838,7 +877,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.push_back(MEMBER_BEGIN "public void Dispose()\n" OPEN_BLOCK_L2 "Dispose(true);\n" INDENT3 "GC.SuppressFinalize(this);\n" CLOSE_BLOCK_L2);
// Add the virtual Dispose
- output.push_back(MEMBER_BEGIN "public virtual void Dispose(bool disposing)\n" OPEN_BLOCK_L2
+ output.push_back(MEMBER_BEGIN "protected virtual void Dispose(bool disposing)\n" OPEN_BLOCK_L2
"if (disposed) return;\n" INDENT3
"if (" BINDINGS_PTR_FIELD " != IntPtr.Zero)\n" OPEN_BLOCK_L3 "NativeCalls.godot_icall_");
output.push_back(itype.proxy_name);
@@ -859,7 +898,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.push_back("\";\n");
output.push_back(INDENT2 "internal static IntPtr " BINDINGS_PTR_FIELD " = ");
- output.push_back(itype.api_type == ClassDB::API_EDITOR ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS);
+ output.push_back(itype.api_type == ClassDB::API_EDITOR ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS);
output.push_back("." ICALL_PREFIX);
output.push_back(itype.name);
output.push_back(SINGLETON_ICALL_SUFFIX "();\n");
@@ -889,7 +928,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// The engine will initialize the pointer field of the managed side before calling the constructor
// This is why we only allocate a new native object from the constructor if the pointer field is not set
output.push_back(")\n" OPEN_BLOCK_L2 "if (" BINDINGS_PTR_FIELD " == IntPtr.Zero)\n" INDENT4 BINDINGS_PTR_FIELD " = ");
- output.push_back(itype.api_type == ClassDB::API_EDITOR ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS);
+ output.push_back(itype.api_type == ClassDB::API_EDITOR ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS);
output.push_back("." + ctor_method);
output.push_back("(this);\n" CLOSE_BLOCK_L2);
} else {
@@ -929,11 +968,11 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.push_back(MEMBER_BEGIN "public void Dispose()\n" OPEN_BLOCK_L2 "Dispose(true);\n" INDENT3 "GC.SuppressFinalize(this);\n" CLOSE_BLOCK_L2);
// Add the virtual Dispose
- output.push_back(MEMBER_BEGIN "public virtual void Dispose(bool disposing)\n" OPEN_BLOCK_L2
+ output.push_back(MEMBER_BEGIN "protected virtual void Dispose(bool disposing)\n" OPEN_BLOCK_L2
"if (disposed) return;\n" INDENT3
"if (" BINDINGS_PTR_FIELD " != IntPtr.Zero)\n" OPEN_BLOCK_L3
"if (" CS_FIELD_MEMORYOWN ")\n" OPEN_BLOCK_L4 CS_FIELD_MEMORYOWN
- " = false;\n" INDENT5 CS_CLASS_NATIVECALLS "." ICALL_OBJECT_DTOR
+ " = false;\n" INDENT5 BINDINGS_CLASS_NATIVECALLS "." ICALL_OBJECT_DTOR
"(this, " BINDINGS_PTR_FIELD ");\n" CLOSE_BLOCK_L4 CLOSE_BLOCK_L3 INDENT3
"this." BINDINGS_PTR_FIELD " = IntPtr.Zero;\n" INDENT3
"GC.SuppressFinalize(this);\n" INDENT3 "disposed = true;\n" CLOSE_BLOCK_L2);
@@ -1122,10 +1161,14 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
String method_bind_field = "method_bind_" + itos(p_method_bind_count);
- String icall_params = method_bind_field + ", " + sformat(p_itype.cs_in, "this");
String arguments_sig;
String cs_in_statements;
+ String icall_params;
+ if (p_itype.is_object_type)
+ icall_params += method_bind_field + ", ";
+ icall_params += sformat(p_itype.cs_in, "this");
+
List<String> default_args_doc;
// Retrieve information from the arguments
@@ -1200,10 +1243,9 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
// Generate method
{
- if (!p_imethod.is_virtual && !p_imethod.requires_object_call) {
- p_output.push_back(MEMBER_BEGIN "private ");
- p_output.push_back(p_itype.is_singleton ? "static IntPtr " : "IntPtr ");
- p_output.push_back(method_bind_field + " = " CS_CLASS_NATIVECALLS "." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
+ if (p_itype.is_object_type && !p_imethod.is_virtual && !p_imethod.requires_object_call) {
+ p_output.push_back(MEMBER_BEGIN "private static IntPtr ");
+ p_output.push_back(method_bind_field + " = " BINDINGS_CLASS_NATIVECALLS "." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
p_output.push_back(p_imethod.name);
p_output.push_back("\");\n");
}
@@ -1284,7 +1326,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
const InternalCall *im_icall = match->value();
- String im_call = im_icall->editor_only ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS;
+ String im_call = im_icall->editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS;
im_call += "." + im_icall->name + "(" + icall_params + ");\n";
if (p_imethod.arguments.size())
@@ -1374,24 +1416,33 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
}
output.push_back("namespace GodotSharpBindings\n" OPEN_BLOCK);
+
output.push_back("uint64_t get_core_api_hash() { return ");
- output.push_back(itos(GDMono::get_singleton()->get_api_core_hash()) + "; }\n");
+ output.push_back(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + "; }\n");
+
output.push_back("#ifdef TOOLS_ENABLED\n"
"uint64_t get_editor_api_hash() { return ");
- output.push_back(itos(GDMono::get_singleton()->get_api_editor_hash()) +
+ output.push_back(String::num_uint64(GDMono::get_singleton()->get_api_editor_hash()) +
"; }\n#endif // TOOLS_ENABLED\n");
- output.push_back("void register_generated_icalls() " OPEN_BLOCK);
-#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \
- { \
- output.push_back("\tmono_add_internal_call("); \
- output.push_back("\"" BINDINGS_NAMESPACE "."); \
- output.push_back(m_icall.editor_only ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS); \
- output.push_back("::"); \
- output.push_back(m_icall.name); \
- output.push_back("\", (void*)"); \
- output.push_back(m_icall.name); \
- output.push_back(");\n"); \
+ output.push_back("uint32_t get_bindings_version() { return ");
+ output.push_back(String::num_uint64(BINDINGS_GENERATOR_VERSION) + "; }\n");
+ output.push_back("uint32_t get_cs_glue_version() { return ");
+ output.push_back(String::num_uint64(CS_GLUE_VERSION) + "; }\n");
+
+ output.push_back("void register_generated_icalls() " OPEN_BLOCK);
+ output.push_back("\tgodot_register_header_icalls();");
+
+#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \
+ { \
+ output.push_back("\tmono_add_internal_call("); \
+ output.push_back("\"" BINDINGS_NAMESPACE "."); \
+ output.push_back(m_icall.editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS); \
+ output.push_back("::"); \
+ output.push_back(m_icall.name); \
+ output.push_back("\", (void*)"); \
+ output.push_back(m_icall.name); \
+ output.push_back(");\n"); \
}
bool tools_sequence = false;
@@ -1443,6 +1494,9 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
output.push_back("#endif\n");
}
+ for (const List<InternalCall>::Element *E = builtin_method_icalls.front(); E; E = E->next())
+ ADD_INTERNAL_CALL_REGISTRATION(E->get());
+
#undef ADD_INTERNAL_CALL_REGISTRATION
output.push_back(CLOSE_BLOCK "}\n");
@@ -1456,6 +1510,14 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
return OK;
}
+uint32_t BindingsGenerator::get_version() {
+ return BINDINGS_GENERATOR_VERSION;
+}
+
+uint32_t BindingsGenerator::get_cs_glue_version() {
+ return CS_GLUE_VERSION;
+}
+
Error BindingsGenerator::_save_file(const String &p_path, const List<String> &p_content) {
FileAccessRef file = FileAccess::open(p_path, FileAccess::WRITE);
@@ -1498,9 +1560,9 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
if (p_imethod.is_vararg) {
if (i < p_imethod.arguments.size() - 1) {
c_in_statements += sformat(arg_type->c_in.size() ? arg_type->c_in : TypeInterface::DEFAULT_VARARG_C_IN, "Variant", c_param_name);
- c_in_statements += "\t" C_LOCAL_PTRCALL_ARGS ".set(0, ";
- c_in_statements += sformat("&%s_in", c_param_name);
- c_in_statements += ");\n";
+ c_in_statements += "\t" C_LOCAL_PTRCALL_ARGS ".set(";
+ c_in_statements += itos(i);
+ c_in_statements += sformat(", &%s_in);\n", c_param_name);
}
} else {
if (i > 0)
@@ -1518,6 +1580,9 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
i++;
}
+ if (!p_itype.is_object_type)
+ return OK; // no auto-generated icall functions for builtin types
+
const Map<const MethodInterface *, const InternalCall *>::Element *match = method_icalls_map.find(&p_imethod);
ERR_FAIL_NULL_V(match, ERR_BUG);
@@ -1811,7 +1876,7 @@ void BindingsGenerator::_populate_object_type_interfaces() {
imethod.return_type = name_cache.type_void;
// Actually, more methods like this may be added in the future,
- // which could actually will return something differnet.
+ // which could actually will return something different.
// Let's put this to notify us if that ever happens.
if (itype.cname != name_cache.type_Object || imethod.name != "free") {
if (verbose_output) {
@@ -2113,36 +2178,34 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
#undef INSERT_STRUCT_TYPE
-#define INSERT_PRIMITIVE_TYPE(m_type) \
- { \
- itype = TypeInterface::create_value_type(String(#m_type)); \
- itype.c_arg_in = "&%s"; \
- itype.c_type_in = #m_type; \
- itype.c_type_out = #m_type; \
- itype.im_type_in = #m_type; \
- itype.im_type_out = #m_type; \
- builtin_types.insert(itype.cname, itype); \
- }
-
- INSERT_PRIMITIVE_TYPE(bool)
- //INSERT_PRIMITIVE_TYPE(int)
+ // bool
+ itype = TypeInterface::create_value_type(String("bool"));
+ itype.c_arg_in = "&%s";
+ // /* MonoBoolean <---> bool
+ itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+ itype.c_out = "\treturn (%0)%1;\n";
+ itype.c_type = "bool";
+ // */
+ itype.c_type_in = "MonoBoolean";
+ itype.c_type_out = itype.c_type_in;
+ itype.im_type_in = itype.name;
+ itype.im_type_out = itype.name;
+ builtin_types.insert(itype.cname, itype);
// int
itype = TypeInterface::create_value_type(String("int"));
itype.c_arg_in = "&%s_in";
- //* ptrcall only supports int64_t and uint64_t
+ // /* ptrcall only supports int64_t and uint64_t
itype.c_in = "\t%0 %1_in = (%0)%1;\n";
itype.c_out = "\treturn (%0)%1;\n";
itype.c_type = "int64_t";
- //*/
- itype.c_type_in = itype.name;
- itype.c_type_out = itype.name;
+ // */
+ itype.c_type_in = "int32_t";
+ itype.c_type_out = itype.c_type_in;
itype.im_type_in = itype.name;
itype.im_type_out = itype.name;
builtin_types.insert(itype.cname, itype);
-#undef INSERT_PRIMITIVE_TYPE
-
// real_t
itype = TypeInterface();
#ifdef REAL_T_IS_DOUBLE
@@ -2200,7 +2263,8 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
"this." BINDINGS_PTR_FIELD " = NativeCalls.godot_icall_NodePath_Ctor(path);\n" CLOSE_BLOCK_L2
MEMBER_BEGIN "public static implicit operator NodePath(string from)\n" OPEN_BLOCK_L2 "return new NodePath(from);\n" CLOSE_BLOCK_L2
MEMBER_BEGIN "public static implicit operator string(NodePath from)\n" OPEN_BLOCK_L2
- "return NativeCalls." ICALL_PREFIX "NodePath_operator_String(NodePath." CS_SMETHOD_GETINSTANCE "(from));\n" CLOSE_BLOCK_L2);
+ "return NativeCalls." ICALL_PREFIX "NodePath_operator_String(NodePath." CS_SMETHOD_GETINSTANCE "(from));\n" CLOSE_BLOCK_L2
+ MEMBER_BEGIN "public override string ToString()\n" OPEN_BLOCK_L2 "return (string)this;\n" CLOSE_BLOCK_L2);
builtin_types.insert(itype.cname, itype);
// RID
@@ -2334,7 +2398,7 @@ void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant::
imethod.name = mi.name;
imethod.cname = imethod.name;
- imethod.proxy_name = mi.name;
+ imethod.proxy_name = escape_csharp_keyword(snake_to_pascal_case(mi.name));
for (int i = 0; i < mi.arguments.size(); i++) {
ArgumentInterface iarg;
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index 8929b45cce..f6194139af 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -441,6 +441,7 @@ class BindingsGenerator {
Map<StringName, String> extra_members;
List<InternalCall> method_icalls;
+ List<InternalCall> builtin_method_icalls;
Map<const MethodInterface *, const InternalCall *> method_icalls_map;
List<const InternalCall *> generated_icall_funcs;
@@ -503,8 +504,8 @@ class BindingsGenerator {
const TypeInterface *_get_type_by_name_or_null(const StringName &p_cname);
const TypeInterface *_get_type_by_name_or_placeholder(const StringName &p_cname);
- void _default_argument_from_variant(const Variant &p_var, ArgumentInterface &r_iarg);
- void _populate_builtin_type(TypeInterface &r_type, Variant::Type vtype);
+ void _default_argument_from_variant(const Variant &p_val, ArgumentInterface &r_iarg);
+ void _populate_builtin_type(TypeInterface &r_itype, Variant::Type vtype);
void _populate_object_type_interfaces();
void _populate_builtin_type_interfaces();
@@ -513,14 +514,14 @@ class BindingsGenerator {
Error _generate_cs_type(const TypeInterface &itype, const String &p_output_file);
- Error _generate_cs_property(const TypeInterface &p_itype, const PropertyInterface &p_prop_doc, List<String> &p_output);
+ Error _generate_cs_property(const TypeInterface &p_itype, const PropertyInterface &p_iprop, List<String> &p_output);
Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, List<String> &p_output);
void _generate_global_constants(List<String> &p_output);
Error _generate_glue_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, List<String> &p_output);
- Error _save_file(const String &path, const List<String> &content);
+ Error _save_file(const String &p_path, const List<String> &p_content);
BindingsGenerator() {}
@@ -535,6 +536,9 @@ public:
Error generate_cs_editor_project(const String &p_output_dir, const String &p_core_dll_path, bool p_verbose_output = true);
Error generate_glue(const String &p_output_dir);
+ static uint32_t get_version();
+ static uint32_t get_cs_glue_version();
+
void initialize();
_FORCE_INLINE_ static BindingsGenerator *get_singleton() {
diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp
index 6b41b10981..ad07f043b2 100644
--- a/modules/mono/editor/godotsharp_builds.cpp
+++ b/modules/mono/editor/godotsharp_builds.cpp
@@ -33,7 +33,6 @@
#include "main/main.h"
#include "../godotsharp_dirs.h"
-#include "../mono_gd/gd_mono.h"
#include "../mono_gd/gd_mono_class.h"
#include "../mono_gd/gd_mono_marshal.h"
#include "../utils/path_utils.h"
@@ -178,13 +177,15 @@ bool GodotSharpBuilds::build_api_sln(const String &p_name, const String &p_api_s
return true;
}
-bool GodotSharpBuilds::copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name) {
+bool GodotSharpBuilds::copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name, APIAssembly::Type p_api_type) {
String assembly_file = p_assembly_name + ".dll";
String assembly_src = p_src_dir.plus_file(assembly_file);
String assembly_dst = p_dst_dir.plus_file(assembly_file);
- if (!FileAccess::exists(assembly_dst) || FileAccess::get_modified_time(assembly_src) > FileAccess::get_modified_time(assembly_dst)) {
+ if (!FileAccess::exists(assembly_dst) ||
+ FileAccess::get_modified_time(assembly_src) > FileAccess::get_modified_time(assembly_dst) ||
+ GDMono::get_singleton()->metadata_is_api_assembly_invalidated(p_api_type)) {
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
String xml_file = p_assembly_name + ".xml";
@@ -200,36 +201,49 @@ bool GodotSharpBuilds::copy_api_assembly(const String &p_src_dir, const String &
memdelete(da);
if (err != OK) {
- show_build_error_dialog("Failed to copy " API_ASSEMBLY_NAME ".dll");
+ show_build_error_dialog("Failed to copy " + assembly_file);
return false;
}
+
+ GDMono::get_singleton()->metadata_set_api_assembly_invalidated(p_api_type, false);
}
return true;
}
-bool GodotSharpBuilds::make_api_sln(GodotSharpBuilds::APIType p_api_type) {
+String GodotSharpBuilds::_api_folder_name(APIAssembly::Type p_api_type) {
+
+ uint64_t api_hash = p_api_type == APIAssembly::API_CORE ?
+ GDMono::get_singleton()->get_api_core_hash() :
+ GDMono::get_singleton()->get_api_editor_hash();
+ return String::num_uint64(api_hash) +
+ "_" + String::num_uint64(BindingsGenerator::get_version()) +
+ "_" + String::num_uint64(BindingsGenerator::get_cs_glue_version());
+}
+
+bool GodotSharpBuilds::make_api_sln(APIAssembly::Type p_api_type) {
- String api_name = p_api_type == API_CORE ? API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
+ String api_name = p_api_type == APIAssembly::API_CORE ? API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
String api_build_config = "Release";
EditorProgress pr("mono_build_release_" + api_name, "Building " + api_name + " solution...", 4);
pr.step("Generating " + api_name + " solution");
- uint64_t core_hash = GDMono::get_singleton()->get_api_core_hash();
- uint64_t editor_hash = GDMono::get_singleton()->get_api_editor_hash();
+ String core_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir()
+ .plus_file(_api_folder_name(APIAssembly::API_CORE))
+ .plus_file(API_ASSEMBLY_NAME);
+ String editor_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir()
+ .plus_file(_api_folder_name(APIAssembly::API_EDITOR))
+ .plus_file(EDITOR_API_ASSEMBLY_NAME);
- String core_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir().plus_file(API_ASSEMBLY_NAME "_" + itos(core_hash));
- String editor_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir().plus_file(EDITOR_API_ASSEMBLY_NAME "_" + itos(editor_hash));
-
- String api_sln_dir = p_api_type == API_CORE ? core_api_sln_dir : editor_api_sln_dir;
+ String api_sln_dir = p_api_type == APIAssembly::API_CORE ? core_api_sln_dir : editor_api_sln_dir;
String api_sln_file = api_sln_dir.plus_file(api_name + ".sln");
if (!DirAccess::exists(api_sln_dir) || !FileAccess::exists(api_sln_file)) {
String core_api_assembly;
- if (p_api_type == API_EDITOR) {
+ if (p_api_type == APIAssembly::API_EDITOR) {
core_api_assembly = core_api_sln_dir.plus_file("bin")
.plus_file(api_build_config)
.plus_file(API_ASSEMBLY_NAME ".dll");
@@ -242,7 +256,7 @@ bool GodotSharpBuilds::make_api_sln(GodotSharpBuilds::APIType p_api_type) {
BindingsGenerator *gen = BindingsGenerator::get_singleton();
bool gen_verbose = OS::get_singleton()->is_stdout_verbose();
- Error err = p_api_type == API_CORE ?
+ Error err = p_api_type == APIAssembly::API_CORE ?
gen->generate_cs_core_project(api_sln_dir, gen_verbose) :
gen->generate_cs_editor_project(api_sln_dir, core_api_assembly, gen_verbose);
@@ -275,7 +289,7 @@ bool GodotSharpBuilds::make_api_sln(GodotSharpBuilds::APIType p_api_type) {
// Copy the built assembly to the assemblies directory
String api_assembly_dir = api_sln_dir.plus_file("bin").plus_file(api_build_config);
- if (!GodotSharpBuilds::copy_api_assembly(api_assembly_dir, res_assemblies_dir, api_name))
+ if (!GodotSharpBuilds::copy_api_assembly(api_assembly_dir, res_assemblies_dir, api_name, p_api_type))
return false;
pr.step("Done");
@@ -283,22 +297,22 @@ bool GodotSharpBuilds::make_api_sln(GodotSharpBuilds::APIType p_api_type) {
return true;
}
-bool GodotSharpBuilds::build_project_blocking() {
+bool GodotSharpBuilds::build_project_blocking(const String &p_config) {
if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))
return true; // No solution to build
- if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_CORE))
+ if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE))
return false;
- if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_EDITOR))
+ if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR))
return false;
EditorProgress pr("mono_project_debug_build", "Building project solution...", 2);
pr.step("Building project solution");
- MonoBuildInfo build_info(GodotSharpDirs::get_project_sln_path(), "Tools");
+ MonoBuildInfo build_info(GodotSharpDirs::get_project_sln_path(), p_config);
if (!GodotSharpBuilds::get_singleton()->build(build_info)) {
GodotSharpBuilds::show_build_error_dialog("Failed to build project solution");
return false;
@@ -309,6 +323,11 @@ bool GodotSharpBuilds::build_project_blocking() {
return true;
}
+bool GodotSharpBuilds::editor_build_callback() {
+
+ return build_project_blocking("Tools");
+}
+
GodotSharpBuilds *GodotSharpBuilds::singleton = NULL;
void GodotSharpBuilds::build_exit_callback(const MonoBuildInfo &p_build_info, int p_exit_code) {
@@ -362,7 +381,7 @@ GodotSharpBuilds::GodotSharpBuilds() {
singleton = this;
- EditorNode::get_singleton()->add_build_callback(&GodotSharpBuilds::build_project_blocking);
+ EditorNode::get_singleton()->add_build_callback(&GodotSharpBuilds::editor_build_callback);
// Build tool settings
EditorSettings *ed_settings = EditorSettings::get_singleton();
@@ -462,6 +481,7 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
if (ex) {
exited = true;
+ GDMonoUtils::print_unhandled_exception(ex);
String message = "The build constructor threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex);
build_tab->on_build_exec_failed(message);
ERR_EXPLAIN(message);
@@ -482,6 +502,7 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
if (ex) {
exited = true;
+ GDMonoUtils::print_unhandled_exception(ex);
String message = "The build method threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex);
build_tab->on_build_exec_failed(message);
ERR_EXPLAIN(message);
diff --git a/modules/mono/editor/godotsharp_builds.h b/modules/mono/editor/godotsharp_builds.h
index 5d2390ecd9..27b771e324 100644
--- a/modules/mono/editor/godotsharp_builds.h
+++ b/modules/mono/editor/godotsharp_builds.h
@@ -31,6 +31,7 @@
#ifndef GODOTSHARP_BUILDS_H
#define GODOTSHARP_BUILDS_H
+#include "../mono_gd/gd_mono.h"
#include "mono_bottom_panel.h"
#include "mono_build_info.h"
@@ -56,17 +57,14 @@ private:
HashMap<MonoBuildInfo, BuildProcess, MonoBuildInfo::Hasher> builds;
+ static String _api_folder_name(APIAssembly::Type p_api_type);
+
static GodotSharpBuilds *singleton;
friend class GDMono;
static void _register_internal_calls();
public:
- enum APIType {
- API_CORE,
- API_EDITOR
- };
-
enum BuildTool {
MSBUILD_MONO,
#ifdef WINDOWS_ENABLED
@@ -89,11 +87,13 @@ public:
bool build_async(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback = NULL);
static bool build_api_sln(const String &p_name, const String &p_api_sln_dir, const String &p_config);
- static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name);
+ static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name, APIAssembly::Type p_api_type);
+
+ static bool make_api_sln(APIAssembly::Type p_api_type);
- static bool make_api_sln(APIType p_api_type);
+ static bool build_project_blocking(const String &p_config);
- static bool build_project_blocking();
+ static bool editor_build_callback();
GodotSharpBuilds();
~GodotSharpBuilds();
diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp
index 9e48da68c1..998da8bda3 100644
--- a/modules/mono/editor/godotsharp_editor.cpp
+++ b/modules/mono/editor/godotsharp_editor.cpp
@@ -41,6 +41,7 @@
#include "../utils/path_utils.h"
#include "bindings_generator.h"
#include "csharp_project.h"
+#include "godotsharp_export.h"
#include "net_solution.h"
#ifdef WINDOWS_ENABLED
@@ -84,10 +85,10 @@ bool GodotSharpEditor::_create_project_solution() {
return false;
}
- if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_CORE))
+ if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE))
return false;
- if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_EDITOR))
+ if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR))
return false;
pr.step(TTR("Done"));
@@ -112,6 +113,21 @@ void GodotSharpEditor::_remove_create_sln_menu_option() {
bottom_panel_btn->show();
}
+void GodotSharpEditor::_show_about_dialog() {
+
+ bool show_on_start = EDITOR_GET("mono/editor/show_info_on_start");
+ about_dialog_checkbox->set_pressed(show_on_start);
+ about_dialog->popup_centered_minsize();
+}
+
+void GodotSharpEditor::_toggle_about_dialog_on_start(bool p_enabled) {
+
+ bool show_on_start = EDITOR_GET("mono/editor/show_info_on_start");
+ if (show_on_start != p_enabled) {
+ EditorSettings::get_singleton()->set_setting("mono/editor/show_info_on_start", p_enabled);
+ }
+}
+
void GodotSharpEditor::_menu_option_pressed(int p_id) {
switch (p_id) {
@@ -119,15 +135,37 @@ void GodotSharpEditor::_menu_option_pressed(int p_id) {
_create_project_solution();
} break;
+ case MENU_ABOUT_CSHARP: {
+
+ _show_about_dialog();
+ } break;
default:
ERR_FAIL();
}
}
+void GodotSharpEditor::_notification(int p_notification) {
+
+ switch (p_notification) {
+
+ case NOTIFICATION_READY: {
+
+ bool show_info_dialog = EDITOR_GET("mono/editor/show_info_on_start");
+ if (show_info_dialog) {
+ about_dialog->set_exclusive(true);
+ _show_about_dialog();
+ // Once shown a first time, it can be seen again via the Mono menu - it doesn't have to be exclusive then.
+ about_dialog->set_exclusive(false);
+ }
+ }
+ }
+}
+
void GodotSharpEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_create_project_solution"), &GodotSharpEditor::_create_project_solution);
ClassDB::bind_method(D_METHOD("_remove_create_sln_menu_option"), &GodotSharpEditor::_remove_create_sln_menu_option);
+ ClassDB::bind_method(D_METHOD("_toggle_about_dialog_on_start"), &GodotSharpEditor::_toggle_about_dialog_on_start);
ClassDB::bind_method(D_METHOD("_menu_option_pressed", "id"), &GodotSharpEditor::_menu_option_pressed);
}
@@ -210,6 +248,56 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) {
menu_button->set_text(TTR("Mono"));
menu_popup = menu_button->get_popup();
+ // TODO: Remove or edit this info dialog once Mono support is no longer in alpha
+ {
+ menu_popup->add_item(TTR("About C# support"), MENU_ABOUT_CSHARP);
+ about_dialog = memnew(AcceptDialog);
+ editor->get_gui_base()->add_child(about_dialog);
+ about_dialog->set_title("Important: C# support is not feature-complete");
+
+ // We don't use set_text() as the default AcceptDialog Label doesn't play well with the TextureRect and CheckBox
+ // we'll add. Instead we add containers and a new autowrapped Label inside.
+
+ // Main VBoxContainer (icon + label on top, checkbox at bottom)
+ VBoxContainer *about_vbc = memnew(VBoxContainer);
+ about_dialog->add_child(about_vbc);
+
+ // HBoxContainer for icon + label
+ HBoxContainer *about_hbc = memnew(HBoxContainer);
+ about_vbc->add_child(about_hbc);
+
+ TextureRect *about_icon = memnew(TextureRect);
+ about_hbc->add_child(about_icon);
+ Ref<Texture> about_icon_tex = about_icon->get_icon("NodeWarning", "EditorIcons");
+ about_icon->set_texture(about_icon_tex);
+
+ Label *about_label = memnew(Label);
+ about_hbc->add_child(about_label);
+ about_label->set_custom_minimum_size(Size2(600, 150) * EDSCALE);
+ about_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ about_label->set_autowrap(true);
+ String about_text =
+ String("C# support in Godot Engine is a brand new feature and a work in progress.\n") +
+ "It is at the alpha stage and thus not suitable for use in production.\n\n" +
+ "As of Godot 3.0, C# support is not feature-complete and may crash in some situations. " +
+ "Bugs and usability issues will be addressed gradually over 3.0.x and 3.x releases, " +
+ "including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" +
+ "The main missing feature is the ability to export games using C# assemblies - you will therefore be able to develop and run games in the editor, " +
+ "but not to share them as standalone binaries yet. This feature is of course high on the priority list and should be available as soon as possible.\n\n" +
+ "If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, Mono version, IDE, etc.:\n\n" +
+ " https://github.com/godotengine/godot/issues\n\n" +
+ "Your critical feedback at this stage will play a great role in shaping the C# support in future releases, so thank you!";
+ about_label->set_text(about_text);
+
+ EDITOR_DEF("mono/editor/show_info_on_start", true);
+
+ // CheckBox in main container
+ about_dialog_checkbox = memnew(CheckBox);
+ about_vbc->add_child(about_dialog_checkbox);
+ about_dialog_checkbox->set_text("Show this warning when starting the editor");
+ about_dialog_checkbox->connect("toggled", this, "_toggle_about_dialog_on_start");
+ }
+
String sln_path = GodotSharpDirs::get_project_sln_path();
String csproj_path = GodotSharpDirs::get_project_csproj_path();
@@ -229,6 +317,11 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) {
EditorSettings *ed_settings = EditorSettings::get_singleton();
EDITOR_DEF("mono/editor/external_editor", EDITOR_NONE);
ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/editor/external_editor", PROPERTY_HINT_ENUM, "None,MonoDevelop,Visual Studio Code"));
+
+ // Export plugin
+ Ref<GodotSharpExport> godotsharp_export;
+ godotsharp_export.instance();
+ EditorExport::get_singleton()->add_export_plugin(godotsharp_export);
}
GodotSharpEditor::~GodotSharpEditor() {
diff --git a/modules/mono/editor/godotsharp_editor.h b/modules/mono/editor/godotsharp_editor.h
index 1b83bae1cd..66da814c8b 100644
--- a/modules/mono/editor/godotsharp_editor.h
+++ b/modules/mono/editor/godotsharp_editor.h
@@ -32,7 +32,6 @@
#define GODOTSHARP_EDITOR_H
#include "godotsharp_builds.h"
-
#include "monodevelop_instance.h"
class GodotSharpEditor : public Node {
@@ -44,6 +43,8 @@ class GodotSharpEditor : public Node {
PopupMenu *menu_popup;
AcceptDialog *error_dialog;
+ AcceptDialog *about_dialog;
+ CheckBox *about_dialog_checkbox;
ToolButton *bottom_panel_btn;
@@ -54,17 +55,21 @@ class GodotSharpEditor : public Node {
bool _create_project_solution();
void _remove_create_sln_menu_option();
+ void _show_about_dialog();
+ void _toggle_about_dialog_on_start(bool p_enabled);
void _menu_option_pressed(int p_id);
static GodotSharpEditor *singleton;
protected:
+ void _notification(int p_notification);
static void _bind_methods();
public:
enum MenuOptions {
- MENU_CREATE_SLN
+ MENU_CREATE_SLN,
+ MENU_ABOUT_CSHARP,
};
enum ExternalEditor {
diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp
new file mode 100644
index 0000000000..cd09e6516a
--- /dev/null
+++ b/modules/mono/editor/godotsharp_export.cpp
@@ -0,0 +1,166 @@
+/*************************************************************************/
+/* godotsharp_export.cpp */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+
+#include "godotsharp_export.h"
+
+#include "../csharp_script.h"
+#include "../godotsharp_defs.h"
+#include "../godotsharp_dirs.h"
+#include "godotsharp_builds.h"
+
+void GodotSharpExport::_export_file(const String &p_path, const String &p_type, const Set<String> &p_features) {
+
+ if (p_type != CSharpLanguage::get_singleton()->get_type())
+ return;
+
+ ERR_FAIL_COND(p_path.get_extension() != CSharpLanguage::get_singleton()->get_extension());
+
+ // TODO what if the source file is not part of the game's C# project
+
+ if (!GLOBAL_GET("mono/export/include_scripts_content")) {
+ // We don't want to include the source code on exported games
+ add_file(p_path, Vector<uint8_t>(), false);
+ skip();
+ }
+}
+
+void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug, const String &p_path, int p_flags) {
+
+ // TODO right now there is no way to stop the export process with an error
+
+ ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
+ ERR_FAIL_NULL(GDMono::get_singleton()->get_tools_domain());
+
+ String build_config = p_debug ? "Debug" : "Release";
+
+ ERR_FAIL_COND(!GodotSharpBuilds::build_project_blocking(build_config));
+
+ // Add API assemblies
+
+ String core_api_dll_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(API_ASSEMBLY_NAME ".dll");
+ ERR_FAIL_COND(!_add_assembly(core_api_dll_path, core_api_dll_path));
+
+ String editor_api_dll_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
+ ERR_FAIL_COND(!_add_assembly(editor_api_dll_path, editor_api_dll_path));
+
+ // Add project assembly
+
+ String project_dll_name = ProjectSettings::get_singleton()->get("application/config/name");
+ if (project_dll_name.empty()) {
+ project_dll_name = "UnnamedProject";
+ }
+
+ String project_dll_src_path = GodotSharpDirs::get_res_temp_assemblies_base_dir().plus_file(build_config).plus_file(project_dll_name + ".dll");
+ String project_dll_dst_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(project_dll_name + ".dll");
+ ERR_FAIL_COND(!_add_assembly(project_dll_src_path, project_dll_dst_path));
+
+ // Add dependencies
+
+ MonoDomain *prev_domain = mono_domain_get();
+ MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.ProjectExportDomain");
+
+ ERR_FAIL_COND(!export_domain);
+ ERR_FAIL_COND(!mono_domain_set(export_domain, false));
+
+ Map<String, String> dependencies;
+ dependencies.insert("mscorlib", GDMono::get_singleton()->get_corlib_assembly()->get_path());
+
+ GDMonoAssembly *scripts_assembly = GDMonoAssembly::load_from(project_dll_name, project_dll_src_path, /* refonly: */ true);
+
+ ERR_EXPLAIN("Cannot load refonly assembly: " + project_dll_name);
+ ERR_FAIL_COND(!scripts_assembly);
+
+ Error depend_error = _get_assembly_dependencies(scripts_assembly, dependencies);
+
+ GDMono::get_singleton()->finalize_and_unload_domain(export_domain);
+ mono_domain_set(prev_domain, false);
+
+ ERR_FAIL_COND(depend_error != OK);
+
+ for (Map<String, String>::Element *E = dependencies.front(); E; E = E->next()) {
+ String depend_src_path = E->value();
+ String depend_dst_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(depend_src_path.get_file());
+ ERR_FAIL_COND(!_add_assembly(depend_src_path, depend_dst_path));
+ }
+}
+
+bool GodotSharpExport::_add_assembly(const String &p_src_path, const String &p_dst_path) {
+
+ FileAccessRef f = FileAccess::open(p_src_path, FileAccess::READ);
+ ERR_FAIL_COND_V(!f, false);
+
+ Vector<uint8_t> data;
+ data.resize(f->get_len());
+ f->get_buffer(data.ptrw(), data.size());
+
+ add_file(p_dst_path, data, false);
+
+ return true;
+}
+
+Error GodotSharpExport::_get_assembly_dependencies(GDMonoAssembly *p_assembly, Map<String, String> &r_dependencies) {
+
+ MonoImage *image = p_assembly->get_image();
+
+ for (int i = 0; i < mono_image_get_table_rows(image, MONO_TABLE_ASSEMBLYREF); i++) {
+ MonoAssemblyName *ref_aname = aname_prealloc;
+ mono_assembly_get_assemblyref(image, i, ref_aname);
+ String ref_name = mono_assembly_name_get_name(ref_aname);
+
+ if (ref_name == "mscorlib" || r_dependencies.find(ref_name))
+ continue;
+
+ GDMonoAssembly *ref_assembly = NULL;
+ if (!GDMono::get_singleton()->load_assembly(ref_name, ref_aname, &ref_assembly, /* refonly: */ true)) {
+ ERR_EXPLAIN("Cannot load refonly assembly: " + ref_name);
+ ERR_FAIL_V(ERR_CANT_RESOLVE);
+ }
+
+ r_dependencies.insert(ref_name, ref_assembly->get_path());
+
+ Error err = _get_assembly_dependencies(ref_assembly, r_dependencies);
+ if (err != OK)
+ return err;
+ }
+
+ return OK;
+}
+
+GodotSharpExport::GodotSharpExport() {
+ // MonoAssemblyName is an incomplete type (internal to mono), so we can't allocate it ourselves.
+ // There isn't any api to allocate an empty one either, so we need to do it this way.
+ aname_prealloc = mono_assembly_name_new("whatever");
+ mono_assembly_name_free(aname_prealloc); // "it does not frees the object itself, only the name members" (typo included)
+}
+
+GodotSharpExport::~GodotSharpExport() {
+ if (aname_prealloc)
+ mono_free(aname_prealloc);
+}
diff --git a/modules/mono/editor/godotsharp_export.h b/modules/mono/editor/godotsharp_export.h
new file mode 100644
index 0000000000..b38db9660c
--- /dev/null
+++ b/modules/mono/editor/godotsharp_export.h
@@ -0,0 +1,57 @@
+/*************************************************************************/
+/* godotsharp_export.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 GODOTSHARP_EXPORT_H
+#define GODOTSHARP_EXPORT_H
+
+#include <mono/metadata/image.h>
+
+#include "editor/editor_export.h"
+
+#include "../mono_gd/gd_mono_header.h"
+
+class GodotSharpExport : public EditorExportPlugin {
+
+ MonoAssemblyName *aname_prealloc;
+
+ bool _add_assembly(const String &p_src_path, const String &p_dst_path);
+
+ Error _get_assembly_dependencies(GDMonoAssembly *p_assembly, Map<String, String> &r_dependencies);
+
+protected:
+ virtual void _export_file(const String &p_path, const String &p_type, const Set<String> &p_features);
+ virtual void _export_begin(const Set<String> &p_features, bool p_debug, const String &p_path, int p_flags);
+
+public:
+ GodotSharpExport();
+ ~GodotSharpExport();
+};
+
+#endif // GODOTSHARP_EXPORT_H
diff --git a/modules/mono/editor/mono_bottom_panel.cpp b/modules/mono/editor/mono_bottom_panel.cpp
index 43689548b5..32aec2a3b5 100644
--- a/modules/mono/editor/mono_bottom_panel.cpp
+++ b/modules/mono/editor/mono_bottom_panel.cpp
@@ -142,7 +142,7 @@ void MonoBottomPanel::_errors_toggled(bool p_pressed) {
void MonoBottomPanel::_build_project_pressed() {
- GodotSharpBuilds::get_singleton()->build_project_blocking();
+ GodotSharpBuilds::get_singleton()->build_project_blocking("Tools");
MonoReloadNode::get_singleton()->restart_reload_timer();
CSharpLanguage::get_singleton()->reload_assemblies_if_needed(true);
@@ -197,7 +197,7 @@ MonoBottomPanel::MonoBottomPanel(EditorNode *p_editor) {
toolbar_hbc->set_h_size_flags(SIZE_EXPAND_FILL);
panel_builds_tab->add_child(toolbar_hbc);
- ToolButton *build_project_btn = memnew(ToolButton);
+ Button *build_project_btn = memnew(Button);
build_project_btn->set_text(TTR("Build Project"));
build_project_btn->set_focus_mode(FOCUS_NONE);
build_project_btn->connect("pressed", this, "_build_project_pressed");
@@ -335,16 +335,14 @@ void MonoBuildTab::_update_issues_list() {
Ref<Texture> MonoBuildTab::get_icon_texture() const {
- // FIXME these icons were removed... find something better
-
if (build_exited) {
if (build_result == RESULT_ERROR) {
- return get_icon("DependencyChangedHl", "EditorIcons");
+ return get_icon("StatusError", "EditorIcons");
} else {
- return get_icon("DependencyOkHl", "EditorIcons");
+ return get_icon("StatusSuccess", "EditorIcons");
}
} else {
- return get_icon("GraphTime", "EditorIcons");
+ return get_icon("Stop", "EditorIcons");
}
}
diff --git a/modules/mono/editor/monodevelop_instance.h b/modules/mono/editor/monodevelop_instance.h
index 7e8a76b595..552c10a61d 100644
--- a/modules/mono/editor/monodevelop_instance.h
+++ b/modules/mono/editor/monodevelop_instance.h
@@ -43,7 +43,7 @@ class MonoDevelopInstance {
public:
void execute(const Vector<String> &p_files);
- void execute(const String &p_files);
+ void execute(const String &p_file);
MonoDevelopInstance(const String &p_solution);
};
diff --git a/modules/mono/glue/builtin_types_glue.h b/modules/mono/glue/builtin_types_glue.h
new file mode 100644
index 0000000000..460de84b65
--- /dev/null
+++ b/modules/mono/glue/builtin_types_glue.h
@@ -0,0 +1,59 @@
+#ifndef BUILTIN_TYPES_GLUE_H
+#define BUILTIN_TYPES_GLUE_H
+
+#include "core/node_path.h"
+#include "core/rid.h"
+
+#include <mono/metadata/object.h>
+
+#include "../mono_gd/gd_mono_marshal.h"
+
+MonoBoolean godot_icall_NodePath_is_absolute(NodePath *p_ptr) {
+ return (MonoBoolean)p_ptr->is_absolute();
+}
+
+uint32_t godot_icall_NodePath_get_name_count(NodePath *p_ptr) {
+ return p_ptr->get_name_count();
+}
+
+MonoString *godot_icall_NodePath_get_name(NodePath *p_ptr, uint32_t p_idx) {
+ return GDMonoMarshal::mono_string_from_godot(p_ptr->get_name(p_idx));
+}
+
+uint32_t godot_icall_NodePath_get_subname_count(NodePath *p_ptr) {
+ return p_ptr->get_subname_count();
+}
+
+MonoString *godot_icall_NodePath_get_subname(NodePath *p_ptr, uint32_t p_idx) {
+ return GDMonoMarshal::mono_string_from_godot(p_ptr->get_subname(p_idx));
+}
+
+MonoString *godot_icall_NodePath_get_concatenated_subnames(NodePath *p_ptr) {
+ return GDMonoMarshal::mono_string_from_godot(p_ptr->get_concatenated_subnames());
+}
+
+NodePath *godot_icall_NodePath_get_as_property_path(NodePath *p_ptr) {
+ return memnew(NodePath(p_ptr->get_as_property_path()));
+}
+
+MonoBoolean godot_icall_NodePath_is_empty(NodePath *p_ptr) {
+ return (MonoBoolean)p_ptr->is_empty();
+}
+
+uint32_t godot_icall_RID_get_id(RID *p_ptr) {
+ return p_ptr->get_id();
+}
+
+void godot_register_builtin_type_icalls() {
+ mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_as_property_path", (void *)godot_icall_NodePath_get_as_property_path);
+ mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_concatenated_subnames", (void *)godot_icall_NodePath_get_concatenated_subnames);
+ mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_name", (void *)godot_icall_NodePath_get_name);
+ mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_name_count", (void *)godot_icall_NodePath_get_name_count);
+ mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_subname", (void *)godot_icall_NodePath_get_subname);
+ mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_subname_count", (void *)godot_icall_NodePath_get_subname_count);
+ mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_is_absolute", (void *)godot_icall_NodePath_is_absolute);
+ mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_is_empty", (void *)godot_icall_NodePath_is_empty);
+ mono_add_internal_call("Godot.NativeCalls::godot_icall_RID_get_id", (void *)godot_icall_RID_get_id);
+}
+
+#endif // BUILTIN_TYPES_GLUE_H
diff --git a/modules/mono/glue/cs_files/Basis.cs b/modules/mono/glue/cs_files/Basis.cs
index ea92b1641b..c6cdc069ef 100644
--- a/modules/mono/glue/cs_files/Basis.cs
+++ b/modules/mono/glue/cs_files/Basis.cs
@@ -452,9 +452,9 @@ namespace Godot
public Basis(float xx, float xy, float xz, float yx, float yy, float yz, float zx, float zy, float zz)
{
- this.x = new Vector3(xx, xy, xz);
- this.y = new Vector3(yx, yy, yz);
- this.z = new Vector3(zx, zy, zz);
+ this.x = new Vector3(xx, yx, zx);
+ this.y = new Vector3(xy, yy, zy);
+ this.z = new Vector3(xz, yz, zz);
}
public static Basis operator *(Basis left, Basis right)
diff --git a/modules/mono/glue/cs_files/DebuggingUtils.cs b/modules/mono/glue/cs_files/DebuggingUtils.cs
index 42ca57fbf9..ffaaf00837 100644
--- a/modules/mono/glue/cs_files/DebuggingUtils.cs
+++ b/modules/mono/glue/cs_files/DebuggingUtils.cs
@@ -34,8 +34,8 @@ namespace Godot
StringBuilder sb = new StringBuilder();
- if (methodBase is MethodInfo methodInfo)
- sb.AppendTypeName(methodInfo.ReturnType);
+ if (methodBase is MethodInfo)
+ sb.AppendTypeName(((MethodInfo)methodBase).ReturnType);
sb.Append(methodBase.DeclaringType.FullName);
sb.Append(".");
diff --git a/modules/mono/glue/cs_files/Mathf.cs b/modules/mono/glue/cs_files/Mathf.cs
index 6951ace4fc..476396e9a3 100644
--- a/modules/mono/glue/cs_files/Mathf.cs
+++ b/modules/mono/glue/cs_files/Mathf.cs
@@ -71,7 +71,7 @@ namespace Godot
public static int Decimals(float step)
{
- return Decimals(step);
+ return Decimals((decimal)step);
}
public static int Decimals(decimal step)
diff --git a/modules/mono/glue/cs_files/Plane.cs b/modules/mono/glue/cs_files/Plane.cs
index 6365e71826..b347c0835a 100644
--- a/modules/mono/glue/cs_files/Plane.cs
+++ b/modules/mono/glue/cs_files/Plane.cs
@@ -91,7 +91,7 @@ namespace Godot
float dist = (normal.Dot(from) - d) / den;
- // This is a ray, before the emiting pos (from) does not exist
+ // This is a ray, before the emitting pos (from) does not exist
if (dist > Mathf.Epsilon)
return new Vector3();
diff --git a/modules/mono/glue/cs_files/SignalAttribute.cs b/modules/mono/glue/cs_files/SignalAttribute.cs
new file mode 100644
index 0000000000..d8a6cabb83
--- /dev/null
+++ b/modules/mono/glue/cs_files/SignalAttribute.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Delegate)]
+ public class SignalAttribute : Attribute
+ {
+ public SignalAttribute()
+ {
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/VERSION.txt b/modules/mono/glue/cs_files/VERSION.txt
new file mode 100755
index 0000000000..d00491fd7e
--- /dev/null
+++ b/modules/mono/glue/cs_files/VERSION.txt
@@ -0,0 +1 @@
+1
diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h
index 32988c5afa..cedc8e9992 100644
--- a/modules/mono/glue/glue_header.h
+++ b/modules/mono/glue/glue_header.h
@@ -28,6 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#include "builtin_types_glue.h"
+
#include "../csharp_script.h"
#include "../mono_gd/gd_mono_class.h"
#include "../mono_gd/gd_mono_internals.h"
@@ -91,12 +93,6 @@ MonoString *godot_icall_NodePath_operator_String(NodePath *p_np) {
return GDMonoMarshal::mono_string_from_godot(p_np->operator String());
}
-MonoArray *godot_icall_String_md5_buffer(MonoString *p_str) {
- Vector<uint8_t> ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_buffer();
- // TODO Check possible Array/Vector<uint8_t> problem?
- return GDMonoMarshal::Array_to_mono_array(Variant(ret));
-}
-
// -- RID --
RID *godot_icall_RID_Ctor(Object *p_from) {
@@ -115,6 +111,12 @@ void godot_icall_RID_Dtor(RID *p_ptr) {
// -- String --
+MonoArray *godot_icall_String_md5_buffer(MonoString *p_str) {
+ Vector<uint8_t> ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_buffer();
+ // TODO Check possible Array/Vector<uint8_t> problem?
+ return GDMonoMarshal::Array_to_mono_array(Variant(ret));
+}
+
MonoString *godot_icall_String_md5_text(MonoString *p_str) {
String ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_text();
return GDMonoMarshal::mono_string_from_godot(ret);
@@ -303,3 +305,7 @@ MonoObject *godot_icall_Godot_weakref(Object *p_obj) {
return GDMonoUtils::create_managed_for_godot_object(CACHED_CLASS(WeakRef), Reference::get_class_static(), Object::cast_to<Object>(wref.ptr()));
}
+
+void godot_register_header_icalls() {
+ godot_register_builtin_type_icalls();
+}
diff --git a/modules/mono/godotsharp_defs.h b/modules/mono/godotsharp_defs.h
index 4c26c3e6bd..f604464e8f 100644
--- a/modules/mono/godotsharp_defs.h
+++ b/modules/mono/godotsharp_defs.h
@@ -39,4 +39,7 @@
#define EDITOR_API_ASSEMBLY_NAME "GodotSharpEditor"
#define EDITOR_TOOLS_ASSEMBLY_NAME "GodotSharpTools"
+#define BINDINGS_CLASS_NATIVECALLS "NativeCalls"
+#define BINDINGS_CLASS_NATIVECALLS_EDITOR "EditorNativeCalls"
+
#endif // GODOTSHARP_DEFS_H
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 6c07c90f79..1ebef04561 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -42,11 +42,15 @@
#include "project_settings.h"
#include "../csharp_script.h"
+#include "../godotsharp_dirs.h"
#include "../utils/path_utils.h"
+#include "gd_mono_class.h"
+#include "gd_mono_marshal.h"
#include "gd_mono_utils.h"
#ifdef TOOLS_ENABLED
#include "../editor/godotsharp_editor.h"
+#include "main/main.h"
#endif
void gdmono_unhandled_exception_hook(MonoObject *exc, void *user_data) {
@@ -94,21 +98,6 @@ static bool _wait_for_debugger_msecs(uint32_t p_msecs) {
}
#endif
-#ifdef TOOLS_ENABLED
-// temporary workaround. should be provided from Main::setup/setup2 instead
-bool _is_project_manager_requested() {
-
- List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
- for (List<String>::Element *E = cmdline_args.front(); E; E = E->next()) {
- const String &arg = E->get();
- if (arg == "-p" || arg == "--project-manager")
- return true;
- }
-
- return false;
-}
-#endif
-
#ifdef DEBUG_ENABLED
void gdmono_debug_init() {
@@ -121,7 +110,7 @@ void gdmono_debug_init() {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint() ||
ProjectSettings::get_singleton()->get_resource_path().empty() ||
- _is_project_manager_requested()) {
+ Main::is_project_manager()) {
return;
}
#endif
@@ -222,7 +211,46 @@ void GDMono::initialize() {
_register_internal_calls();
// The following assemblies are not required at initialization
- _load_all_script_assemblies();
+#ifndef MONO_GLUE_DISABLED
+ if (_load_api_assemblies()) {
+ if (!core_api_assembly_out_of_sync && !editor_api_assembly_out_of_sync && GDMonoUtils::mono_cache.godot_api_cache_updated) {
+ // Everything is fine with the api assemblies, load the project assembly
+ _load_project_assembly();
+ } else {
+#ifdef TOOLS_ENABLED
+ // The assembly was successfuly loaded, but the full api could not be cached.
+ // This is most likely an outdated assembly loaded because of an invalid version in the metadata,
+ // so we invalidate the version in the metadata and unload the script domain.
+
+ if (core_api_assembly_out_of_sync) {
+ ERR_PRINT("The loaded Core API assembly is out of sync");
+ metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true);
+ } else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) {
+ ERR_PRINT("The loaded Core API assembly is in sync, but the cache update failed");
+ metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true);
+ }
+
+ if (editor_api_assembly_out_of_sync) {
+ ERR_PRINT("The loaded Editor API assembly is out of sync");
+ metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true);
+ }
+
+ OS::get_singleton()->print("Mono: Proceeding to unload scripts domain because of invalid API assemblies\n");
+
+ Error err = _unload_scripts_domain();
+ if (err != OK) {
+ WARN_PRINT("Mono: Failed to unload scripts domain");
+ }
+#else
+ ERR_PRINT("The loaded API assembly is invalid");
+ CRASH_NOW();
+#endif
+ }
+ }
+#else
+ if (OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->print("Mono: Glue disabled, ignoring script assemblies\n");
+#endif
mono_install_unhandled_exception_hook(gdmono_unhandled_exception_hook, NULL);
@@ -233,7 +261,11 @@ void GDMono::initialize() {
namespace GodotSharpBindings {
uint64_t get_core_api_hash();
+#ifdef TOOLS_ENABLED
uint64_t get_editor_api_hash();
+#endif // TOOLS_ENABLED
+uint32_t get_bindings_version();
+uint32_t get_cs_glue_version();
void register_generated_icalls();
} // namespace GodotSharpBindings
@@ -285,43 +317,84 @@ GDMonoAssembly **GDMono::get_loaded_assembly(const String &p_name) {
return assemblies[domain_id].getptr(p_name);
}
-bool GDMono::_load_assembly(const String &p_name, GDMonoAssembly **r_assembly) {
+bool GDMono::load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly) {
+
+ CRASH_COND(!r_assembly);
+
+ MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8());
+ bool result = load_assembly(p_name, aname, r_assembly, p_refonly);
+ mono_assembly_name_free(aname);
+ mono_free(aname);
+
+ return result;
+}
+
+bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly) {
CRASH_COND(!r_assembly);
if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->print((String() + "Mono: Loading assembly " + p_name + "...\n").utf8());
+ OS::get_singleton()->print((String() + "Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "...\n").utf8());
MonoImageOpenStatus status = MONO_IMAGE_OK;
- MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8());
- MonoAssembly *assembly = mono_assembly_load_full(aname, NULL, &status, false);
- mono_assembly_name_free(aname);
+ MonoAssembly *assembly = mono_assembly_load_full(p_aname, NULL, &status, p_refonly);
if (!assembly)
return false;
+ ERR_FAIL_COND_V(status != MONO_IMAGE_OK, false);
+
uint32_t domain_id = mono_domain_get_id(mono_domain_get());
GDMonoAssembly **stored_assembly = assemblies[domain_id].getptr(p_name);
- ERR_FAIL_COND_V(status != MONO_IMAGE_OK, false);
ERR_FAIL_COND_V(stored_assembly == NULL, false);
-
ERR_FAIL_COND_V((*stored_assembly)->get_assembly() != assembly, false);
+
*r_assembly = *stored_assembly;
if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->print(String("Mono: Assembly " + p_name + " loaded from path: " + (*r_assembly)->get_path() + "\n").utf8());
+ OS::get_singleton()->print(String("Mono: Assembly " + p_name + (p_refonly ? " (refonly)" : "") + " loaded from path: " + (*r_assembly)->get_path() + "\n").utf8());
return true;
}
+APIAssembly::Version APIAssembly::Version::get_from_loaded_assembly(GDMonoAssembly *p_api_assembly, APIAssembly::Type p_api_type) {
+ APIAssembly::Version api_assembly_version;
+
+ const char *nativecalls_name = p_api_type == APIAssembly::API_CORE ?
+ BINDINGS_CLASS_NATIVECALLS :
+ BINDINGS_CLASS_NATIVECALLS_EDITOR;
+
+ GDMonoClass *nativecalls_klass = p_api_assembly->get_class(BINDINGS_NAMESPACE, nativecalls_name);
+
+ if (nativecalls_klass) {
+ GDMonoField *api_hash_field = nativecalls_klass->get_field("godot_api_hash");
+ if (api_hash_field)
+ api_assembly_version.godot_api_hash = GDMonoMarshal::unbox<uint64_t>(api_hash_field->get_value(NULL));
+
+ GDMonoField *binds_ver_field = nativecalls_klass->get_field("bindings_version");
+ if (binds_ver_field)
+ api_assembly_version.bindings_version = GDMonoMarshal::unbox<uint32_t>(binds_ver_field->get_value(NULL));
+
+ GDMonoField *cs_glue_ver_field = nativecalls_klass->get_field("cs_glue_version");
+ if (cs_glue_ver_field)
+ api_assembly_version.cs_glue_version = GDMonoMarshal::unbox<uint32_t>(cs_glue_ver_field->get_value(NULL));
+ }
+
+ return api_assembly_version;
+}
+
+String APIAssembly::to_string(APIAssembly::Type p_type) {
+ return p_type == APIAssembly::API_CORE ? "API_CORE" : "API_EDITOR";
+}
+
bool GDMono::_load_corlib_assembly() {
if (corlib_assembly)
return true;
- bool success = _load_assembly("mscorlib", &corlib_assembly);
+ bool success = load_assembly("mscorlib", &corlib_assembly);
if (success)
GDMonoUtils::update_corlib_cache();
@@ -331,13 +404,25 @@ bool GDMono::_load_corlib_assembly() {
bool GDMono::_load_core_api_assembly() {
- if (api_assembly)
+ if (core_api_assembly)
return true;
- bool success = _load_assembly(API_ASSEMBLY_NAME, &api_assembly);
+#ifdef TOOLS_ENABLED
+ if (metadata_is_api_assembly_invalidated(APIAssembly::API_CORE))
+ return false;
+#endif
- if (success)
+ bool success = load_assembly(API_ASSEMBLY_NAME, &core_api_assembly);
+
+ if (success) {
+#ifndef MONO_GLUE_DISABLED
+ APIAssembly::Version api_assembly_ver = APIAssembly::Version::get_from_loaded_assembly(core_api_assembly, APIAssembly::API_CORE);
+ core_api_assembly_out_of_sync = GodotSharpBindings::get_core_api_hash() != api_assembly_ver.godot_api_hash ||
+ GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version ||
+ GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version;
+#endif
GDMonoUtils::update_godot_api_cache();
+ }
return success;
}
@@ -348,7 +433,23 @@ bool GDMono::_load_editor_api_assembly() {
if (editor_api_assembly)
return true;
- return _load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly);
+#ifdef TOOLS_ENABLED
+ if (metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR))
+ return false;
+#endif
+
+ bool success = load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly);
+
+ if (success) {
+#ifndef MONO_GLUE_DISABLED
+ APIAssembly::Version api_assembly_ver = APIAssembly::Version::get_from_loaded_assembly(editor_api_assembly, APIAssembly::API_EDITOR);
+ editor_api_assembly_out_of_sync = GodotSharpBindings::get_editor_api_hash() != api_assembly_ver.godot_api_hash ||
+ GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version ||
+ GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version;
+#endif
+ }
+
+ return success;
}
#endif
@@ -360,7 +461,7 @@ bool GDMono::_load_editor_tools_assembly() {
_GDMONO_SCOPE_DOMAIN_(tools_domain)
- return _load_assembly(EDITOR_TOOLS_ASSEMBLY_NAME, &editor_tools_assembly);
+ return load_assembly(EDITOR_TOOLS_ASSEMBLY_NAME, &editor_tools_assembly);
}
#endif
@@ -374,17 +475,20 @@ bool GDMono::_load_project_assembly() {
name = "UnnamedProject";
}
- bool success = _load_assembly(name, &project_assembly);
+ bool success = load_assembly(name, &project_assembly);
- if (success)
+ if (success) {
mono_assembly_set_main(project_assembly->get_assembly());
+ } else {
+ if (OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->printerr("Mono: Failed to load project assembly\n");
+ }
return success;
}
-bool GDMono::_load_all_script_assemblies() {
+bool GDMono::_load_api_assemblies() {
-#ifndef MONO_GLUE_DISABLED
if (!_load_core_api_assembly()) {
if (OS::get_singleton()->is_stdout_verbose())
OS::get_singleton()->printerr("Mono: Failed to load Core API assembly\n");
@@ -399,20 +503,72 @@ bool GDMono::_load_all_script_assemblies() {
#endif
}
- if (!_load_project_assembly()) {
- if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->printerr("Mono: Failed to load project assembly\n");
- return false;
+ return true;
+}
+
+#ifdef TOOLS_ENABLED
+String GDMono::_get_api_assembly_metadata_path() {
+
+ return GodotSharpDirs::get_res_metadata_dir().plus_file("api_assemblies.cfg");
+}
+
+void GDMono::metadata_set_api_assembly_invalidated(APIAssembly::Type p_api_type, bool p_invalidated) {
+
+ String section = APIAssembly::to_string(p_api_type);
+ String path = _get_api_assembly_metadata_path();
+
+ Ref<ConfigFile> metadata;
+ metadata.instance();
+ metadata->load(path);
+
+ metadata->set_value(section, "invalidated", p_invalidated);
+
+ String assembly_path = GodotSharpDirs::get_res_assemblies_dir()
+ .plus_file(p_api_type == APIAssembly::API_CORE ?
+ API_ASSEMBLY_NAME ".dll" :
+ EDITOR_API_ASSEMBLY_NAME ".dll");
+
+ ERR_FAIL_COND(!FileAccess::exists(assembly_path));
+
+ uint64_t modified_time = FileAccess::get_modified_time(assembly_path);
+
+ metadata->set_value(section, "invalidated_asm_modified_time", String::num_uint64(modified_time));
+
+ String dir = path.get_base_dir();
+ if (!DirAccess::exists(dir)) {
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND(!da);
+ Error err = da->make_dir_recursive(ProjectSettings::get_singleton()->globalize_path(dir));
+ ERR_FAIL_COND(err != OK);
}
- return true;
-#else
- if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->print("Mono: Glue disbled, ignoring script assemblies\n");
+ Error save_err = metadata->save(path);
+ ERR_FAIL_COND(save_err != OK);
+}
- return true;
-#endif
+bool GDMono::metadata_is_api_assembly_invalidated(APIAssembly::Type p_api_type) {
+
+ String section = APIAssembly::to_string(p_api_type);
+
+ Ref<ConfigFile> metadata;
+ metadata.instance();
+ metadata->load(_get_api_assembly_metadata_path());
+
+ String assembly_path = GodotSharpDirs::get_res_assemblies_dir()
+ .plus_file(p_api_type == APIAssembly::API_CORE ?
+ API_ASSEMBLY_NAME ".dll" :
+ EDITOR_API_ASSEMBLY_NAME ".dll");
+
+ if (!FileAccess::exists(assembly_path))
+ return false;
+
+ uint64_t modified_time = FileAccess::get_modified_time(assembly_path);
+
+ uint64_t stored_modified_time = metadata->get_value(section, "invalidated_asm_modified_time", 0);
+
+ return metadata->get_value(section, "invalidated", false) && modified_time <= stored_modified_time;
}
+#endif
Error GDMono::_load_scripts_domain() {
@@ -455,12 +611,15 @@ Error GDMono::_unload_scripts_domain() {
_domain_assemblies_cleanup(mono_domain_get_id(scripts_domain));
- api_assembly = NULL;
+ core_api_assembly = NULL;
project_assembly = NULL;
#ifdef TOOLS_ENABLED
editor_api_assembly = NULL;
#endif
+ core_api_assembly_out_of_sync = false;
+ editor_api_assembly_out_of_sync = false;
+
MonoDomain *domain = scripts_domain;
scripts_domain = NULL;
@@ -515,16 +674,80 @@ Error GDMono::reload_scripts_domain() {
return err;
}
- if (!_load_all_script_assemblies()) {
- if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->printerr("Mono: Failed to load script assemblies\n");
+#ifndef MONO_GLUE_DISABLED
+ if (!_load_api_assemblies()) {
return ERR_CANT_OPEN;
}
+ if (!core_api_assembly_out_of_sync && !editor_api_assembly_out_of_sync && GDMonoUtils::mono_cache.godot_api_cache_updated) {
+ // Everything is fine with the api assemblies, load the project assembly
+ _load_project_assembly();
+ } else {
+ // The assembly was successfuly loaded, but the full api could not be cached.
+ // This is most likely an outdated assembly loaded because of an invalid version in the metadata,
+ // so we invalidate the version in the metadata and unload the script domain.
+
+ if (core_api_assembly_out_of_sync) {
+ metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true);
+ } else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) {
+ ERR_PRINT("Core API assembly is in sync, but the cache update failed");
+ metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true);
+ }
+
+ if (editor_api_assembly_out_of_sync) {
+ metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true);
+ }
+
+ Error err = _unload_scripts_domain();
+ if (err != OK) {
+ WARN_PRINT("Mono: Failed to unload scripts domain");
+ }
+
+ return ERR_CANT_RESOLVE;
+ }
+
+ if (!_load_project_assembly())
+ return ERR_CANT_OPEN;
+#else
+ if (OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->print("Mono: Glue disabled, ignoring script assemblies\n");
+#endif
+
return OK;
}
#endif
+Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
+
+ CRASH_COND(p_domain == NULL);
+
+ String domain_name = mono_domain_get_friendly_name(p_domain);
+
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print(String("Mono: Unloading domain `" + domain_name + "`...\n").utf8());
+ }
+
+ if (mono_domain_get() != root_domain)
+ mono_domain_set(root_domain, true);
+
+ mono_gc_collect(mono_gc_max_generation());
+ mono_domain_finalize(p_domain, 2000);
+ mono_gc_collect(mono_gc_max_generation());
+
+ _domain_assemblies_cleanup(mono_domain_get_id(p_domain));
+
+ MonoObject *ex = NULL;
+ mono_domain_try_unload(p_domain, &ex);
+
+ if (ex) {
+ ERR_PRINTS("Exception thrown when unloading domain `" + domain_name + "`:");
+ mono_print_unhandled_exception(ex);
+ return FAILED;
+ }
+
+ return OK;
+}
+
GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
MonoImage *image = mono_class_get_image(p_raw_class);
@@ -576,8 +799,11 @@ GDMono::GDMono() {
tools_domain = NULL;
#endif
+ core_api_assembly_out_of_sync = false;
+ editor_api_assembly_out_of_sync = false;
+
corlib_assembly = NULL;
- api_assembly = NULL;
+ core_api_assembly = NULL;
project_assembly = NULL;
#ifdef TOOLS_ENABLED
editor_api_assembly = NULL;
@@ -696,11 +922,13 @@ bool _GodotSharp::is_domain_loaded() {
return GDMono::get_singleton()->get_scripts_domain() != NULL;
}
-#define ENQUEUE_FOR_DISPOSAL(m_queue, m_inst) \
- m_queue.push_back(m_inst); \
- if (queue_empty) { \
- queue_empty = false; \
- call_deferred("_dispose_callback"); \
+#define ENQUEUE_FOR_DISPOSAL(m_queue, m_inst) \
+ m_queue.push_back(m_inst); \
+ if (queue_empty) { \
+ queue_empty = false; \
+ if (!is_finalizing_domain()) { /* call_deferred may not be safe here */ \
+ call_deferred("_dispose_callback"); \
+ } \
}
void _GodotSharp::queue_dispose(MonoObject *p_mono_object, Object *p_object) {
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index 67251778c6..5e01152870 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -31,6 +31,8 @@
#ifndef GD_MONO_H
#define GD_MONO_H
+#include "core/io/config_file.h"
+
#include "../godotsharp_defs.h"
#include "gd_mono_assembly.h"
#include "gd_mono_log.h"
@@ -39,6 +41,43 @@
#include "../utils/mono_reg_utils.h"
#endif
+namespace APIAssembly {
+enum Type {
+ API_CORE,
+ API_EDITOR
+};
+
+struct Version {
+ uint64_t godot_api_hash;
+ uint32_t bindings_version;
+ uint32_t cs_glue_version;
+
+ bool operator==(const Version &p_other) const {
+ return godot_api_hash == p_other.godot_api_hash &&
+ bindings_version == p_other.bindings_version &&
+ cs_glue_version == p_other.cs_glue_version;
+ }
+
+ Version() :
+ godot_api_hash(0),
+ bindings_version(0),
+ cs_glue_version(0) {
+ }
+
+ Version(uint64_t p_godot_api_hash,
+ uint32_t p_bindings_version,
+ uint32_t p_cs_glue_version) :
+ godot_api_hash(p_godot_api_hash),
+ bindings_version(p_bindings_version),
+ cs_glue_version(p_cs_glue_version) {
+ }
+
+ static Version get_from_loaded_assembly(GDMonoAssembly *p_api_assembly, Type p_api_type);
+};
+
+String to_string(Type p_type);
+} // namespace APIAssembly
+
#define SCRIPTS_DOMAIN GDMono::get_singleton()->get_scripts_domain()
#ifdef TOOLS_ENABLED
#define TOOLS_DOMAIN GDMono::get_singleton()->get_tools_domain()
@@ -55,8 +94,11 @@ class GDMono {
MonoDomain *tools_domain;
#endif
+ bool core_api_assembly_out_of_sync;
+ bool editor_api_assembly_out_of_sync;
+
GDMonoAssembly *corlib_assembly;
- GDMonoAssembly *api_assembly;
+ GDMonoAssembly *core_api_assembly;
GDMonoAssembly *project_assembly;
#ifdef TOOLS_ENABLED
GDMonoAssembly *editor_api_assembly;
@@ -75,7 +117,11 @@ class GDMono {
#endif
bool _load_project_assembly();
- bool _load_all_script_assemblies();
+ bool _load_api_assemblies();
+
+#ifdef TOOLS_ENABLED
+ String _get_api_assembly_metadata_path();
+#endif
void _register_internal_calls();
@@ -94,8 +140,6 @@ class GDMono {
void _initialize_and_check_api_hashes();
#endif
- bool _load_assembly(const String &p_name, GDMonoAssembly **r_assembly);
-
GDMonoLog *gdmono_log;
#ifdef WINDOWS_ENABLED
@@ -113,6 +157,11 @@ public:
#endif
#endif
+#ifdef TOOLS_ENABLED
+ void metadata_set_api_assembly_invalidated(APIAssembly::Type p_api_type, bool p_invalidated);
+ bool metadata_is_api_assembly_invalidated(APIAssembly::Type p_api_type);
+#endif
+
static GDMono *get_singleton() { return singleton; }
// Do not use these, unless you know what you're doing
@@ -128,7 +177,7 @@ public:
#endif
_FORCE_INLINE_ GDMonoAssembly *get_corlib_assembly() const { return corlib_assembly; }
- _FORCE_INLINE_ GDMonoAssembly *get_api_assembly() const { return api_assembly; }
+ _FORCE_INLINE_ GDMonoAssembly *get_core_api_assembly() const { return core_api_assembly; }
_FORCE_INLINE_ GDMonoAssembly *get_project_assembly() const { return project_assembly; }
#ifdef TOOLS_ENABLED
_FORCE_INLINE_ GDMonoAssembly *get_editor_api_assembly() const { return editor_api_assembly; }
@@ -145,6 +194,10 @@ public:
Error reload_scripts_domain();
#endif
+ bool load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly = false);
+ bool load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly = false);
+ Error finalize_and_unload_domain(MonoDomain *p_domain);
+
void initialize();
GDMono();
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index 19529dbcee..2ce1b0a9df 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -43,7 +43,23 @@
bool GDMonoAssembly::no_search = false;
Vector<String> GDMonoAssembly::search_dirs;
-MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_data) {
+MonoAssembly *GDMonoAssembly::assembly_search_hook(MonoAssemblyName *aname, void *user_data) {
+ return GDMonoAssembly::_search_hook(aname, user_data, false);
+}
+
+MonoAssembly *GDMonoAssembly::assembly_refonly_search_hook(MonoAssemblyName *aname, void *user_data) {
+ return GDMonoAssembly::_search_hook(aname, user_data, true);
+}
+
+MonoAssembly *GDMonoAssembly::assembly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) {
+ return GDMonoAssembly::_preload_hook(aname, assemblies_path, user_data, false);
+}
+
+MonoAssembly *GDMonoAssembly::assembly_refonly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) {
+ return GDMonoAssembly::_preload_hook(aname, assemblies_path, user_data, true);
+}
+
+MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_data, bool refonly) {
(void)user_data; // UNUSED
@@ -60,7 +76,7 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d
no_search = true; // Avoid the recursion madness
String path;
- MonoAssembly *res = NULL;
+ GDMonoAssembly *res = NULL;
for (int i = 0; i < search_dirs.size(); i++) {
const String &search_dir = search_dirs[i];
@@ -68,19 +84,19 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d
if (has_extension) {
path = search_dir.plus_file(name);
if (FileAccess::exists(path)) {
- res = _load_assembly_from(name.get_basename(), path);
+ res = _load_assembly_from(name.get_basename(), path, refonly);
break;
}
} else {
path = search_dir.plus_file(name + ".dll");
if (FileAccess::exists(path)) {
- res = _load_assembly_from(name, path);
+ res = _load_assembly_from(name, path, refonly);
break;
}
path = search_dir.plus_file(name + ".exe");
if (FileAccess::exists(path)) {
- res = _load_assembly_from(name, path);
+ res = _load_assembly_from(name, path, refonly);
break;
}
}
@@ -88,17 +104,15 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d
no_search = false;
- return res;
+ return res ? res->get_assembly() : NULL;
}
-MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) {
+MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly) {
(void)user_data; // UNUSED
if (search_dirs.empty()) {
-#ifdef TOOLS_DOMAIN
search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir());
-#endif
search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir());
search_dirs.push_back(OS::get_singleton()->get_resource_dir());
search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir());
@@ -119,38 +133,78 @@ MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **asse
}
}
+ String name = mono_assembly_name_get_name(aname);
+ bool has_extension = name.ends_with(".dll");
+
+ if (has_extension ? name == "mscorlib.dll" : name == "mscorlib") {
+ GDMonoAssembly **stored_assembly = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name);
+ if (stored_assembly)
+ return (*stored_assembly)->get_assembly();
+
+ String path;
+ GDMonoAssembly *res = NULL;
+
+ for (int i = 0; i < search_dirs.size(); i++) {
+ const String &search_dir = search_dirs[i];
+
+ if (has_extension) {
+ path = search_dir.plus_file(name);
+ if (FileAccess::exists(path)) {
+ res = _load_assembly_from(name.get_basename(), path, refonly);
+ break;
+ }
+ } else {
+ path = search_dir.plus_file(name + ".dll");
+ if (FileAccess::exists(path)) {
+ res = _load_assembly_from(name, path, refonly);
+ break;
+ }
+
+ path = search_dir.plus_file(name + ".exe");
+ if (FileAccess::exists(path)) {
+ res = _load_assembly_from(name, path, refonly);
+ break;
+ }
+ }
+ }
+
+ return res ? res->get_assembly() : NULL;
+ }
+
return NULL;
}
-MonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path) {
+GDMonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly) {
GDMonoAssembly *assembly = memnew(GDMonoAssembly(p_name, p_path));
- MonoDomain *domain = mono_domain_get();
-
- Error err = assembly->load(domain);
+ Error err = assembly->load(p_refonly);
if (err != OK) {
memdelete(assembly);
ERR_FAIL_V(NULL);
}
+ MonoDomain *domain = mono_domain_get();
GDMono::get_singleton()->add_assembly(domain ? mono_domain_get_id(domain) : 0, assembly);
- return assembly->get_assembly();
+ return assembly;
}
void GDMonoAssembly::initialize() {
- // TODO refonly as well?
- mono_install_assembly_preload_hook(&GDMonoAssembly::_preload_hook, NULL);
- mono_install_assembly_search_hook(&GDMonoAssembly::_search_hook, NULL);
+ mono_install_assembly_search_hook(&assembly_search_hook, NULL);
+ mono_install_assembly_refonly_search_hook(&assembly_refonly_search_hook, NULL);
+ mono_install_assembly_preload_hook(&assembly_preload_hook, NULL);
+ mono_install_assembly_refonly_preload_hook(&assembly_refonly_preload_hook, NULL);
}
-Error GDMonoAssembly::load(MonoDomain *p_domain) {
+Error GDMonoAssembly::load(bool p_refonly) {
ERR_FAIL_COND_V(loaded, ERR_FILE_ALREADY_IN_USE);
+ refonly = p_refonly;
+
uint64_t last_modified_time = FileAccess::get_modified_time(path);
Vector<uint8_t> data = FileAccess::get_file_as_array(path);
@@ -162,7 +216,7 @@ Error GDMonoAssembly::load(MonoDomain *p_domain) {
image = mono_image_open_from_data_with_name(
(char *)&data[0], data.size(),
- true, &status, false,
+ true, &status, refonly,
image_filename.utf8().get_data());
ERR_FAIL_COND_V(status != MONO_IMAGE_OK || image == NULL, ERR_FILE_CANT_OPEN);
@@ -185,15 +239,10 @@ no_pdb:
#endif
- assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, false);
+ assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, refonly);
ERR_FAIL_COND_V(status != MONO_IMAGE_OK || assembly == NULL, ERR_FILE_CANT_OPEN);
- if (p_domain && mono_image_get_entry_point(image)) {
- // TODO should this be removed? do we want to call main? what other effects does this have?
- mono_jit_exec(p_domain, assembly, 0, NULL);
- }
-
loaded = true;
modified_time = last_modified_time;
@@ -345,12 +394,26 @@ GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class)
return match;
}
+GDMonoAssembly *GDMonoAssembly::load_from(const String &p_name, const String &p_path, bool p_refonly) {
+
+ GDMonoAssembly **loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name);
+ if (loaded_asm)
+ return *loaded_asm;
+
+ no_search = true;
+ GDMonoAssembly *res = _load_assembly_from(p_name, p_path, p_refonly);
+ no_search = false;
+
+ return res;
+}
+
GDMonoAssembly::GDMonoAssembly(const String &p_name, const String &p_path) {
loaded = false;
gdobject_class_cache_updated = false;
name = p_name;
path = p_path;
+ refonly = false;
modified_time = 0;
assembly = NULL;
image = NULL;
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
index 8e7aa701bf..5cf744a5a2 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -71,6 +71,7 @@ class GDMonoAssembly {
MonoAssembly *assembly;
MonoImage *image;
+ bool refonly;
bool loaded;
String name;
@@ -90,19 +91,25 @@ class GDMonoAssembly {
static bool no_search;
static Vector<String> search_dirs;
- static MonoAssembly *_search_hook(MonoAssemblyName *aname, void *user_data);
- static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
+ static MonoAssembly *assembly_search_hook(MonoAssemblyName *aname, void *user_data);
+ static MonoAssembly *assembly_refonly_search_hook(MonoAssemblyName *aname, void *user_data);
+ static MonoAssembly *assembly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
+ static MonoAssembly *assembly_refonly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
- static MonoAssembly *_load_assembly_from(const String &p_name, const String &p_path);
+ static MonoAssembly *_search_hook(MonoAssemblyName *aname, void *user_data, bool refonly);
+ static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly);
+
+ static GDMonoAssembly *_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly);
friend class GDMono;
static void initialize();
public:
- Error load(MonoDomain *p_domain);
+ Error load(bool p_refonly);
Error wrapper_for_image(MonoImage *p_image);
void unload();
+ _FORCE_INLINE_ bool is_refonly() const { return refonly; }
_FORCE_INLINE_ bool is_loaded() const { return loaded; }
_FORCE_INLINE_ MonoImage *get_image() const { return image; }
_FORCE_INLINE_ MonoAssembly *get_assembly() const { return assembly; }
@@ -110,11 +117,13 @@ public:
_FORCE_INLINE_ String get_path() const { return path; }
_FORCE_INLINE_ uint64_t get_modified_time() const { return modified_time; }
- GDMonoClass *get_class(const StringName &p_namespace, const StringName &p_class);
+ GDMonoClass *get_class(const StringName &p_namespace, const StringName &p_name);
GDMonoClass *get_class(MonoClass *p_mono_class);
GDMonoClass *get_object_derived_class(const StringName &p_class);
+ static GDMonoAssembly *load_from(const String &p_name, const String &p_path, bool p_refonly);
+
GDMonoAssembly(const String &p_name, const String &p_path = String());
~GDMonoAssembly();
};
diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp
index b826352f02..66339d7ae6 100644
--- a/modules/mono/mono_gd/gd_mono_class.cpp
+++ b/modules/mono/mono_gd/gd_mono_class.cpp
@@ -404,6 +404,33 @@ const Vector<GDMonoProperty *> &GDMonoClass::get_all_properties() {
return properties_list;
}
+const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() {
+ if (delegates_fetched)
+ return delegates_list;
+
+ void *iter = NULL;
+ MonoClass *raw_class = NULL;
+ while ((raw_class = mono_class_get_nested_types(mono_class, &iter)) != NULL) {
+ if (mono_class_is_delegate(raw_class)) {
+ StringName name = mono_class_get_name(raw_class);
+
+ Map<StringName, GDMonoClass *>::Element *match = delegates.find(name);
+
+ if (match) {
+ delegates_list.push_back(match->get());
+ } else {
+ GDMonoClass *delegate = memnew(GDMonoClass(mono_class_get_namespace(raw_class), mono_class_get_name(raw_class), raw_class, assembly));
+ delegates.insert(name, delegate);
+ delegates_list.push_back(delegate);
+ }
+ }
+ }
+
+ delegates_fetched = true;
+
+ return delegates_list;
+}
+
GDMonoClass::GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly) {
namespace_name = p_namespace;
@@ -417,6 +444,7 @@ GDMonoClass::GDMonoClass(const StringName &p_namespace, const StringName &p_name
methods_fetched = false;
fields_fetched = false;
properties_fetched = false;
+ delegates_fetched = false;
}
GDMonoClass::~GDMonoClass() {
diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h
index f5895be144..417c138594 100644
--- a/modules/mono/mono_gd/gd_mono_class.h
+++ b/modules/mono/mono_gd/gd_mono_class.h
@@ -90,6 +90,10 @@ class GDMonoClass {
Map<StringName, GDMonoProperty *> properties;
Vector<GDMonoProperty *> properties_list;
+ bool delegates_fetched;
+ Map<StringName, GDMonoClass *> delegates;
+ Vector<GDMonoClass *> delegates_list;
+
friend class GDMonoAssembly;
GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly);
@@ -125,7 +129,7 @@ public:
GDMonoMethod *get_method(MonoMethod *p_raw_method);
GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name);
GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count);
- GDMonoMethod *get_method_with_desc(const String &p_description, bool p_includes_namespace);
+ GDMonoMethod *get_method_with_desc(const String &p_description, bool p_include_namespace);
GDMonoField *get_field(const StringName &p_name);
const Vector<GDMonoField *> &get_all_fields();
@@ -133,6 +137,8 @@ public:
GDMonoProperty *get_property(const StringName &p_name);
const Vector<GDMonoProperty *> &get_all_properties();
+ const Vector<GDMonoClass *> &get_all_delegates();
+
~GDMonoClass();
};
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index 1ec8f41c91..aa1a8e39c7 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -459,11 +459,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
type.type_encoding = mono_type_get_type(raw_type);
type.type_class = tclass;
- return mono_object_to_variant(p_obj, type);
-}
-
-Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) {
- switch (p_type.type_encoding) {
+ switch (type.type_encoding) {
case MONO_TYPE_BOOLEAN:
return (bool)unbox<MonoBoolean>(p_obj);
@@ -497,7 +493,7 @@ Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) {
} break;
case MONO_TYPE_VALUETYPE: {
- GDMonoClass *tclass = p_type.type_class;
+ GDMonoClass *tclass = type.type_class;
if (tclass == CACHED_CLASS(Vector2))
RETURN_UNBOXED_STRUCT(Vector2, p_obj);
@@ -535,7 +531,7 @@ Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) {
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY: {
- MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(p_type.type_class));
+ MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(type.type_class));
if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
return mono_array_to_Array((MonoArray *)p_obj);
@@ -566,7 +562,7 @@ Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) {
} break;
case MONO_TYPE_CLASS: {
- GDMonoClass *type_class = p_type.type_class;
+ GDMonoClass *type_class = type.type_class;
// GodotObject
if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
@@ -586,14 +582,14 @@ Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) {
} break;
case MONO_TYPE_GENERICINST: {
- if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_mono_ptr()) {
+ if (CACHED_RAW_MONO_CLASS(Dictionary) == type.type_class->get_mono_ptr()) {
return mono_object_to_Dictionary(p_obj);
}
} break;
}
ERR_EXPLAIN(String() + "Attempted to convert an unmarshallable managed type to Variant. Name: \'" +
- p_type.type_class->get_name() + "\' Encoding: " + itos(p_type.type_encoding));
+ type.type_class->get_name() + "\' Encoding: " + itos(type.type_encoding));
ERR_FAIL_V(Variant());
}
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index 727b9fa230..4e28622adb 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -102,7 +102,6 @@ _FORCE_INLINE_ MonoObject *variant_to_mono_object(Variant p_var) {
}
Variant mono_object_to_variant(MonoObject *p_obj);
-Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type);
// Array
@@ -196,13 +195,13 @@ Dictionary mono_object_to_Dictionary(MonoObject *p_dict);
// Transform
#define MARSHALLED_OUT_Transform(m_in, m_out) real_t m_out[12] = { \
- m_in.basis[0].x, m_in.basis[0].y, m_in.basis[0].z, \
- m_in.basis[1].x, m_in.basis[1].y, m_in.basis[1].z, \
- m_in.basis[2].x, m_in.basis[2].y, m_in.basis[2].z, \
+ m_in.basis[0].x, m_in.basis[1].x, m_in.basis[2].x, \
+ m_in.basis[0].y, m_in.basis[1].y, m_in.basis[2].y, \
+ m_in.basis[0].z, m_in.basis[1].z, m_in.basis[2].z, \
m_in.origin.x, m_in.origin.y, m_in.origin.z \
};
#define MARSHALLED_IN_Transform(m_in, m_out) Transform m_out( \
- Basis(m_in[0], m_in[1], m_in[2], m_in[3], m_in[4], m_in[5], m_in[6], m_in[7], m_in[8]), \
+ Basis(m_in[0], m_in[3], m_in[6], m_in[1], m_in[4], m_in[7], m_in[2], m_in[5], m_in[8]), \
Vector3(m_in[9], m_in[10], m_in[11]));
// AABB
diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp
index 1f8e9a1926..ad52904945 100644
--- a/modules/mono/mono_gd/gd_mono_method.cpp
+++ b/modules/mono/mono_gd/gd_mono_method.cpp
@@ -229,6 +229,23 @@ String GDMonoMethod::get_signature_desc(bool p_namespaces) const {
return res;
}
+void GDMonoMethod::get_parameter_names(Vector<StringName> &names) const {
+ if (params_count > 0) {
+ const char **_names = memnew_arr(const char *, params_count);
+ mono_method_get_param_names(mono_method, _names);
+ for (int i = 0; i < params_count; ++i) {
+ names.push_back(StringName(_names[i]));
+ }
+ memdelete_arr(_names);
+ }
+}
+
+void GDMonoMethod::get_parameter_types(Vector<ManagedType> &types) const {
+ for (int i = 0; i < param_types.size(); ++i) {
+ types.push_back(param_types[i]);
+ }
+}
+
GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) {
name = p_name;
diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h
index 14df8dcfb4..a173af83f4 100644
--- a/modules/mono/mono_gd/gd_mono_method.h
+++ b/modules/mono/mono_gd/gd_mono_method.h
@@ -80,6 +80,9 @@ public:
String get_ret_type_full_name() const;
String get_signature_desc(bool p_namespaces = false) const;
+ void get_parameter_names(Vector<StringName> &names) const;
+ void get_parameter_types(Vector<ManagedType> &types) const;
+
GDMonoMethod(StringName p_name, MonoMethod *p_method);
~GDMonoMethod();
};
diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp
index bc5a1d3a39..0fe527b199 100644
--- a/modules/mono/mono_gd/gd_mono_property.cpp
+++ b/modules/mono/mono_gd/gd_mono_property.cpp
@@ -139,7 +139,7 @@ bool GDMonoProperty::has_setter() {
}
void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoObject **r_exc) {
- MonoMethod *prop_method = mono_property_get_get_method(mono_property);
+ MonoMethod *prop_method = mono_property_get_set_method(mono_property);
MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1);
mono_array_set(params, MonoObject *, 0, p_value);
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index 835a4614c1..297992f625 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -114,6 +114,7 @@ void MonoCache::clear_members() {
class_ExportAttribute = NULL;
field_ExportAttribute_hint = NULL;
field_ExportAttribute_hintString = NULL;
+ class_SignalAttribute = NULL;
class_ToolAttribute = NULL;
class_RemoteAttribute = NULL;
class_SyncAttribute = NULL;
@@ -142,7 +143,7 @@ void MonoCache::cleanup() {
godot_api_cache_updated = false;
}
-#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class))
+#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class))
void update_corlib_cache() {
@@ -184,7 +185,7 @@ void update_godot_api_cache() {
CACHE_CLASS_AND_CHECK(Color, GODOT_API_CLASS(Color));
CACHE_CLASS_AND_CHECK(Plane, GODOT_API_CLASS(Plane));
CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath));
- CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(NodePath));
+ CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(RID));
CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object));
CACHE_CLASS_AND_CHECK(GodotReference, GODOT_API_CLASS(Reference));
CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node));
@@ -201,6 +202,7 @@ void update_godot_api_cache() {
CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute));
CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint"));
CACHE_FIELD_AND_CHECK(ExportAttribute, hintString, CACHED_CLASS(ExportAttribute)->get_field("hintString"));
+ CACHE_CLASS_AND_CHECK(SignalAttribute, GODOT_API_CLASS(SignalAttribute));
CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute));
CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute));
CACHE_CLASS_AND_CHECK(SyncAttribute, GODOT_API_CLASS(SyncAttribute));
@@ -243,7 +245,7 @@ void update_godot_api_cache() {
mono_runtime_object_init(task_scheduler);
mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler);
- mono_cache.corlib_cache_updated = true;
+ mono_cache.godot_api_cache_updated = true;
}
void clear_cache() {
@@ -303,7 +305,7 @@ GDMonoClass *type_get_proxy_class(const StringName &p_type) {
if (class_name[0] == '_')
class_name = class_name.substr(1, class_name.length());
- GDMonoClass *klass = GDMono::get_singleton()->get_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name);
+ GDMonoClass *klass = GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name);
#ifdef TOOLS_ENABLED
if (!klass) {
@@ -319,7 +321,7 @@ GDMonoClass *get_class_native_base(GDMonoClass *p_class) {
do {
const GDMonoAssembly *assembly = klass->get_assembly();
- if (assembly == GDMono::get_singleton()->get_api_assembly())
+ if (assembly == GDMono::get_singleton()->get_core_api_assembly())
return klass;
#ifdef TOOLS_ENABLED
if (assembly == GDMono::get_singleton()->get_editor_api_assembly())
@@ -418,37 +420,56 @@ void print_unhandled_exception(MonoObject *p_exc, bool p_recursion_caution) {
if (!ScriptDebugger::get_singleton())
return;
- GDMonoClass *st_klass = CACHED_CLASS(System_Diagnostics_StackTrace);
- MonoObject *stack_trace = mono_object_new(mono_domain_get(), st_klass->get_mono_ptr());
+ ScriptLanguage::StackInfo separator;
+ separator.file = "";
+ separator.func = "--- " + TTR("End of inner exception stack trace") + " ---";
+ separator.line = 0;
+
+ Vector<ScriptLanguage::StackInfo> si;
+ String exc_msg = "";
+
+ while (p_exc != NULL) {
+ GDMonoClass *st_klass = CACHED_CLASS(System_Diagnostics_StackTrace);
+ MonoObject *stack_trace = mono_object_new(mono_domain_get(), st_klass->get_mono_ptr());
- MonoBoolean need_file_info = true;
- void *ctor_args[2] = { p_exc, &need_file_info };
+ MonoBoolean need_file_info = true;
+ void *ctor_args[2] = { p_exc, &need_file_info };
- MonoObject *unexpected_exc = NULL;
- CACHED_METHOD(System_Diagnostics_StackTrace, ctor_Exception_bool)->invoke_raw(stack_trace, ctor_args, &unexpected_exc);
+ MonoObject *unexpected_exc = NULL;
+ CACHED_METHOD(System_Diagnostics_StackTrace, ctor_Exception_bool)->invoke_raw(stack_trace, ctor_args, &unexpected_exc);
- if (unexpected_exc != NULL) {
- mono_print_unhandled_exception(unexpected_exc);
+ if (unexpected_exc != NULL) {
+ mono_print_unhandled_exception(unexpected_exc);
- if (p_recursion_caution) {
- // Called from CSharpLanguage::get_current_stack_info,
- // so printing an error here could result in endless recursion
- OS::get_singleton()->printerr("Mono: Method GDMonoUtils::print_unhandled_exception failed");
- return;
- } else {
- ERR_FAIL();
+ if (p_recursion_caution) {
+ // Called from CSharpLanguage::get_current_stack_info,
+ // so printing an error here could result in endless recursion
+ OS::get_singleton()->printerr("Mono: Method GDMonoUtils::print_unhandled_exception failed");
+ return;
+ } else {
+ ERR_FAIL();
+ }
}
- }
- Vector<ScriptLanguage::StackInfo> si;
- if (stack_trace != NULL && !p_recursion_caution)
- si = CSharpLanguage::get_singleton()->stack_trace_get_info(stack_trace);
+ Vector<ScriptLanguage::StackInfo> _si;
+ if (stack_trace != NULL && !p_recursion_caution) {
+ _si = CSharpLanguage::get_singleton()->stack_trace_get_info(stack_trace);
+ for (int i = _si.size() - 1; i >= 0; i--)
+ si.insert(0, _si[i]);
+ }
+
+ exc_msg += (exc_msg.length() > 0 ? " ---> " : "") + GDMonoUtils::get_exception_name_and_message(p_exc);
+
+ GDMonoProperty *p_prop = GDMono::get_singleton()->get_class(mono_object_get_class(p_exc))->get_property("InnerException");
+ p_exc = p_prop != NULL ? p_prop->get_value(p_exc) : NULL;
+ if (p_exc != NULL)
+ si.insert(0, separator);
+ }
String file = si.size() ? si[0].file : __FILE__;
String func = si.size() ? si[0].func : FUNCTION_STR;
int line = si.size() ? si[0].line : __LINE__;
String error_msg = "Unhandled exception";
- String exc_msg = GDMonoUtils::get_exception_name_and_message(p_exc);
ScriptDebugger::get_singleton()->send_error(func, file, line, error_msg, exc_msg, ERR_HANDLER_ERROR, si);
#endif
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index 2666433170..1a34180d15 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -43,7 +43,7 @@ namespace GDMonoUtils {
typedef MonoObject *(*MarshalUtils_DictToArrays)(MonoObject *, MonoArray **, MonoArray **, MonoObject **);
typedef MonoObject *(*MarshalUtils_ArraysToDict)(MonoArray *, MonoArray *, MonoObject **);
-typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray **, MonoObject **);
+typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoObject **);
typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoObject **);
typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoObject **);
typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoObject **);
@@ -108,6 +108,7 @@ struct MonoCache {
GDMonoClass *class_ExportAttribute;
GDMonoField *field_ExportAttribute_hint;
GDMonoField *field_ExportAttribute_hintString;
+ GDMonoClass *class_SignalAttribute;
GDMonoClass *class_ToolAttribute;
GDMonoClass *class_RemoteAttribute;
GDMonoClass *class_SyncAttribute;
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index 2671e9a970..b9d8520ac9 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -102,7 +102,7 @@ Variant SignalAwaiterHandle::_signal_callback(const Variant **p_args, int p_argc
GDMonoUtils::SignalAwaiter_SignalCallback thunk = CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback);
MonoObject *ex = NULL;
- thunk(get_target(), &signal_args, &ex);
+ thunk(get_target(), signal_args, &ex);
if (ex) {
mono_print_unhandled_exception(ex);
diff --git a/modules/openssl/SCsub b/modules/openssl/SCsub
deleted file mode 100644
index 84c5e68439..0000000000
--- a/modules/openssl/SCsub
+++ /dev/null
@@ -1,696 +0,0 @@
-#!/usr/bin/env python
-
-Import('env')
-Import('env_modules')
-
-env_openssl = env_modules.Clone()
-
-# Thirdparty source files
-if env['builtin_openssl']:
- thirdparty_dir = "#thirdparty/openssl/"
-
- thirdparty_sources = [
- "ssl/t1_lib.c",
- "ssl/t1_ext.c",
- "ssl/s3_srvr.c",
- "ssl/t1_enc.c",
- "ssl/t1_meth.c",
- "ssl/s23_clnt.c",
- "ssl/ssl_asn1.c",
- "ssl/tls_srp.c",
- "ssl/kssl.c",
- "ssl/d1_both.c",
- "ssl/t1_clnt.c",
- "ssl/bio_ssl.c",
- "ssl/d1_srtp.c",
- "ssl/t1_reneg.c",
- "ssl/ssl_cert.c",
- "ssl/s3_lib.c",
- "ssl/d1_srvr.c",
- "ssl/s23_meth.c",
- "ssl/ssl_stat.c",
- "ssl/ssl_err.c",
- "ssl/ssl_algs.c",
- "ssl/s3_cbc.c",
- "ssl/d1_clnt.c",
- "ssl/s3_pkt.c",
- "ssl/d1_meth.c",
- "ssl/s3_both.c",
- "ssl/s2_enc.c",
- "ssl/s3_meth.c",
- "ssl/s3_enc.c",
- "ssl/s23_pkt.c",
- "ssl/s2_pkt.c",
- "ssl/d1_pkt.c",
- "ssl/ssl_rsa.c",
- "ssl/s23_srvr.c",
- "ssl/s2_meth.c",
- "ssl/s3_clnt.c",
- "ssl/s23_lib.c",
- "ssl/t1_srvr.c",
- "ssl/ssl_lib.c",
- "ssl/ssl_txt.c",
- "ssl/s2_srvr.c",
- "ssl/ssl_sess.c",
- "ssl/s2_clnt.c",
- "ssl/d1_lib.c",
- "ssl/s2_lib.c",
- "ssl/ssl_err2.c",
- "ssl/ssl_ciph.c",
- "crypto/dsa/dsa_lib.c",
- "crypto/dsa/dsa_pmeth.c",
- "crypto/dsa/dsa_ossl.c",
- "crypto/dsa/dsa_gen.c",
- "crypto/dsa/dsa_asn1.c",
- "crypto/dsa/dsa_prn.c",
- "crypto/dsa/dsa_sign.c",
- "crypto/dsa/dsa_key.c",
- "crypto/dsa/dsa_vrf.c",
- "crypto/dsa/dsa_err.c",
- "crypto/dsa/dsa_ameth.c",
- "crypto/dsa/dsa_depr.c",
- "crypto/x509/x509_lu.c",
- "crypto/x509/x509cset.c",
- "crypto/x509/x509_set.c",
- "crypto/x509/x509_d2.c",
- "crypto/x509/x509_txt.c",
- "crypto/x509/x509rset.c",
- "crypto/x509/by_dir.c",
- "crypto/x509/x509_vpm.c",
- "crypto/x509/x509_vfy.c",
- "crypto/x509/x509_trs.c",
- "crypto/x509/by_file.c",
- "crypto/x509/x509_obj.c",
- "crypto/x509/x509spki.c",
- "crypto/x509/x509_v3.c",
- "crypto/x509/x509_req.c",
- "crypto/x509/x509_att.c",
- "crypto/x509/x_all.c",
- "crypto/x509/x509_ext.c",
- "crypto/x509/x509type.c",
- "crypto/x509/x509_def.c",
- "crypto/x509/x509_err.c",
- "crypto/x509/x509name.c",
- "crypto/x509/x509_r2x.c",
- "crypto/x509/x509_cmp.c",
- "crypto/asn1/x_pkey.c",
- "crypto/asn1/a_gentm.c",
- "crypto/asn1/x_sig.c",
- "crypto/asn1/t_req.c",
- "crypto/asn1/t_pkey.c",
- "crypto/asn1/p8_pkey.c",
- "crypto/asn1/a_i2d_fp.c",
- "crypto/asn1/x_val.c",
- "crypto/asn1/f_string.c",
- "crypto/asn1/p5_pbe.c",
- "crypto/asn1/bio_ndef.c",
- "crypto/asn1/a_bool.c",
- "crypto/asn1/asn1_gen.c",
- "crypto/asn1/x_algor.c",
- "crypto/asn1/bio_asn1.c",
- "crypto/asn1/asn_mime.c",
- "crypto/asn1/t_x509.c",
- "crypto/asn1/a_strex.c",
- "crypto/asn1/x_nx509.c",
- "crypto/asn1/asn1_err.c",
- "crypto/asn1/x_crl.c",
- "crypto/asn1/a_print.c",
- "crypto/asn1/a_type.c",
- "crypto/asn1/tasn_new.c",
- "crypto/asn1/n_pkey.c",
- "crypto/asn1/x_bignum.c",
- "crypto/asn1/asn_pack.c",
- "crypto/asn1/evp_asn1.c",
- "crypto/asn1/t_bitst.c",
- "crypto/asn1/x_req.c",
- "crypto/asn1/a_time.c",
- "crypto/asn1/x_name.c",
- "crypto/asn1/x_pubkey.c",
- "crypto/asn1/tasn_typ.c",
- "crypto/asn1/asn_moid.c",
- "crypto/asn1/a_utctm.c",
- "crypto/asn1/asn1_lib.c",
- "crypto/asn1/x_x509a.c",
- "crypto/asn1/a_set.c",
- "crypto/asn1/t_crl.c",
- "crypto/asn1/p5_pbev2.c",
- "crypto/asn1/tasn_enc.c",
- "crypto/asn1/a_mbstr.c",
- "crypto/asn1/tasn_dec.c",
- "crypto/asn1/x_x509.c",
- "crypto/asn1/a_octet.c",
- "crypto/asn1/x_long.c",
- "crypto/asn1/a_bytes.c",
- "crypto/asn1/t_x509a.c",
- "crypto/asn1/a_enum.c",
- "crypto/asn1/a_int.c",
- "crypto/asn1/tasn_prn.c",
- "crypto/asn1/i2d_pr.c",
- "crypto/asn1/a_utf8.c",
- "crypto/asn1/t_spki.c",
- "crypto/asn1/a_digest.c",
- "crypto/asn1/a_dup.c",
- "crypto/asn1/i2d_pu.c",
- "crypto/asn1/a_verify.c",
- "crypto/asn1/f_enum.c",
- "crypto/asn1/a_sign.c",
- "crypto/asn1/d2i_pr.c",
- "crypto/asn1/asn1_par.c",
- "crypto/asn1/x_spki.c",
- "crypto/asn1/a_d2i_fp.c",
- "crypto/asn1/f_int.c",
- "crypto/asn1/x_exten.c",
- "crypto/asn1/tasn_utl.c",
- "crypto/asn1/nsseq.c",
- "crypto/asn1/a_bitstr.c",
- "crypto/asn1/x_info.c",
- "crypto/asn1/a_strnid.c",
- "crypto/asn1/a_object.c",
- "crypto/asn1/tasn_fre.c",
- "crypto/asn1/d2i_pu.c",
- "crypto/asn1/ameth_lib.c",
- "crypto/asn1/x_attrib.c",
- "crypto/evp/m_sha.c",
- "crypto/evp/e_camellia.c",
- "crypto/evp/e_aes.c",
- "crypto/evp/bio_b64.c",
- "crypto/evp/m_sigver.c",
- "crypto/evp/m_wp.c",
- "crypto/evp/m_sha1.c",
- "crypto/evp/p_seal.c",
- "crypto/evp/c_alld.c",
- "crypto/evp/p5_crpt.c",
- "crypto/evp/e_rc4.c",
- "crypto/evp/m_ecdsa.c",
- "crypto/evp/bio_enc.c",
- "crypto/evp/e_des3.c",
- "crypto/evp/m_null.c",
- "crypto/evp/bio_ok.c",
- "crypto/evp/pmeth_gn.c",
- "crypto/evp/e_rc5.c",
- "crypto/evp/e_rc2.c",
- "crypto/evp/p_dec.c",
- "crypto/evp/p_verify.c",
- "crypto/evp/e_rc4_hmac_md5.c",
- "crypto/evp/pmeth_lib.c",
- "crypto/evp/m_ripemd.c",
- "crypto/evp/m_md5.c",
- "crypto/evp/e_bf.c",
- "crypto/evp/p_enc.c",
- "crypto/evp/m_dss.c",
- "crypto/evp/bio_md.c",
- "crypto/evp/evp_pbe.c",
- "crypto/evp/e_seed.c",
- "crypto/evp/e_cast.c",
- "crypto/evp/p_open.c",
- "crypto/evp/p5_crpt2.c",
- "crypto/evp/m_dss1.c",
- "crypto/evp/names.c",
- "crypto/evp/evp_acnf.c",
- "crypto/evp/e_des.c",
- "crypto/evp/evp_cnf.c",
- "crypto/evp/evp_lib.c",
- "crypto/evp/digest.c",
- "crypto/evp/evp_err.c",
- "crypto/evp/evp_enc.c",
- "crypto/evp/e_old.c",
- "crypto/evp/c_all.c",
- "crypto/evp/m_md2.c",
- "crypto/evp/e_xcbc_d.c",
- "crypto/evp/pmeth_fn.c",
- "crypto/evp/p_lib.c",
- "crypto/evp/evp_key.c",
- "crypto/evp/encode.c",
- "crypto/evp/e_aes_cbc_hmac_sha1.c",
- "crypto/evp/e_aes_cbc_hmac_sha256.c",
- "crypto/evp/m_mdc2.c",
- "crypto/evp/e_null.c",
- "crypto/evp/p_sign.c",
- "crypto/evp/e_idea.c",
- "crypto/evp/c_allc.c",
- "crypto/evp/evp_pkey.c",
- "crypto/evp/m_md4.c",
- "crypto/ex_data.c",
- "crypto/pkcs12/p12_p8e.c",
- "crypto/pkcs12/p12_crt.c",
- "crypto/pkcs12/p12_utl.c",
- "crypto/pkcs12/p12_attr.c",
- "crypto/pkcs12/p12_npas.c",
- "crypto/pkcs12/p12_decr.c",
- "crypto/pkcs12/p12_init.c",
- "crypto/pkcs12/p12_kiss.c",
- "crypto/pkcs12/p12_add.c",
- "crypto/pkcs12/p12_p8d.c",
- "crypto/pkcs12/p12_mutl.c",
- "crypto/pkcs12/p12_crpt.c",
- "crypto/pkcs12/pk12err.c",
- "crypto/pkcs12/p12_asn.c",
- "crypto/pkcs12/p12_key.c",
- "crypto/ecdh/ech_key.c",
- "crypto/ecdh/ech_ossl.c",
- "crypto/ecdh/ech_lib.c",
- "crypto/ecdh/ech_err.c",
- "crypto/ecdh/ech_kdf.c",
- "crypto/o_str.c",
- "crypto/conf/conf_api.c",
- "crypto/conf/conf_err.c",
- "crypto/conf/conf_def.c",
- "crypto/conf/conf_lib.c",
- "crypto/conf/conf_mall.c",
- "crypto/conf/conf_sap.c",
- "crypto/conf/conf_mod.c",
- "crypto/ebcdic.c",
- "crypto/ecdsa/ecs_lib.c",
- "crypto/ecdsa/ecs_asn1.c",
- "crypto/ecdsa/ecs_ossl.c",
- "crypto/ecdsa/ecs_vrf.c",
- "crypto/ecdsa/ecs_sign.c",
- "crypto/ecdsa/ecs_err.c",
- "crypto/dso/dso_win32.c",
- "crypto/dso/dso_lib.c",
- "crypto/dso/dso_dlfcn.c",
- "crypto/dso/dso_dl.c",
- "crypto/dso/dso_beos.c",
- "crypto/dso/dso_null.c",
- "crypto/dso/dso_vms.c",
- "crypto/dso/dso_err.c",
- "crypto/dso/dso_openssl.c",
- "crypto/cryptlib.c",
- "crypto/md5/md5_one.c",
- "crypto/md5/md5_dgst.c",
- "crypto/pkcs7/pkcs7err.c",
- "crypto/pkcs7/pk7_smime.c",
- "crypto/pkcs7/bio_pk7.c",
- "crypto/pkcs7/pk7_mime.c",
- "crypto/pkcs7/pk7_lib.c",
- "crypto/pkcs7/pk7_asn1.c",
- "crypto/pkcs7/pk7_doit.c",
- "crypto/pkcs7/pk7_attr.c",
- "crypto/md4/md4_one.c",
- "crypto/md4/md4_dgst.c",
- "crypto/o_dir.c",
- "crypto/buffer/buf_err.c",
- "crypto/buffer/buf_str.c",
- "crypto/buffer/buffer.c",
- "crypto/cms/cms_lib.c",
- "crypto/cms/cms_io.c",
- "crypto/cms/cms_err.c",
- "crypto/cms/cms_dd.c",
- "crypto/cms/cms_smime.c",
- "crypto/cms/cms_att.c",
- "crypto/cms/cms_pwri.c",
- "crypto/cms/cms_cd.c",
- "crypto/cms/cms_sd.c",
- "crypto/cms/cms_asn1.c",
- "crypto/cms/cms_env.c",
- "crypto/cms/cms_enc.c",
- "crypto/cms/cms_ess.c",
- "crypto/cms/cms_kari.c",
- "crypto/mem_dbg.c",
- "crypto/uid.c",
- "crypto/stack/stack.c",
- "crypto/ec/ec_ameth.c",
- "crypto/ec/ec_err.c",
- "crypto/ec/ec_lib.c",
- "crypto/ec/ec_curve.c",
- "crypto/ec/ec_oct.c",
- "crypto/ec/ec_asn1.c",
- "crypto/ec/ecp_oct.c",
- "crypto/ec/ec_print.c",
- "crypto/ec/ec2_smpl.c",
- "crypto/ec/ecp_nistp224.c",
- "crypto/ec/ec2_oct.c",
- "crypto/ec/eck_prn.c",
- "crypto/ec/ec_key.c",
- "crypto/ec/ecp_nist.c",
- "crypto/ec/ec_check.c",
- "crypto/ec/ecp_smpl.c",
- "crypto/ec/ec2_mult.c",
- "crypto/ec/ecp_mont.c",
- "crypto/ec/ecp_nistp521.c",
- "crypto/ec/ec_mult.c",
- "crypto/ec/ecp_nistputil.c",
- "crypto/ec/ec_pmeth.c",
- "crypto/ec/ec_cvt.c",
- "crypto/ec/ecp_nistp256.c",
- "crypto/krb5/krb5_asn.c",
- "crypto/hmac/hmac.c",
- "crypto/hmac/hm_ameth.c",
- "crypto/hmac/hm_pmeth.c",
- "crypto/comp/c_rle.c",
- "crypto/comp/c_zlib.c",
- "crypto/comp/comp_lib.c",
- "crypto/comp/comp_err.c",
- "crypto/des/fcrypt.c",
- "crypto/des/str2key.c",
- "crypto/des/cbc_cksm.c",
- "crypto/des/des_enc.c",
- "crypto/des/ofb_enc.c",
- "crypto/des/read2pwd.c",
- "crypto/des/ecb3_enc.c",
- "crypto/des/rand_key.c",
- "crypto/des/cfb64ede.c",
- "crypto/des/rpc_enc.c",
- "crypto/des/ofb64ede.c",
- "crypto/des/qud_cksm.c",
- "crypto/des/enc_writ.c",
- "crypto/des/set_key.c",
- "crypto/des/xcbc_enc.c",
- "crypto/des/fcrypt_b.c",
- "crypto/des/ede_cbcm_enc.c",
- "crypto/des/des_old2.c",
- "crypto/des/cfb_enc.c",
- "crypto/des/ecb_enc.c",
- "crypto/des/enc_read.c",
- "crypto/des/des_old.c",
- "crypto/des/ofb64enc.c",
- "crypto/des/pcbc_enc.c",
- "crypto/des/cbc_enc.c",
- "crypto/des/cfb64enc.c",
- "crypto/lhash/lh_stats.c",
- "crypto/lhash/lhash.c",
- "crypto/x509v3/v3_genn.c",
- "crypto/x509v3/pcy_cache.c",
- "crypto/x509v3/v3_sxnet.c",
- "crypto/x509v3/v3_scts.c",
- "crypto/x509v3/v3err.c",
- "crypto/x509v3/v3_conf.c",
- "crypto/x509v3/v3_utl.c",
- "crypto/x509v3/v3_akeya.c",
- "crypto/x509v3/v3_lib.c",
- "crypto/x509v3/pcy_lib.c",
- "crypto/x509v3/v3_cpols.c",
- "crypto/x509v3/v3_ia5.c",
- "crypto/x509v3/v3_bitst.c",
- "crypto/x509v3/v3_skey.c",
- "crypto/x509v3/v3_info.c",
- "crypto/x509v3/v3_asid.c",
- "crypto/x509v3/pcy_tree.c",
- "crypto/x509v3/v3_pcons.c",
- "crypto/x509v3/v3_bcons.c",
- "crypto/x509v3/v3_pku.c",
- "crypto/x509v3/v3_ocsp.c",
- "crypto/x509v3/pcy_map.c",
- "crypto/x509v3/v3_ncons.c",
- "crypto/x509v3/v3_purp.c",
- "crypto/x509v3/v3_enum.c",
- "crypto/x509v3/v3_pmaps.c",
- "crypto/x509v3/pcy_node.c",
- "crypto/x509v3/v3_pcia.c",
- "crypto/x509v3/v3_crld.c",
- "crypto/x509v3/v3_pci.c",
- "crypto/x509v3/v3_akey.c",
- "crypto/x509v3/v3_addr.c",
- "crypto/x509v3/v3_int.c",
- "crypto/x509v3/v3_alt.c",
- "crypto/x509v3/v3_extku.c",
- "crypto/x509v3/v3_prn.c",
- "crypto/x509v3/pcy_data.c",
- "crypto/aes/aes_ofb.c",
- "crypto/aes/aes_ctr.c",
- "crypto/aes/aes_ecb.c",
- "crypto/aes/aes_cfb.c",
- "crypto/aes/aes_wrap.c",
- "crypto/aes/aes_ige.c",
- "crypto/aes/aes_misc.c",
- "crypto/pqueue/pqueue.c",
- "crypto/sha/sha_one.c",
- "crypto/sha/sha_dgst.c",
- "crypto/sha/sha512.c",
- "crypto/sha/sha1_one.c",
- "crypto/sha/sha1dgst.c",
- "crypto/sha/sha256.c",
- "crypto/whrlpool/wp_dgst.c",
- "crypto/objects/obj_xref.c",
- "crypto/objects/o_names.c",
- "crypto/objects/obj_err.c",
- "crypto/objects/obj_dat.c",
- "crypto/objects/obj_lib.c",
- "crypto/mem.c",
- "crypto/fips_ers.c",
- "crypto/o_fips.c",
- "crypto/engine/eng_rdrand.c",
- "crypto/engine/eng_err.c",
- "crypto/engine/tb_ecdsa.c",
- "crypto/engine/tb_rsa.c",
- "crypto/engine/tb_cipher.c",
- "crypto/engine/tb_dsa.c",
- "crypto/engine/eng_lib.c",
- "crypto/engine/tb_asnmth.c",
- "crypto/engine/tb_ecdh.c",
- "crypto/engine/tb_dh.c",
- "crypto/engine/tb_store.c",
- "crypto/engine/eng_init.c",
- "crypto/engine/eng_cnf.c",
- "crypto/engine/eng_all.c",
- "crypto/engine/tb_digest.c",
- "crypto/engine/tb_pkmeth.c",
- "crypto/engine/eng_table.c",
- "crypto/engine/eng_ctrl.c",
- "crypto/engine/eng_list.c",
- "crypto/engine/eng_cryptodev.c",
- "crypto/engine/eng_pkey.c",
- "crypto/engine/tb_rand.c",
- "crypto/engine/eng_openssl.c",
- "crypto/engine/eng_fat.c",
- "crypto/engine/eng_dyn.c",
- "crypto/ts/ts_rsp_verify.c",
- "crypto/ts/ts_req_print.c",
- "crypto/ts/ts_verify_ctx.c",
- "crypto/ts/ts_req_utils.c",
- "crypto/ts/ts_err.c",
- "crypto/ts/ts_rsp_print.c",
- "crypto/ts/ts_rsp_utils.c",
- "crypto/ts/ts_lib.c",
- "crypto/ts/ts_conf.c",
- "crypto/ts/ts_asn1.c",
- "crypto/ts/ts_rsp_sign.c",
- "crypto/ocsp/ocsp_ext.c",
- "crypto/ocsp/ocsp_cl.c",
- "crypto/ocsp/ocsp_ht.c",
- "crypto/ocsp/ocsp_lib.c",
- "crypto/ocsp/ocsp_srv.c",
- "crypto/ocsp/ocsp_vfy.c",
- "crypto/ocsp/ocsp_err.c",
- "crypto/ocsp/ocsp_prn.c",
- "crypto/ocsp/ocsp_asn.c",
- "crypto/bf/bf_cfb64.c",
- "crypto/bf/bf_ecb.c",
- "crypto/bf/bf_enc.c",
- "crypto/bf/bf_skey.c",
- "crypto/bf/bf_ofb64.c",
- "crypto/idea/i_skey.c",
- "crypto/idea/i_ofb64.c",
- "crypto/idea/i_cbc.c",
- "crypto/idea/i_ecb.c",
- "crypto/idea/i_cfb64.c",
- "crypto/cmac/cm_ameth.c",
- "crypto/cmac/cmac.c",
- "crypto/cmac/cm_pmeth.c",
- "crypto/dh/dh_lib.c",
- "crypto/dh/dh_key.c",
- "crypto/dh/dh_asn1.c",
- "crypto/dh/dh_depr.c",
- "crypto/dh/dh_pmeth.c",
- "crypto/dh/dh_prn.c",
- "crypto/dh/dh_gen.c",
- "crypto/dh/dh_ameth.c",
- "crypto/dh/dh_check.c",
- "crypto/dh/dh_err.c",
- "crypto/dh/dh_kdf.c",
- "crypto/dh/dh_rfc5114.c",
- "crypto/modes/ccm128.c",
- "crypto/modes/ofb128.c",
- "crypto/modes/cts128.c",
- "crypto/modes/ctr128.c",
- "crypto/modes/gcm128.c",
- "crypto/modes/cbc128.c",
- "crypto/modes/cfb128.c",
- "crypto/modes/xts128.c",
- "crypto/modes/wrap128.c",
- "crypto/camellia/cmll_cfb.c",
- "crypto/camellia/cmll_ecb.c",
- "crypto/camellia/cmll_utl.c",
- "crypto/camellia/cmll_misc.c",
- "crypto/camellia/cmll_ofb.c",
- "crypto/camellia/cmll_ctr.c",
- "crypto/seed/seed_ecb.c",
- "crypto/seed/seed_cbc.c",
- "crypto/seed/seed.c",
- "crypto/seed/seed_ofb.c",
- "crypto/seed/seed_cfb.c",
- "crypto/txt_db/txt_db.c",
- "crypto/cpt_err.c",
- "crypto/pem/pem_pk8.c",
- "crypto/pem/pem_lib.c",
- "crypto/pem/pem_sign.c",
- "crypto/pem/pem_all.c",
- "crypto/pem/pem_info.c",
- "crypto/pem/pem_pkey.c",
- "crypto/pem/pem_seal.c",
- "crypto/pem/pem_err.c",
- "crypto/pem/pem_xaux.c",
- "crypto/pem/pvkfmt.c",
- "crypto/pem/pem_x509.c",
- "crypto/pem/pem_oth.c",
- "crypto/rand/rand_lib.c",
- "crypto/rand/randfile.c",
- "crypto/rand/rand_os2.c",
- "crypto/rand/rand_unix.c",
- "crypto/rand/rand_nw.c",
- "crypto/rand/md_rand.c",
- "crypto/rand/rand_err.c",
- "crypto/rand/rand_win.c",
- "crypto/rand/rand_egd.c",
- "crypto/cversion.c",
- "crypto/cast/c_ecb.c",
- "crypto/cast/c_skey.c",
- "crypto/cast/c_ofb64.c",
- "crypto/cast/c_enc.c",
- "crypto/cast/c_cfb64.c",
- "crypto/o_time.c",
- "crypto/mdc2/mdc2dgst.c",
- "crypto/mdc2/mdc2_one.c",
- "crypto/rc4/rc4_utl.c",
- "crypto/ui/ui_compat.c",
- "crypto/ui/ui_util.c",
- "crypto/ui/ui_lib.c",
- "crypto/ui/ui_err.c",
- "crypto/ui/ui_openssl.c",
- "crypto/bio/bf_buff.c",
- "crypto/bio/bss_null.c",
- "crypto/bio/bss_acpt.c",
- "crypto/bio/bss_conn.c",
- "crypto/bio/bss_fd.c",
- "crypto/bio/bf_null.c",
- "crypto/bio/bio_err.c",
- "crypto/bio/bss_sock.c",
- "crypto/bio/bss_mem.c",
- "crypto/bio/b_dump.c",
- "crypto/bio/b_print.c",
- "crypto/bio/b_sock.c",
- "crypto/bio/bss_dgram.c",
- "crypto/bio/bf_nbio.c",
- "crypto/bio/bio_lib.c",
- "crypto/bio/bss_file.c",
- "crypto/bio/bss_bio.c",
- "crypto/bio/bss_log.c",
- "crypto/bio/bio_cb.c",
- "crypto/o_init.c",
- "crypto/rc2/rc2_skey.c",
- "crypto/rc2/rc2_cbc.c",
- "crypto/rc2/rc2cfb64.c",
- "crypto/rc2/rc2_ecb.c",
- "crypto/rc2/rc2ofb64.c",
- "crypto/bn/bn_x931p.c",
- "crypto/bn/bn_blind.c",
- "crypto/bn/bn_gf2m.c",
- "crypto/bn/bn_const.c",
- "crypto/bn/bn_sqr.c",
- "crypto/bn/bn_nist.c",
- "crypto/bn/bn_rand.c",
- "crypto/bn/bn_err.c",
- "crypto/bn/bn_div.c",
- "crypto/bn/bn_kron.c",
- "crypto/bn/bn_ctx.c",
- "crypto/bn/bn_shift.c",
- "crypto/bn/bn_mod.c",
- "crypto/bn/bn_exp2.c",
- "crypto/bn/bn_word.c",
- "crypto/bn/bn_add.c",
- "crypto/bn/bn_exp.c",
- "crypto/bn/bn_mont.c",
- "crypto/bn/bn_print.c",
- "crypto/bn/bn_mul.c",
- "crypto/bn/bn_prime.c",
- "crypto/bn/bn_depr.c",
- "crypto/bn/bn_gcd.c",
- "crypto/bn/bn_mpi.c",
- "crypto/bn/bn_sqrt.c",
- "crypto/bn/bn_recp.c",
- "crypto/bn/bn_lib.c",
- "crypto/ripemd/rmd_dgst.c",
- "crypto/ripemd/rmd_one.c",
- "crypto/rsa/rsa_x931.c",
- "crypto/rsa/rsa_depr.c",
- "crypto/rsa/rsa_saos.c",
- "crypto/rsa/rsa_crpt.c",
- "crypto/rsa/rsa_pss.c",
- "crypto/rsa/rsa_oaep.c",
- "crypto/rsa/rsa_null.c",
- "crypto/rsa/rsa_gen.c",
- "crypto/rsa/rsa_prn.c",
- "crypto/rsa/rsa_pmeth.c",
- "crypto/rsa/rsa_asn1.c",
- "crypto/rsa/rsa_ssl.c",
- "crypto/rsa/rsa_ameth.c",
- "crypto/rsa/rsa_pk1.c",
- "crypto/rsa/rsa_err.c",
- "crypto/rsa/rsa_lib.c",
- "crypto/rsa/rsa_none.c",
- "crypto/rsa/rsa_chk.c",
- "crypto/rsa/rsa_eay.c",
- "crypto/rsa/rsa_sign.c",
- "crypto/srp/srp_lib.c",
- "crypto/srp/srp_vfy.c",
- "crypto/err/err.c",
- "crypto/err/err_prn.c",
- "crypto/err/err_all.c",
- "crypto/mem_clr.c",
- "crypto/rc4/rc4_skey.c",
- "crypto/rc4/rc4_enc.c",
- "crypto/camellia/camellia.c",
- "crypto/camellia/cmll_cbc.c",
- #"crypto/aes/aes_x86core.c",
- "crypto/aes/aes_core.c",
- "crypto/aes/aes_cbc.c",
- "crypto/whrlpool/wp_block.c",
- "crypto/bn/bn_asm.c",
- ]
-
- if "platform" in env and env["platform"] == "uwp":
- thirdparty_sources += ['uwp.cpp']
-
- thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
-
- env_openssl.add_source_files(env.modules_sources, thirdparty_sources)
-
- # FIXME: Clone the environment to make env_openssl and not pollute the modules env
- thirdparty_include_paths = [
- "",
- "crypto",
- "crypto/asn1",
- "crypto/evp",
- "crypto/modes",
- "openssl",
- ]
- env_openssl.Append(CPPPATH=[thirdparty_dir + "/" + dir for dir in thirdparty_include_paths])
-
- env_openssl.Append(CPPFLAGS=["-DOPENSSL_NO_ASM", "-DOPENSSL_THREADS", "-DL_ENDIAN"])
-
- # Workaround for compilation error with GCC/Clang when -Werror is too greedy (GH-4517)
- import os
- import methods
- if not (os.name == "nt" and os.getenv("VCINSTALLDIR")): # not Windows and not MSVC
- env_openssl.Append(CFLAGS=["-Wno-error=implicit-function-declaration"])
-
-
-# Module sources
-env_openssl.add_source_files(env.modules_sources, "*.cpp")
-
-
-# Other thirdparty dependencies
-thirdparty_misc_dir = "#thirdparty/misc/"
-thirdparty_misc_sources = [
- "curl_hostcheck.c",
-]
-thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_misc_sources]
-env_openssl.add_source_files(env.modules_sources, thirdparty_misc_sources)
-
-
-# platform/uwp need to know openssl is available, pass to main env
-if "platform" in env and env["platform"] == "uwp":
- env.Append(CPPPATH=[thirdparty_dir])
- env.Append(CPPFLAGS=['-DOPENSSL_ENABLED'])
-
-Export('env')
diff --git a/modules/openssl/stream_peer_openssl.cpp b/modules/openssl/stream_peer_openssl.cpp
deleted file mode 100644
index e3cb9bbdf8..0000000000
--- a/modules/openssl/stream_peer_openssl.cpp
+++ /dev/null
@@ -1,632 +0,0 @@
-/*************************************************************************/
-/* stream_peer_openssl.cpp */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-
-#include "stream_peer_openssl.h"
-
-// Compatibility with OpenSSL 1.1.0.
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-#define BIO_set_num(b, n)
-#else
-#define BIO_set_num(b, n) ((b)->num = (n))
-
-#define BIO_set_init(b, i) ((b)->init = (i))
-#define BIO_set_data(b, p) ((b)->ptr = (p))
-#define BIO_get_data(b) ((b)->ptr)
-#endif
-
-//hostname matching code from curl
-
-bool StreamPeerOpenSSL::_match_host_name(const char *name, const char *hostname) {
-
- return Tool_Curl_cert_hostcheck(name, hostname) == CURL_HOST_MATCH;
-}
-
-Error StreamPeerOpenSSL::_match_common_name(const char *hostname, const X509 *server_cert) {
-
- // Find the position of the CN field in the Subject field of the certificate
- int common_name_loc = X509_NAME_get_index_by_NID(X509_get_subject_name((X509 *)server_cert), NID_commonName, -1);
-
- ERR_FAIL_COND_V(common_name_loc < 0, ERR_INVALID_PARAMETER);
-
- // Extract the CN field
- X509_NAME_ENTRY *common_name_entry = X509_NAME_get_entry(X509_get_subject_name((X509 *)server_cert), common_name_loc);
-
- ERR_FAIL_COND_V(common_name_entry == NULL, ERR_INVALID_PARAMETER);
-
- // Convert the CN field to a C string
- ASN1_STRING *common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
-
- ERR_FAIL_COND_V(common_name_asn1 == NULL, ERR_INVALID_PARAMETER);
-
- char *common_name_str = (char *)ASN1_STRING_data(common_name_asn1);
-
- // Make sure there isn't an embedded NUL character in the CN
- bool malformed_certificate = (size_t)ASN1_STRING_length(common_name_asn1) != strlen(common_name_str);
-
- ERR_FAIL_COND_V(malformed_certificate, ERR_INVALID_PARAMETER);
-
- // Compare expected hostname with the CN
-
- return _match_host_name(common_name_str, hostname) ? OK : FAILED;
-}
-
-/**
-* Tries to find a match for hostname in the certificate's Subject Alternative Name extension.
-*
-*/
-
-Error StreamPeerOpenSSL::_match_subject_alternative_name(const char *hostname, const X509 *server_cert) {
-
- Error result = FAILED;
- int i;
- int san_names_nb = -1;
- STACK_OF(GENERAL_NAME) *san_names = NULL;
-
- // Try to extract the names within the SAN extension from the certificate
- san_names = (STACK_OF(GENERAL_NAME) *)X509_get_ext_d2i((X509 *)server_cert, NID_subject_alt_name, NULL, NULL);
- if (san_names == NULL) {
- return ERR_FILE_NOT_FOUND;
- }
- san_names_nb = sk_GENERAL_NAME_num(san_names);
-
- // Check each name within the extension
- for (i = 0; i < san_names_nb; i++) {
- const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i);
-
- if (current_name->type == GEN_DNS) {
- // Current name is a DNS name, let's check it
- char *dns_name = (char *)ASN1_STRING_data(current_name->d.dNSName);
-
- // Make sure there isn't an embedded NUL character in the DNS name
- if ((size_t)ASN1_STRING_length(current_name->d.dNSName) != strlen(dns_name)) {
- result = ERR_INVALID_PARAMETER;
- break;
- } else { // Compare expected hostname with the DNS name
- if (_match_host_name(dns_name, hostname)) {
- result = OK;
- break;
- }
- }
- }
- }
- sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
-
- return result;
-}
-
-/* See http://archives.seul.org/libevent/users/Jan-2013/msg00039.html */
-int StreamPeerOpenSSL::_cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg) {
-
- /* This is the function that OpenSSL would call if we hadn't called
- * SSL_CTX_set_cert_verify_callback(). Therefore, we are "wrapping"
- * the default functionality, rather than replacing it. */
-
- bool base_cert_valid = X509_verify_cert(x509_ctx);
- if (!base_cert_valid) {
- print_line("Cause: " + String(X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx))));
- ERR_print_errors_fp(stdout);
- }
- X509 *server_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
-
- ERR_FAIL_COND_V(!server_cert, 0);
-
- char cert_str[256];
- X509_NAME_oneline(X509_get_subject_name(server_cert),
- cert_str, sizeof(cert_str));
-
- print_line("CERT STR: " + String(cert_str));
- print_line("VALID: " + itos(base_cert_valid));
-
- if (!base_cert_valid)
- return 0;
-
- StreamPeerOpenSSL *ssl = (StreamPeerOpenSSL *)arg;
-
- if (ssl->validate_hostname) {
-
- Error err = _match_subject_alternative_name(ssl->hostname.utf8().get_data(), server_cert);
-
- if (err == ERR_FILE_NOT_FOUND) {
-
- err = _match_common_name(ssl->hostname.utf8().get_data(), server_cert);
- }
-
- if (err != OK) {
-
- ssl->status = STATUS_ERROR_HOSTNAME_MISMATCH;
- return 0;
- }
- }
-
- return 1;
-}
-
-int StreamPeerOpenSSL::_bio_create(BIO *b) {
- BIO_set_init(b, 1);
- BIO_set_num(b, 0);
- BIO_set_data(b, NULL);
- BIO_clear_flags(b, ~0);
- return 1;
-}
-
-int StreamPeerOpenSSL::_bio_destroy(BIO *b) {
- if (b == NULL)
- return 0;
-
- BIO_set_data(b, NULL); /* sb_tls_remove() will free it */
- BIO_set_init(b, 0);
- BIO_clear_flags(b, ~0);
- return 1;
-}
-
-int StreamPeerOpenSSL::_bio_read(BIO *b, char *buf, int len) {
-
- if (buf == NULL || len <= 0) return 0;
-
- StreamPeerOpenSSL *sp = (StreamPeerOpenSSL *)BIO_get_data(b);
-
- ERR_FAIL_COND_V(sp == NULL, 0);
-
- BIO_clear_retry_flags(b);
- if (sp->use_blocking) {
-
- Error err = sp->base->get_data((uint8_t *)buf, len);
- if (err != OK) {
- return -1;
- }
-
- return len;
- } else {
-
- int got;
- Error err = sp->base->get_partial_data((uint8_t *)buf, len, got);
- if (err != OK) {
- return -1;
- }
- if (got == 0) {
- BIO_set_retry_read(b);
- }
- return got;
- }
-
- //unreachable
- return 0;
-}
-
-int StreamPeerOpenSSL::_bio_write(BIO *b, const char *buf, int len) {
-
- if (buf == NULL || len <= 0) return 0;
-
- StreamPeerOpenSSL *sp = (StreamPeerOpenSSL *)BIO_get_data(b);
-
- ERR_FAIL_COND_V(sp == NULL, 0);
-
- BIO_clear_retry_flags(b);
- if (sp->use_blocking) {
-
- Error err = sp->base->put_data((const uint8_t *)buf, len);
- if (err != OK) {
- return -1;
- }
-
- return len;
- } else {
-
- int sent;
- Error err = sp->base->put_partial_data((const uint8_t *)buf, len, sent);
- if (err != OK) {
- return -1;
- }
- if (sent == 0) {
- BIO_set_retry_write(b);
- }
- return sent;
- }
-
- //unreachable
- return 0;
-}
-
-long StreamPeerOpenSSL::_bio_ctrl(BIO *b, int cmd, long num, void *ptr) {
- if (cmd == BIO_CTRL_FLUSH) {
- /* The OpenSSL library needs this */
- return 1;
- }
- return 0;
-}
-
-int StreamPeerOpenSSL::_bio_gets(BIO *b, char *buf, int len) {
- return -1;
-}
-
-int StreamPeerOpenSSL::_bio_puts(BIO *b, const char *str) {
- return _bio_write(b, str, strlen(str));
-}
-
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-BIO_METHOD *StreamPeerOpenSSL::_bio_method = NULL;
-
-BIO_METHOD *StreamPeerOpenSSL::_get_bio_method() {
- if (_bio_method) // already initialized.
- return _bio_method;
-
- /* it's a source/sink BIO */
- _bio_method = BIO_meth_new(100 | 0x400, "streampeer glue");
- BIO_meth_set_write(_bio_method, _bio_write);
- BIO_meth_set_read(_bio_method, _bio_read);
- BIO_meth_set_puts(_bio_method, _bio_puts);
- BIO_meth_set_gets(_bio_method, _bio_gets);
- BIO_meth_set_ctrl(_bio_method, _bio_ctrl);
- BIO_meth_set_create(_bio_method, _bio_create);
- BIO_meth_set_destroy(_bio_method, _bio_destroy);
-
- return _bio_method;
-}
-#else
-BIO_METHOD StreamPeerOpenSSL::_bio_method = {
- /* it's a source/sink BIO */
- (100 | 0x400),
- "streampeer glue",
- _bio_write,
- _bio_read,
- _bio_puts,
- _bio_gets,
- _bio_ctrl,
- _bio_create,
- _bio_destroy
-};
-
-BIO_METHOD *StreamPeerOpenSSL::_get_bio_method() {
- return &_bio_method;
-}
-#endif
-
-Error StreamPeerOpenSSL::connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs, const String &p_for_hostname) {
-
- if (connected)
- disconnect_from_stream();
-
- hostname = p_for_hostname;
- status = STATUS_DISCONNECTED;
-
- // Set up a SSL_CTX object, which will tell our BIO object how to do its work
- ctx = SSL_CTX_new(SSLv23_client_method());
- base = p_base;
- validate_certs = p_validate_certs;
- validate_hostname = p_for_hostname != "";
-
- if (p_validate_certs) {
-
- if (certs.size()) {
- //yay for undocumented OpenSSL functions
-
- X509_STORE *store = SSL_CTX_get_cert_store(ctx);
- for (int i = 0; i < certs.size(); i++) {
-
- X509_STORE_add_cert(store, certs[i]);
- }
- }
-
- //used for testing
- //int res = SSL_CTX_load_verify_locations(ctx,"/etc/ssl/certs/ca-certificates.crt",NULL);
- //print_line("verify locations res: "+itos(res));
-
- /* Ask OpenSSL to verify the server certificate. Note that this
- * does NOT include verifying that the hostname is correct.
- * So, by itself, this means anyone with any legitimate
- * CA-issued certificate for any website, can impersonate any
- * other website in the world. This is not good. See "The
- * Most Dangerous Code in the World" article at
- * https://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html
- */
- SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
- /* This is how we solve the problem mentioned in the previous
- * comment. We "wrap" OpenSSL's validation routine in our
- * own routine, which also validates the hostname by calling
- * the code provided by iSECPartners. Note that even though
- * the "Everything You've Always Wanted to Know About
- * Certificate Validation With OpenSSL (But Were Afraid to
- * Ask)" paper from iSECPartners says very explicitly not to
- * call SSL_CTX_set_cert_verify_callback (at the bottom of
- * page 2), what we're doing here is safe because our
- * cert_verify_callback() calls X509_verify_cert(), which is
- * OpenSSL's built-in routine which would have been called if
- * we hadn't set the callback. Therefore, we're just
- * "wrapping" OpenSSL's routine, not replacing it. */
- SSL_CTX_set_cert_verify_callback(ctx, _cert_verify_callback, this);
-
- //Let the verify_callback catch the verify_depth error so that we get an appropriate error in the logfile. (??)
- SSL_CTX_set_verify_depth(ctx, max_cert_chain_depth + 1);
- }
-
- ssl = SSL_new(ctx);
- bio = BIO_new(_get_bio_method());
- BIO_set_data(bio, this);
- SSL_set_bio(ssl, bio, bio);
-
- if (p_for_hostname != String()) {
- SSL_set_tlsext_host_name(ssl, p_for_hostname.utf8().get_data());
- }
-
- use_blocking = true; // let handshake use blocking
- // Set the SSL to automatically retry on failure.
- SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
-
- // Same as before, try to connect.
- int result = SSL_connect(ssl);
-
- print_line("CONNECTION RESULT: " + itos(result));
- if (result < 1) {
- ERR_print_errors_fp(stdout);
- _print_error(result);
- }
-
- X509 *peer = SSL_get_peer_certificate(ssl);
-
- if (peer) {
- bool cert_ok = SSL_get_verify_result(ssl) == X509_V_OK;
- print_line("cert_ok: " + itos(cert_ok));
-
- } else if (validate_certs) {
- status = STATUS_ERROR_NO_CERTIFICATE;
- }
-
- connected = true;
- status = STATUS_CONNECTED;
-
- return OK;
-}
-
-Error StreamPeerOpenSSL::accept_stream(Ref<StreamPeer> p_base) {
-
- return ERR_UNAVAILABLE;
-}
-
-void StreamPeerOpenSSL::_print_error(int err) {
-
- err = SSL_get_error(ssl, err);
- switch (err) {
- case SSL_ERROR_NONE:
- ERR_PRINT("NO ERROR: The TLS/SSL I/O operation completed");
- break;
- case SSL_ERROR_ZERO_RETURN:
- ERR_PRINT("The TLS/SSL connection has been closed.");
- break;
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- ERR_PRINT("The operation did not complete.");
- break;
- case SSL_ERROR_WANT_CONNECT:
- case SSL_ERROR_WANT_ACCEPT:
- ERR_PRINT("The connect/accept operation did not complete");
- break;
- case SSL_ERROR_WANT_X509_LOOKUP:
- ERR_PRINT("The operation did not complete because an application callback set by SSL_CTX_set_client_cert_cb() has asked to be called again.");
- break;
- case SSL_ERROR_SYSCALL:
- ERR_PRINT("Some I/O error occurred. The OpenSSL error queue may contain more information on the error.");
- break;
- case SSL_ERROR_SSL:
- ERR_PRINT("A failure in the SSL library occurred, usually a protocol error.");
- break;
- }
-}
-
-Error StreamPeerOpenSSL::put_data(const uint8_t *p_data, int p_bytes) {
-
- ERR_FAIL_COND_V(!connected, ERR_UNCONFIGURED);
-
- while (p_bytes > 0) {
- int ret = SSL_write(ssl, p_data, p_bytes);
- if (ret <= 0) {
- _print_error(ret);
- disconnect_from_stream();
- return ERR_CONNECTION_ERROR;
- }
- p_data += ret;
- p_bytes -= ret;
- }
-
- return OK;
-}
-
-Error StreamPeerOpenSSL::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) {
-
- ERR_FAIL_COND_V(!connected, ERR_UNCONFIGURED);
- if (p_bytes == 0)
- return OK;
-
- Error err = put_data(p_data, p_bytes);
- if (err != OK)
- return err;
-
- r_sent = p_bytes;
- return OK;
-}
-
-Error StreamPeerOpenSSL::get_data(uint8_t *p_buffer, int p_bytes) {
-
- ERR_FAIL_COND_V(!connected, ERR_UNCONFIGURED);
-
- while (p_bytes > 0) {
-
- int ret = SSL_read(ssl, p_buffer, p_bytes);
- if (ret <= 0) {
- _print_error(ret);
- disconnect_from_stream();
- return ERR_CONNECTION_ERROR;
- }
- p_buffer += ret;
- p_bytes -= ret;
- }
-
- return OK;
-}
-
-Error StreamPeerOpenSSL::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) {
-
- ERR_FAIL_COND_V(!connected, ERR_UNCONFIGURED);
- if (p_bytes == 0) {
- r_received = 0;
- return OK;
- }
-
- Error err = get_data(p_buffer, p_bytes);
- if (err != OK)
- return err;
- r_received = p_bytes;
- return OK;
-}
-
-int StreamPeerOpenSSL::get_available_bytes() const {
-
- ERR_FAIL_COND_V(!connected, 0);
-
- return SSL_pending(ssl);
-}
-StreamPeerOpenSSL::StreamPeerOpenSSL() {
-
- ctx = NULL;
- ssl = NULL;
- bio = NULL;
- connected = false;
- use_blocking = true; //might be improved int the future, but for now it always blocks
- max_cert_chain_depth = 9;
- flags = 0;
-}
-
-void StreamPeerOpenSSL::disconnect_from_stream() {
-
- if (!connected)
- return;
- SSL_shutdown(ssl);
- SSL_free(ssl);
- SSL_CTX_free(ctx);
- base = Ref<StreamPeer>();
- connected = false;
- validate_certs = false;
- validate_hostname = false;
- status = STATUS_DISCONNECTED;
-}
-
-StreamPeerOpenSSL::Status StreamPeerOpenSSL::get_status() const {
-
- return status;
-}
-
-StreamPeerOpenSSL::~StreamPeerOpenSSL() {
- disconnect_from_stream();
-}
-
-StreamPeerSSL *StreamPeerOpenSSL::_create_func() {
-
- return memnew(StreamPeerOpenSSL);
-}
-
-Vector<X509 *> StreamPeerOpenSSL::certs;
-
-void StreamPeerOpenSSL::_load_certs(const PoolByteArray &p_array) {
-
- PoolByteArray::Read r = p_array.read();
- BIO *mem = BIO_new(BIO_s_mem());
- BIO_puts(mem, (const char *)r.ptr());
- while (true) {
- X509 *cert = PEM_read_bio_X509(mem, NULL, 0, NULL);
- if (!cert)
- break;
- certs.push_back(cert);
- }
- BIO_free(mem);
-}
-
-void StreamPeerOpenSSL::initialize_ssl() {
-
- available = true;
-
- load_certs_func = _load_certs;
-
- _create = _create_func;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
- CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use
-#endif
- SSL_library_init(); // Initialize OpenSSL's SSL libraries
- SSL_load_error_strings(); // Load SSL error strings
- ERR_load_BIO_strings(); // Load BIO error strings
- OpenSSL_add_all_algorithms(); // Load all available encryption algorithms
- String certs_path = GLOBAL_DEF("network/ssl/certificates", "");
- ProjectSettings::get_singleton()->set_custom_property_info("network/ssl/certificates", PropertyInfo(Variant::STRING, "network/ssl/certificates", PROPERTY_HINT_FILE, "*.crt"));
- if (certs_path != "") {
-
- FileAccess *f = FileAccess::open(certs_path, FileAccess::READ);
- if (f) {
- PoolByteArray arr;
- int flen = f->get_len();
- arr.resize(flen + 1);
- {
- PoolByteArray::Write w = arr.write();
- f->get_buffer(w.ptr(), flen);
- w[flen] = 0; //end f string
- }
-
- memdelete(f);
-
- _load_certs(arr);
- print_line("Loaded certs from '" + certs_path + "': " + itos(certs.size()));
- }
- }
- String config_path = GLOBAL_DEF("network/ssl/config", "");
- ProjectSettings::get_singleton()->set_custom_property_info("network/ssl/config", PropertyInfo(Variant::STRING, "network/ssl/config", PROPERTY_HINT_FILE, "*.cnf"));
- if (config_path != "") {
-
- Vector<uint8_t> data = FileAccess::get_file_as_array(config_path);
- if (data.size()) {
- data.push_back(0);
- BIO *mem = BIO_new(BIO_s_mem());
- BIO_puts(mem, (const char *)data.ptr());
-
- while (true) {
- X509 *cert = PEM_read_bio_X509(mem, NULL, 0, NULL);
- if (!cert)
- break;
- certs.push_back(cert);
- }
- BIO_free(mem);
- }
- print_line("Loaded certs from '" + certs_path + "': " + itos(certs.size()));
- }
-}
-
-void StreamPeerOpenSSL::finalize_ssl() {
-
- for (int i = 0; i < certs.size(); i++) {
- X509_free(certs[i]);
- }
- certs.clear();
-}
diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml
index 8cd163b0c8..26f0501df3 100644
--- a/modules/regex/doc_classes/RegEx.xml
+++ b/modules/regex/doc_classes/RegEx.xml
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RegEx" inherits="Reference" category="Core" version="3.0-beta">
+<class name="RegEx" inherits="Reference" category="Core" version="3.1-dev">
<brief_description>
Class for searching text for patterns using regular expressions.
</brief_description>
<description>
- Regular Expression (or regex) is a compact programming language that can be used to recognise strings that follow a specific pattern, such as URLs, email addresses, complete sentences, etc. For instance, a regex of [code]ab[0-9][/code] would find any string that is [code]ab[/code] followed by any number from [code]0[/code] to [code]9[/code]. For a more in-depth look, you can easily find various tutorials and detailed explainations on the Internet.
+ Regular Expression (or regex) is a compact programming language that can be used to recognise strings that follow a specific pattern, such as URLs, email addresses, complete sentences, etc. For instance, a regex of [code]ab[0-9][/code] would find any string that is [code]ab[/code] followed by any number from [code]0[/code] to [code]9[/code]. For a more in-depth look, you can easily find various tutorials and detailed explanations on the Internet.
To begin, the RegEx object needs to be compiled with the search pattern using [method compile] before it can be used.
[codeblock]
var regex = RegEx.new()
regex.compile("\\w-(\\d+)")
[/codeblock]
The search pattern must be escaped first for gdscript before it is escaped for the expression. For example, [code]compile("\\d+")[/code] would be read by RegEx as [code]\d+[/code]. Similarly, [code]compile("\"(?:\\\\.|[^\"])*\"")[/code] would be read as [code]"(?:\\.|[^"])*"[/code]
- Using [method search] you can find the pattern within the given text. If a pattern is found, [RegExMatch] is returned and you can retrieve details of the results using fuctions such as [method RegExMatch.get_string] and [method RegExMatch.get_start].
+ Using [method search] you can find the pattern within the given text. If a pattern is found, [RegExMatch] is returned and you can retrieve details of the results using functions such as [method RegExMatch.get_string] and [method RegExMatch.get_start].
[codeblock]
var regex = RegEx.new()
regex.compile("\\w-(\\d+)")
diff --git a/modules/regex/doc_classes/RegExMatch.xml b/modules/regex/doc_classes/RegExMatch.xml
index b84a98ff6d..550411d3e0 100644
--- a/modules/regex/doc_classes/RegExMatch.xml
+++ b/modules/regex/doc_classes/RegExMatch.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RegExMatch" inherits="Reference" category="Core" version="3.0-beta">
+<class name="RegExMatch" inherits="Reference" category="Core" version="3.1-dev">
<brief_description>
Contains the results of a regex search.
</brief_description>
diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
index 6a6ee390cc..18ab616826 100644
--- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
+++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
@@ -115,7 +115,7 @@ void AudioStreamPlaybackOGGVorbis::seek(float p_time) {
if (!active)
return;
- if (p_time >= get_length()) {
+ if (p_time >= vorbis_stream->get_length()) {
p_time = 0;
}
frames_mixed = uint32_t(vorbis_stream->sample_rate * p_time);
@@ -123,11 +123,6 @@ void AudioStreamPlaybackOGGVorbis::seek(float p_time) {
stb_vorbis_seek(ogg_stream, frames_mixed);
}
-float AudioStreamPlaybackOGGVorbis::get_length() const {
-
- return vorbis_stream->length;
-}
-
AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() {
if (ogg_alloc.alloc_buffer) {
stb_vorbis_close(ogg_stream);
@@ -261,6 +256,11 @@ float AudioStreamOGGVorbis::get_loop_offset() const {
return loop_offset;
}
+float AudioStreamOGGVorbis::get_length() const {
+
+ return length;
+}
+
void AudioStreamOGGVorbis::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_data", "data"), &AudioStreamOGGVorbis::set_data);
diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.h b/modules/stb_vorbis/audio_stream_ogg_vorbis.h
index bb01c26902..d7bc7cc0d7 100644
--- a/modules/stb_vorbis/audio_stream_ogg_vorbis.h
+++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.h
@@ -71,8 +71,6 @@ public:
virtual float get_playback_position() const;
virtual void seek(float p_time);
- virtual float get_length() const; //if supported, otherwise return 0
-
AudioStreamPlaybackOGGVorbis() {}
~AudioStreamPlaybackOGGVorbis();
};
@@ -112,6 +110,8 @@ public:
void set_data(const PoolVector<uint8_t> &p_data);
PoolVector<uint8_t> get_data() const;
+ virtual float get_length() const; //if supported, otherwise return 0
+
AudioStreamOGGVorbis();
virtual ~AudioStreamOGGVorbis();
};
diff --git a/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml b/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml
index 57fcc75887..8d311ae1b8 100644
--- a/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml
+++ b/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamOGGVorbis" inherits="AudioStream" category="Core" version="3.0-beta">
+<class name="AudioStreamOGGVorbis" inherits="AudioStream" category="Core" version="3.1-dev">
<brief_description>
OGG Vorbis audio stream driver.
</brief_description>
diff --git a/modules/stb_vorbis/doc_classes/ResourceImporterOGGVorbis.xml b/modules/stb_vorbis/doc_classes/ResourceImporterOGGVorbis.xml
index 9d541cda58..5872dd35ff 100644
--- a/modules/stb_vorbis/doc_classes/ResourceImporterOGGVorbis.xml
+++ b/modules/stb_vorbis/doc_classes/ResourceImporterOGGVorbis.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ResourceImporterOGGVorbis" inherits="ResourceImporter" category="Core" version="3.0-beta">
+<class name="ResourceImporterOGGVorbis" inherits="ResourceImporter" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/theora/doc_classes/ResourceImporterTheora.xml b/modules/theora/doc_classes/ResourceImporterTheora.xml
index 85c7c6bf89..6d2de4a9ad 100644
--- a/modules/theora/doc_classes/ResourceImporterTheora.xml
+++ b/modules/theora/doc_classes/ResourceImporterTheora.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ResourceImporterTheora" inherits="ResourceImporter" category="Core" version="3.0-beta">
+<class name="ResourceImporterTheora" inherits="ResourceImporter" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/theora/doc_classes/VideoStreamTheora.xml b/modules/theora/doc_classes/VideoStreamTheora.xml
index 6c8806ed72..550844128d 100644
--- a/modules/theora/doc_classes/VideoStreamTheora.xml
+++ b/modules/theora/doc_classes/VideoStreamTheora.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VideoStreamTheora" inherits="VideoStream" category="Core" version="3.0-beta">
+<class name="VideoStreamTheora" inherits="VideoStream" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml
index 46bd35dd73..975b294f30 100644
--- a/modules/visual_script/doc_classes/VisualScript.xml
+++ b/modules/visual_script/doc_classes/VisualScript.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScript" inherits="Script" category="Core" version="3.0-beta">
+<class name="VisualScript" inherits="Script" category="Core" version="3.1-dev">
<brief_description>
A script implemented in the Visual Script programming environment.
</brief_description>
@@ -9,6 +9,7 @@
You are most likely to use this class via the Visual Script editor or when writing plugins for it.
</description>
<tutorials>
+ http://docs.godotengine.org/en/3.0/getting_started/scripting/visual_script/index.html
</tutorials>
<demos>
</demos>
diff --git a/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml b/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
index e602214a66..b529589b98 100644
--- a/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptBasicTypeConstant" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptBasicTypeConstant" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
A Visual Script node representing a constant from the base types.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
index 9f7d38e957..9c2ec3b849 100644
--- a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
+++ b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptBuiltinFunc" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptBuiltinFunc" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
A Visual Script node used to call built-in functions.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
index 78757843cd..dc946cfcbd 100644
--- a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptClassConstant" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptClassConstant" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Gets a constant from a given class.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptComment.xml b/modules/visual_script/doc_classes/VisualScriptComment.xml
index c21a082362..5c20f27ec2 100644
--- a/modules/visual_script/doc_classes/VisualScriptComment.xml
+++ b/modules/visual_script/doc_classes/VisualScriptComment.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptComment" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptComment" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
A Visual Script node used to annotate the script.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptCondition.xml b/modules/visual_script/doc_classes/VisualScriptCondition.xml
index f1f87c010d..a3313a43d9 100644
--- a/modules/visual_script/doc_classes/VisualScriptCondition.xml
+++ b/modules/visual_script/doc_classes/VisualScriptCondition.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptCondition" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptCondition" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
A Visual Script node which branches the flow.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptConstant.xml b/modules/visual_script/doc_classes/VisualScriptConstant.xml
index 39a1e5eba8..274adb5423 100644
--- a/modules/visual_script/doc_classes/VisualScriptConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptConstant" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptConstant" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Gets a contant's value.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptConstructor.xml b/modules/visual_script/doc_classes/VisualScriptConstructor.xml
index cbe8c6c096..2efe8d9bd6 100644
--- a/modules/visual_script/doc_classes/VisualScriptConstructor.xml
+++ b/modules/visual_script/doc_classes/VisualScriptConstructor.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptConstructor" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptConstructor" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
A Visual Script node which calls a base type constructor.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml b/modules/visual_script/doc_classes/VisualScriptCustomNode.xml
index c321c616af..2165c403d4 100644
--- a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml
+++ b/modules/visual_script/doc_classes/VisualScriptCustomNode.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptCustomNode" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptCustomNode" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
A scripted Visual Script node.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml b/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml
index 0f396564e2..f076c70715 100644
--- a/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml
+++ b/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptDeconstruct" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptDeconstruct" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
A Visual Script node which deconstructs a base type instance into its parts.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptEditor.xml b/modules/visual_script/doc_classes/VisualScriptEditor.xml
index b433f132c1..1c4542336f 100644
--- a/modules/visual_script/doc_classes/VisualScriptEditor.xml
+++ b/modules/visual_script/doc_classes/VisualScriptEditor.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptEditor" inherits="Object" category="Core" version="3.0-beta">
+<class name="VisualScriptEditor" inherits="Object" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
index 71e8c7d93c..7eea609db4 100644
--- a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
+++ b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptEmitSignal" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptEmitSignal" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Emits a specified signal.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml b/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml
index b9f356412d..26196f278e 100644
--- a/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml
+++ b/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptEngineSingleton" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptEngineSingleton" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
A Visual Script node returning a singleton from [@GlobalScope]
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptExpression.xml b/modules/visual_script/doc_classes/VisualScriptExpression.xml
index 91c107e069..0b93c3092c 100644
--- a/modules/visual_script/doc_classes/VisualScriptExpression.xml
+++ b/modules/visual_script/doc_classes/VisualScriptExpression.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptExpression" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptExpression" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptFunction.xml b/modules/visual_script/doc_classes/VisualScriptFunction.xml
index 2c63b98b22..18daa42797 100644
--- a/modules/visual_script/doc_classes/VisualScriptFunction.xml
+++ b/modules/visual_script/doc_classes/VisualScriptFunction.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptFunction" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptFunction" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
index 03c47dca7c..dc025cfb27 100644
--- a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
+++ b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptFunctionCall" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptFunctionCall" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml
index 90ec85e4f4..05e9a6cb81 100644
--- a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml
+++ b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptFunctionState" inherits="Reference" category="Core" version="3.0-beta">
+<class name="VisualScriptFunctionState" inherits="Reference" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml b/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml
index 4417c8a533..d0db8cbab3 100644
--- a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptGlobalConstant" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptGlobalConstant" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptIndexGet.xml b/modules/visual_script/doc_classes/VisualScriptIndexGet.xml
index c0a83f186a..983d8882a7 100644
--- a/modules/visual_script/doc_classes/VisualScriptIndexGet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptIndexGet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptIndexGet" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptIndexGet" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptIndexSet.xml b/modules/visual_script/doc_classes/VisualScriptIndexSet.xml
index 8661341919..bc876900f3 100644
--- a/modules/visual_script/doc_classes/VisualScriptIndexSet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptIndexSet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptIndexSet" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptIndexSet" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptInputAction.xml b/modules/visual_script/doc_classes/VisualScriptInputAction.xml
index afe72ba564..4316bf146d 100644
--- a/modules/visual_script/doc_classes/VisualScriptInputAction.xml
+++ b/modules/visual_script/doc_classes/VisualScriptInputAction.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptInputAction" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptInputAction" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptIterator.xml b/modules/visual_script/doc_classes/VisualScriptIterator.xml
index 08dfad5acb..d815476e2c 100644
--- a/modules/visual_script/doc_classes/VisualScriptIterator.xml
+++ b/modules/visual_script/doc_classes/VisualScriptIterator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptIterator" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptIterator" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Steps through items in a given input.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
index a4293adaae..038fd8c9cd 100644
--- a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
+++ b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptLocalVar" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptLocalVar" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Gets a local variable's value.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
index c1a279bdb2..fa65a89c4a 100644
--- a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptLocalVarSet" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptLocalVarSet" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Changes a local variable's value.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptMathConstant.xml b/modules/visual_script/doc_classes/VisualScriptMathConstant.xml
index 2cb053ee5f..243ab03b49 100644
--- a/modules/visual_script/doc_classes/VisualScriptMathConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptMathConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptMathConstant" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptMathConstant" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Commonly used mathematical constants.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptNode.xml b/modules/visual_script/doc_classes/VisualScriptNode.xml
index ef7cf7c3b8..c2c5464047 100644
--- a/modules/visual_script/doc_classes/VisualScriptNode.xml
+++ b/modules/visual_script/doc_classes/VisualScriptNode.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptNode" inherits="Resource" category="Core" version="3.0-beta">
+<class name="VisualScriptNode" inherits="Resource" category="Core" version="3.1-dev">
<brief_description>
A node which is part of a [VisualScript].
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptOperator.xml b/modules/visual_script/doc_classes/VisualScriptOperator.xml
index b7819592d9..68a57191de 100644
--- a/modules/visual_script/doc_classes/VisualScriptOperator.xml
+++ b/modules/visual_script/doc_classes/VisualScriptOperator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptOperator" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptOperator" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptPreload.xml b/modules/visual_script/doc_classes/VisualScriptPreload.xml
index 712ec99fdb..19abc27053 100644
--- a/modules/visual_script/doc_classes/VisualScriptPreload.xml
+++ b/modules/visual_script/doc_classes/VisualScriptPreload.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptPreload" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptPreload" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Creates a new [Resource] or loads one from the filesystem.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
index 11c50f2b97..88aac85f59 100644
--- a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptPropertyGet" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptPropertyGet" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
index 2e96ccc1f6..ac962a071d 100644
--- a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptPropertySet" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptPropertySet" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptResourcePath.xml b/modules/visual_script/doc_classes/VisualScriptResourcePath.xml
index 36bcf2a460..a3144582cb 100644
--- a/modules/visual_script/doc_classes/VisualScriptResourcePath.xml
+++ b/modules/visual_script/doc_classes/VisualScriptResourcePath.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptResourcePath" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptResourcePath" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptReturn.xml b/modules/visual_script/doc_classes/VisualScriptReturn.xml
index a05c1076a4..ca50f811c3 100644
--- a/modules/visual_script/doc_classes/VisualScriptReturn.xml
+++ b/modules/visual_script/doc_classes/VisualScriptReturn.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptReturn" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptReturn" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Exits a function and returns an optional value.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptSceneNode.xml b/modules/visual_script/doc_classes/VisualScriptSceneNode.xml
index 1a73faaf67..3d4bdcfd0a 100644
--- a/modules/visual_script/doc_classes/VisualScriptSceneNode.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSceneNode.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSceneNode" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptSceneNode" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Node reference.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptSceneTree.xml b/modules/visual_script/doc_classes/VisualScriptSceneTree.xml
index 25ae9c26ac..c77b674b64 100644
--- a/modules/visual_script/doc_classes/VisualScriptSceneTree.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSceneTree.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSceneTree" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptSceneTree" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptSelect.xml b/modules/visual_script/doc_classes/VisualScriptSelect.xml
index 45ac505110..f1aad841ca 100644
--- a/modules/visual_script/doc_classes/VisualScriptSelect.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSelect.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSelect" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptSelect" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Chooses between two input values.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptSelf.xml b/modules/visual_script/doc_classes/VisualScriptSelf.xml
index 2b0c46a4bb..c2847fcada 100644
--- a/modules/visual_script/doc_classes/VisualScriptSelf.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSelf.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSelf" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptSelf" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Outputs a reference to the current instance.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptSequence.xml b/modules/visual_script/doc_classes/VisualScriptSequence.xml
index 624663b0d3..0180f34c72 100644
--- a/modules/visual_script/doc_classes/VisualScriptSequence.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSequence.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSequence" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptSequence" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Executes a series of Sequence ports.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptSubCall.xml b/modules/visual_script/doc_classes/VisualScriptSubCall.xml
index b7dc5ad65f..d34d0b7127 100644
--- a/modules/visual_script/doc_classes/VisualScriptSubCall.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSubCall.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSubCall" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptSubCall" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptSwitch.xml b/modules/visual_script/doc_classes/VisualScriptSwitch.xml
index a34754b596..ea9e6438cf 100644
--- a/modules/visual_script/doc_classes/VisualScriptSwitch.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSwitch.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSwitch" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptSwitch" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Branches program flow based on a given input's value.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
index e61e81c397..4bdfeab35b 100644
--- a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
+++ b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptTypeCast" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptTypeCast" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
index 7122d2d3f6..76c218294e 100644
--- a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptVariableGet" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptVariableGet" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Gets a variable's value.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
index 3c39da0a8d..0262ad5dfb 100644
--- a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptVariableSet" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptVariableSet" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Changes a variable's value.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptWhile.xml b/modules/visual_script/doc_classes/VisualScriptWhile.xml
index d8e59a7576..46a6ea7a30 100644
--- a/modules/visual_script/doc_classes/VisualScriptWhile.xml
+++ b/modules/visual_script/doc_classes/VisualScriptWhile.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptWhile" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptWhile" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
Conditional loop.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptYield.xml b/modules/visual_script/doc_classes/VisualScriptYield.xml
index b42fc027cf..a1129ffbd7 100644
--- a/modules/visual_script/doc_classes/VisualScriptYield.xml
+++ b/modules/visual_script/doc_classes/VisualScriptYield.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptYield" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptYield" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
index f69043a685..ad3a016c0d 100644
--- a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
+++ b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptYieldSignal" inherits="VisualScriptNode" category="Core" version="3.0-beta">
+<class name="VisualScriptYieldSignal" inherits="VisualScriptNode" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index 5987fdf5da..ef680547ca 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -2182,7 +2182,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
Ref<VisualScriptNode> node = F->get().node;
VisualScriptNodeInstance *instance = instances[F->key()];
- // conect to default values
+ // connect to default values
for (int i = 0; i < instance->input_port_count; i++) {
if (instance->input_ports[i] == -1) {
@@ -2192,7 +2192,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
}
}
- // conect to trash
+ // connect to trash
for (int i = 0; i < instance->output_port_count; i++) {
if (instance->output_ports[i] == -1) {
instance->output_ports[i] = function.trash_pos; //trash is same for all
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index 1ee0989564..7f0a42da82 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -257,10 +257,10 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
case MATH_ASIN:
case MATH_ACOS:
case MATH_ATAN:
- case MATH_ATAN2:
case MATH_SQRT: {
- return PropertyInfo(Variant::REAL, "num");
+ return PropertyInfo(Variant::REAL, "s");
} break;
+ case MATH_ATAN2:
case MATH_FMOD:
case MATH_FPOSMOD: {
if (p_idx == 0)
@@ -273,7 +273,7 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
case MATH_ROUND:
case MATH_ABS:
case MATH_SIGN: {
- return PropertyInfo(Variant::REAL, "num");
+ return PropertyInfo(Variant::REAL, "s");
} break;
@@ -287,7 +287,7 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
case MATH_EXP:
case MATH_ISNAN:
case MATH_ISINF: {
- return PropertyInfo(Variant::REAL, "num");
+ return PropertyInfo(Variant::REAL, "s");
} break;
case MATH_EASE: {
if (p_idx == 0)
@@ -318,7 +318,7 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
else if (p_idx == 1)
return PropertyInfo(Variant::REAL, "to");
else
- return PropertyInfo(Variant::REAL, "value");
+ return PropertyInfo(Variant::REAL, "weight");
} break;
case MATH_RANGE_LERP: {
if (p_idx == 0)
@@ -415,14 +415,14 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
} break;
case LOGIC_CLAMP: {
if (p_idx == 0)
- return PropertyInfo(Variant::REAL, "a");
- else if (p_idx == 0) // FIXME: is it ok to test p_idx == 0 twice?
+ return PropertyInfo(Variant::REAL, "value");
+ else if (p_idx == 1)
return PropertyInfo(Variant::REAL, "min");
else
return PropertyInfo(Variant::REAL, "max");
} break;
case LOGIC_NEAREST_PO2: {
- return PropertyInfo(Variant::INT, "num");
+ return PropertyInfo(Variant::INT, "value");
} break;
case OBJ_WEAKREF: {
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 37b0b8ac55..69503e631c 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -318,7 +318,8 @@ protected:
}
p_list->push_back(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt));
p_list->push_back(PropertyInfo(script->get_variable_info(var).type, "value", script->get_variable_info(var).hint, script->get_variable_info(var).hint_string, PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,ExpRange,Enum,ExpEasing,Length,SpriteFrame,KeyAccel,BitFlags,AllFlags,File,Dir,GlobalFile,GlobalDir,ResourceType,MultilineText"));
+ // Update this when PropertyHint changes
+ p_list->push_back(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,ExpRange,Enum,ExpEasing,Length,SpriteFrame,KeyAccel,Flags,Layers2dRender,Layers2dPhysics,Layer3dRender,Layer3dPhysics,File,Dir,GlobalFile,GlobalDir,ResourceType,MultilineText,ColorNoAlpha,ImageCompressLossy,ImageCompressLossLess,ObjectId,String,NodePathToEditedNode,MethodOfVariantType,MethodOfBaseType,MethodOfInstance,MethodOfScript,PropertyOfVariantType,PropertyOfBaseType,PropertyOfInstance,PropertyOfScript,ObjectTooBig"));
p_list->push_back(PropertyInfo(Variant::STRING, "hint_string"));
p_list->push_back(PropertyInfo(Variant::BOOL, "export"));
}
@@ -1307,6 +1308,35 @@ void VisualScriptEditor::_input(const Ref<InputEvent> &p_event) {
}
}
+void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) {
+
+ Ref<InputEventKey> key = p_event;
+ if (key.is_valid() && key->is_pressed() && !key->is_echo()) {
+ if (members->has_focus()) {
+ TreeItem *ti = members->get_selected();
+ if (ti) {
+ TreeItem *root = members->get_root();
+ if (ti->get_parent() == root->get_children()) {
+ member_type = MEMBER_FUNCTION;
+ }
+ if (ti->get_parent() == root->get_children()->get_next()) {
+ member_type = MEMBER_VARIABLE;
+ }
+ if (ti->get_parent() == root->get_children()->get_next()->get_next()) {
+ member_type = MEMBER_SIGNAL;
+ }
+ member_name = ti->get_text(0);
+ }
+ if (ED_IS_SHORTCUT("visual_script_editor/delete_selected", p_event)) {
+ _member_option(MEMBER_REMOVE);
+ }
+ if (ED_IS_SHORTCUT("visual_script_editor/edit_member", p_event)) {
+ _member_option(MEMBER_EDIT);
+ }
+ }
+ }
+}
+
Variant VisualScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
if (p_from == nodes) {
@@ -3089,7 +3119,7 @@ void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) {
member_type = MEMBER_FUNCTION;
member_name = ti->get_text(0);
- member_popup->add_icon_item(del_icon, TTR("Remove Function"), MEMBER_REMOVE);
+ member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("visual_script_editor/delete_selected"), MEMBER_REMOVE);
member_popup->popup();
return;
}
@@ -3098,9 +3128,9 @@ void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) {
member_type = MEMBER_VARIABLE;
member_name = ti->get_text(0);
- member_popup->add_icon_item(edit_icon, TTR("Edit Variable"), MEMBER_EDIT);
+ member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);
member_popup->add_separator();
- member_popup->add_icon_item(del_icon, TTR("Remove Variable"), MEMBER_REMOVE);
+ member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("visual_script_editor/delete_selected"), MEMBER_REMOVE);
member_popup->popup();
return;
}
@@ -3109,9 +3139,9 @@ void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) {
member_type = MEMBER_SIGNAL;
member_name = ti->get_text(0);
- member_popup->add_icon_item(edit_icon, TTR("Edit Signal"), MEMBER_EDIT);
+ member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);
member_popup->add_separator();
- member_popup->add_icon_item(del_icon, TTR("Remove Signal"), MEMBER_REMOVE);
+ member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("visual_script_editor/delete_selected"), MEMBER_REMOVE);
member_popup->popup();
return;
}
@@ -3242,6 +3272,7 @@ void VisualScriptEditor::_bind_methods() {
ClassDB::bind_method("drop_data_fw", &VisualScriptEditor::drop_data_fw);
ClassDB::bind_method("_input", &VisualScriptEditor::_input);
+ ClassDB::bind_method("_members_gui_input", &VisualScriptEditor::_members_gui_input);
ClassDB::bind_method("_on_nodes_delete", &VisualScriptEditor::_on_nodes_delete);
ClassDB::bind_method("_on_nodes_duplicate", &VisualScriptEditor::_on_nodes_duplicate);
@@ -3304,6 +3335,7 @@ VisualScriptEditor::VisualScriptEditor() {
members->connect("button_pressed", this, "_member_button");
members->connect("item_edited", this, "_member_edited");
members->connect("cell_selected", this, "_member_selected", varray(), CONNECT_DEFERRED);
+ members->connect("gui_input", this, "_members_gui_input");
members->set_allow_reselect(true);
members->set_hide_folding(true);
members->set_drag_forwarding(this);
@@ -3477,12 +3509,13 @@ static void register_editor_callback() {
ScriptEditor::register_create_script_editor_function(create_editor);
- ED_SHORTCUT("visual_script_editor/delete_selected", TTR("Delete Selected"));
+ ED_SHORTCUT("visual_script_editor/delete_selected", TTR("Delete Selected"), KEY_DELETE);
ED_SHORTCUT("visual_script_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), KEY_F9);
ED_SHORTCUT("visual_script_editor/find_node_type", TTR("Find Node Type"), KEY_MASK_CMD + KEY_F);
ED_SHORTCUT("visual_script_editor/copy_nodes", TTR("Copy Nodes"), KEY_MASK_CMD + KEY_C);
ED_SHORTCUT("visual_script_editor/cut_nodes", TTR("Cut Nodes"), KEY_MASK_CMD + KEY_X);
ED_SHORTCUT("visual_script_editor/paste_nodes", TTR("Paste Nodes"), KEY_MASK_CMD + KEY_V);
+ ED_SHORTCUT("visual_script_editor/edit_member", TTR("Edit Member"), KEY_MASK_CMD + KEY_E);
}
void VisualScriptEditor::register_editor() {
diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h
index 4d789e6ef7..80bbf142d9 100644
--- a/modules/visual_script/visual_script_editor.h
+++ b/modules/visual_script/visual_script_editor.h
@@ -211,6 +211,7 @@ class VisualScriptEditor : public ScriptEditorBase {
String revert_on_drag;
void _input(const Ref<InputEvent> &p_event);
+ void _members_gui_input(const Ref<InputEvent> &p_event);
void _on_nodes_delete();
void _on_nodes_duplicate();
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index e0b4fde237..c5654a5a20 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -425,7 +425,7 @@ PropertyInfo VisualScriptOperator::get_input_value_port_info(int p_idx) const {
}
PropertyInfo VisualScriptOperator::get_output_value_port_info(int p_idx) const {
static const Variant::Type port_types[Variant::OP_MAX] = {
- //comparation
+ //comparison
Variant::BOOL, //OP_EQUAL,
Variant::BOOL, //OP_NOT_EQUAL,
Variant::BOOL, //OP_LESS,
@@ -466,7 +466,7 @@ PropertyInfo VisualScriptOperator::get_output_value_port_info(int p_idx) const {
}
static const char *op_names[] = {
- //comparation
+ //comparison
"Equal", //OP_EQUAL,
"NotEqual", //OP_NOT_EQUAL,
"Less", //OP_LESS,
@@ -506,7 +506,7 @@ String VisualScriptOperator::get_caption() const {
String VisualScriptOperator::get_text() const {
static const wchar_t *op_names[] = {
- //comparation
+ //comparison
L"A = B", //OP_EQUAL,
L"A \u2260 B", //OP_NOT_EQUAL,
L"A < B", //OP_LESS,
diff --git a/modules/webm/doc_classes/ResourceImporterWebm.xml b/modules/webm/doc_classes/ResourceImporterWebm.xml
index 5dadb83b07..7c8e1a46b1 100644
--- a/modules/webm/doc_classes/ResourceImporterWebm.xml
+++ b/modules/webm/doc_classes/ResourceImporterWebm.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ResourceImporterWebm" inherits="ResourceImporter" category="Core" version="3.0-beta">
+<class name="ResourceImporterWebm" inherits="ResourceImporter" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/webm/doc_classes/VideoStreamWebm.xml b/modules/webm/doc_classes/VideoStreamWebm.xml
index 6e8120b1de..d52e2324a1 100644
--- a/modules/webm/doc_classes/VideoStreamWebm.xml
+++ b/modules/webm/doc_classes/VideoStreamWebm.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VideoStreamWebm" inherits="VideoStream" category="Core" version="3.0-beta">
+<class name="VideoStreamWebm" inherits="VideoStream" category="Core" version="3.1-dev">
<brief_description>
</brief_description>
<description>
diff --git a/modules/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub
index 73ba17d184..0ebafa022d 100644
--- a/modules/webm/libvpx/SCsub
+++ b/modules/webm/libvpx/SCsub
@@ -254,7 +254,6 @@ env_libvpx = env.Clone()
env_libvpx.Append(CPPPATH=[libvpx_dir])
cpu_bits = env["bits"]
-osx_fat = (env["platform"] == 'osx' and cpu_bits == 'fat')
webm_cpu_x86 = False
webm_cpu_arm = False
if env["platform"] == 'uwp':
@@ -269,11 +268,8 @@ else:
is_android_x86 = (env["platform"] == 'android' and env["android_arch"] == 'x86')
if is_android_x86:
cpu_bits = '32'
- if osx_fat:
- webm_cpu_x86 = True
- else:
- webm_cpu_x86 = not is_x11_or_server_arm and (cpu_bits == '32' or cpu_bits == '64') and (env["platform"] == 'windows' or env["platform"] == 'x11' or env["platform"] == 'osx' or env["platform"] == 'haiku' or is_android_x86 or is_ios_x86)
- webm_cpu_arm = is_x11_or_server_arm or (not is_ios_x86 and env["platform"] == 'iphone') or (not is_android_x86 and env["platform"] == 'android')
+ webm_cpu_x86 = not is_x11_or_server_arm and (cpu_bits == '32' or cpu_bits == '64') and (env["platform"] == 'windows' or env["platform"] == 'x11' or env["platform"] == 'osx' or env["platform"] == 'haiku' or is_android_x86 or is_ios_x86)
+ webm_cpu_arm = is_x11_or_server_arm or (not is_ios_x86 and env["platform"] == 'iphone') or (not is_android_x86 and env["platform"] == 'android')
if webm_cpu_x86:
import subprocess
@@ -303,28 +299,22 @@ if webm_cpu_x86:
webm_simd_optimizations = False
if webm_cpu_x86:
- if osx_fat:
- #'osx' platform only: run python script which will compile using 'yasm' command and then merge 32-bit and 64-bit using 'lipo' command
- env_libvpx["AS"] = 'python modules/webm/libvpx/yasm_osx_fat.py'
- env_libvpx["ASFLAGS"] = '-I' + libvpx_dir[1:]
- env_libvpx["ASCOM"] = '$AS $ASFLAGS $TARGET $SOURCES'
+ if env["platform"] == 'windows' or env["platform"] == 'uwp':
+ env_libvpx["ASFORMAT"] = 'win'
+ elif env["platform"] == 'osx' or env["platform"] == "iphone":
+ env_libvpx["ASFORMAT"] = 'macho'
else:
- if env["platform"] == 'windows' or env["platform"] == 'uwp':
- env_libvpx["ASFORMAT"] = 'win'
- elif env["platform"] == 'osx' or env["platform"] == "iphone":
- env_libvpx["ASFORMAT"] = 'macho'
- else:
- env_libvpx["ASFORMAT"] = 'elf'
- env_libvpx["ASFORMAT"] += cpu_bits
-
- env_libvpx["AS"] = 'yasm'
- env_libvpx["ASFLAGS"] = '-I' + libvpx_dir[1:] + ' -f $ASFORMAT -D $ASCPU'
- env_libvpx["ASCOM"] = '$AS $ASFLAGS -o $TARGET $SOURCES'
+ env_libvpx["ASFORMAT"] = 'elf'
+ env_libvpx["ASFORMAT"] += cpu_bits
- if cpu_bits == '32':
- env_libvpx["ASCPU"] = 'X86_32'
- elif cpu_bits == '64':
- env_libvpx["ASCPU"] = 'X86_64'
+ env_libvpx["AS"] = 'yasm'
+ env_libvpx["ASFLAGS"] = '-I' + libvpx_dir[1:] + ' -f $ASFORMAT -D $ASCPU'
+ env_libvpx["ASCOM"] = '$AS $ASFLAGS -o $TARGET $SOURCES'
+
+ if cpu_bits == '32':
+ env_libvpx["ASCPU"] = 'X86_32'
+ elif cpu_bits == '64':
+ env_libvpx["ASCPU"] = 'X86_64'
env_libvpx.Append(CCFLAGS=['-DWEBM_X86ASM'])
@@ -333,7 +323,7 @@ if webm_cpu_x86:
if webm_cpu_arm:
if env["platform"] == 'iphone':
env_libvpx["ASFLAGS"] = '-arch armv7'
- elif env["platform"] == 'android' or env["platform"] == 'x11' or env["platform"] == 'server':
+ elif env["platform"] == 'android' and env["android_arch"] == 'armv7' or env["platform"] == 'x11' or env["platform"] == 'server':
env_libvpx["ASFLAGS"] = '-mfpu=neon'
elif env["platform"] == 'uwp':
env_libvpx["AS"] = 'armasm'
@@ -375,7 +365,7 @@ if webm_cpu_x86:
env_libvpx.add_source_files(env.modules_sources, libvpx_sources_intrin_x86)
env_libvpx.add_source_files(env.modules_sources, libvpx_sources_x86asm)
- if cpu_bits == '64' or osx_fat:
+ if cpu_bits == '64':
env_libvpx.add_source_files(env.modules_sources, libvpx_sources_x86_64asm)
elif webm_cpu_arm:
env_libvpx.add_source_files(env.modules_sources, libvpx_sources_arm)
@@ -389,5 +379,5 @@ elif webm_cpu_arm:
env_libvpx.add_source_files(env.modules_sources, libvpx_sources_arm_neon_armasm_ms)
elif env["platform"] == 'iphone':
env_libvpx.add_source_files(env.modules_sources, libvpx_sources_arm_neon_gas_apple)
- else:
+ elif not env["android_arch"] == 'arm64v8':
env_libvpx.add_source_files(env.modules_sources, libvpx_sources_arm_neon_gas)
diff --git a/modules/webm/libvpx/yasm_osx_fat.py b/modules/webm/libvpx/yasm_osx_fat.py
deleted file mode 100644
index 0065e2766c..0000000000
--- a/modules/webm/libvpx/yasm_osx_fat.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-import os
-
-includes = sys.argv[1]
-output_file = sys.argv[2]
-input_file = sys.argv[3]
-
-can_remove = {}
-
-lipo_command = ''
-
-exit_code = 1
-
-for arch in ['32', '64']:
- if arch == '32' and input_file.endswith('x86_64.asm'):
- can_remove[arch] = False
- else:
- command = 'yasm ' + includes + ' -f macho' + arch + ' -D X86_' + arch + ' -o ' + output_file + '.' + arch + ' ' + input_file
- print(command)
- if os.system(command) == 0:
- lipo_command += output_file + '.' + arch + ' '
- can_remove[arch] = True
- else:
- can_remove[arch] = False
-
-if lipo_command != '':
- lipo_command = 'lipo -create ' + lipo_command + '-output ' + output_file
- print(lipo_command)
- if os.system(lipo_command) == 0:
- exit_code = 0
-
-for arch in ['32', '64']:
- if can_remove[arch]:
- os.remove(output_file + '.' + arch)
-
-sys.exit(exit_code)
diff --git a/modules/websocket/SCsub b/modules/websocket/SCsub
new file mode 100644
index 0000000000..1a36e05863
--- /dev/null
+++ b/modules/websocket/SCsub
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+
+Import('env')
+Import('env_modules')
+
+# Thirdparty source files
+
+env_lws = env_modules.Clone()
+
+thirdparty_dir = "#thirdparty/lws/"
+helper_dir = "win32helpers/"
+thirdparty_sources = [
+ "client/client.c",
+ "client/client-handshake.c",
+ "client/client-parser.c",
+ "client/ssl-client.c",
+
+ "ext/extension.c",
+ "ext/extension-permessage-deflate.c",
+
+ "server/fops-zip.c",
+ "server/lejp-conf.c",
+ "server/parsers.c",
+ "server/ranges.c",
+ "server/server.c",
+ "server/server-handshake.c",
+ "server/ssl-server.c",
+
+ "misc/base64-decode.c",
+ "misc/lejp.c",
+ "misc/sha-1.c",
+
+ "alloc.c",
+ "context.c",
+ "handshake.c",
+ "header.c",
+ "libwebsockets.c",
+ "minilex.c",
+ "output.c",
+ "pollfd.c",
+ "service.c",
+ "ssl.c",
+
+ "mbedtls_wrapper/library/ssl_cert.c",
+ "mbedtls_wrapper/library/ssl_pkey.c",
+ "mbedtls_wrapper/library/ssl_stack.c",
+ "mbedtls_wrapper/library/ssl_methods.c",
+ "mbedtls_wrapper/library/ssl_lib.c",
+ "mbedtls_wrapper/library/ssl_x509.c",
+ "mbedtls_wrapper/platform/ssl_port.c",
+ "mbedtls_wrapper/platform/ssl_pm.c",
+]
+
+if env_lws["platform"] == "android": # Builtin getifaddrs
+ thirdparty_sources += ["misc/getifaddrs.c"]
+
+if env_lws["platform"] == "windows" or env_lws["platform"] == "uwp": # Winsock
+ thirdparty_sources += ["plat/lws-plat-win.c", helper_dir + "getopt.c", helper_dir + "getopt_long.c", helper_dir + "gettimeofday.c"]
+else: # Unix socket
+ thirdparty_sources += ["plat/lws-plat-unix.c"]
+
+
+thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+if env_lws["platform"] == "javascript": # No need to add third party libraries at all
+ pass
+else:
+ env_lws.add_source_files(env.modules_sources, thirdparty_sources)
+ env_lws.Append(CPPPATH=[thirdparty_dir])
+
+ wrapper_includes = ["#thirdparty/lws/mbedtls_wrapper/include/" + inc for inc in ["internal", "openssl", "platform", ""]]
+ env_lws.Append(CPPPATH=wrapper_includes)
+
+ if env['builtin_mbedtls']:
+ mbedtls_includes = "#thirdparty/mbedtls/include"
+ env_lws.Append(CPPPATH=[mbedtls_includes])
+
+ if env_lws["platform"] == "windows" or env_lws["platform"] == "uwp":
+ env_lws.Append(CPPPATH=[thirdparty_dir + helper_dir])
+
+ if env_lws["platform"] == "uwp":
+ env_lws.Append(CCFLAGS=["/DLWS_MINGW_SUPPORT"])
+
+env_lws.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/websocket/config.py b/modules/websocket/config.py
new file mode 100644
index 0000000000..fb920482f5
--- /dev/null
+++ b/modules/websocket/config.py
@@ -0,0 +1,7 @@
+
+def can_build(platform):
+ return True
+
+
+def configure(env):
+ pass
diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp
new file mode 100644
index 0000000000..38fe520fc1
--- /dev/null
+++ b/modules/websocket/emws_client.cpp
@@ -0,0 +1,224 @@
+/*************************************************************************/
+/* emws_client.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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. */
+/*************************************************************************/
+#ifdef JAVASCRIPT_ENABLED
+
+#include "emws_client.h"
+#include "core/io/ip.h"
+#include "emscripten.h"
+
+extern "C" {
+EMSCRIPTEN_KEEPALIVE void _esws_on_connect(void *obj, char *proto) {
+ EMWSClient *client = static_cast<EMWSClient *>(obj);
+ client->_is_connecting = false;
+ client->_on_connect(String(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();
+}
+
+EMSCRIPTEN_KEEPALIVE void _esws_on_error(void *obj) {
+ EMWSClient *client = static_cast<EMWSClient *>(obj);
+ client->_is_connecting = false;
+ client->_on_error();
+}
+
+EMSCRIPTEN_KEEPALIVE void _esws_on_close(void *obj, int code, char *reason, int was_clean) {
+ EMWSClient *client = static_cast<EMWSClient *>(obj);
+ client->_is_connecting = false;
+ client->_on_disconnect();
+}
+}
+
+Error EMWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocols) {
+
+ String str = "ws://";
+ String proto_string = "";
+ int i = 0;
+
+ if (p_ssl)
+ str = "wss://";
+ str += p_host + ":" + itos(p_port) + p_path;
+ for (int i = 0; i < p_protocols.size(); i++) {
+ proto_string += p_protocols[i];
+ proto_string += ",";
+ }
+ if (proto_string == "")
+ proto_string = "binary,";
+
+ proto_string = proto_string.substr(0, proto_string.length() - 1);
+
+ _is_connecting = true;
+ /* clang-format off */
+ int peer_sock = EM_ASM_INT({
+ var socket = new WebSocket(UTF8ToString($1), UTF8ToString($2).split(","));
+ var c_ptr = Module.IDHandler.get($0);
+ socket.binaryType = "arraybuffer";
+
+ // Connection opened
+ socket.addEventListener("open", function (event) {
+ if (!Module.IDHandler.has($0))
+ return; // Godot Object is gone!
+ ccall("_esws_on_connect",
+ "void",
+ ["number", "string"],
+ [c_ptr, socket.protocol]
+ );
+ });
+
+ // Listen for messages
+ socket.addEventListener("message", function (event) {
+ if (!Module.IDHandler.has($0))
+ return; // Godot Object is gone!
+ var buffer;
+ var is_string = 0;
+ if (event.data instanceof ArrayBuffer) {
+
+ buffer = new Uint8Array(event.data);
+
+ } else if (event.data instanceof Blob) {
+
+ alert("Blob type not supported");
+ return;
+
+ } else if (typeof event.data === "string") {
+
+ is_string = 1;
+ var enc = new TextEncoder("utf-8");
+ buffer = new Uint8Array(enc.encode(event.data));
+
+ } else {
+
+ alert("Unknown message type");
+ return;
+
+ }
+ var len = buffer.length*buffer.BYTES_PER_ELEMENT;
+ var out = Module._malloc(len);
+ Module.HEAPU8.set(buffer, out);
+ ccall("_esws_on_message",
+ "void",
+ ["number", "number", "number", "number"],
+ [c_ptr, out, len, is_string]
+ );
+ Module._free(out);
+ });
+
+ socket.addEventListener("error", function (event) {
+ if (!Module.IDHandler.has($0))
+ return; // Godot Object is gone!
+ ccall("_esws_on_error",
+ "void",
+ ["number"],
+ [c_ptr]
+ );
+ });
+
+ socket.addEventListener("close", function (event) {
+ if (!Module.IDHandler.has($0))
+ return; // Godot Object is gone!
+ var was_clean = 0;
+ if (event.was_clean)
+ was_clean = 1;
+ ccall("_esws_on_close",
+ "void",
+ ["number", "number", "string", "number"],
+ [c_ptr, event.code, event.reason, was_clean]
+ );
+ });
+
+ return Module.IDHandler.add(socket);
+ }, _js_id, str.utf8().get_data(), proto_string.utf8().get_data());
+ /* clang-format on */
+
+ static_cast<Ref<EMWSPeer> >(_peer)->set_sock(peer_sock);
+
+ return OK;
+};
+
+void EMWSClient::poll() {
+}
+
+Ref<WebSocketPeer> EMWSClient::get_peer(int p_peer_id) const {
+
+ return _peer;
+}
+
+NetworkedMultiplayerPeer::ConnectionStatus EMWSClient::get_connection_status() const {
+
+ if (_peer->is_connected_to_host())
+ return CONNECTION_CONNECTED;
+
+ if (_is_connecting)
+ return CONNECTION_CONNECTING;
+
+ return CONNECTION_DISCONNECTED;
+};
+
+void EMWSClient::disconnect_from_host() {
+
+ _peer->close();
+};
+
+IP_Address EMWSClient::get_connected_host() const {
+
+ return IP_Address();
+};
+
+uint16_t EMWSClient::get_connected_port() const {
+
+ return 1025;
+};
+
+EMWSClient::EMWSClient() {
+ _is_connecting = false;
+ _peer = Ref<EMWSPeer>(memnew(EMWSPeer));
+ /* clang-format off */
+ _js_id = EM_ASM_INT({
+ return Module.IDHandler.add($0);
+ }, this);
+ /* clang-format on */
+};
+
+EMWSClient::~EMWSClient() {
+
+ disconnect_from_host();
+ _peer = Ref<EMWSPeer>();
+ /* clang-format off */
+ EM_ASM({
+ Module.IDHandler.remove($0);
+ }, _js_id);
+ /* clang-format on */
+};
+
+#endif // JAVASCRIPT_ENABLED
diff --git a/modules/websocket/emws_client.h b/modules/websocket/emws_client.h
new file mode 100644
index 0000000000..8801f37007
--- /dev/null
+++ b/modules/websocket/emws_client.h
@@ -0,0 +1,62 @@
+/*************************************************************************/
+/* emws_client.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 EMWSCLIENT_H
+#define EMWSCLIENT_H
+
+#ifdef JAVASCRIPT_ENABLED
+
+#include "core/error_list.h"
+#include "emws_peer.h"
+#include "websocket_client.h"
+
+class EMWSClient : public WebSocketClient {
+
+ GDCIIMPL(EMWSClient, WebSocketClient);
+
+private:
+ int _js_id;
+
+public:
+ bool _is_connecting;
+
+ Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocol = PoolVector<String>());
+ Ref<WebSocketPeer> get_peer(int p_peer_id) const;
+ void disconnect_from_host();
+ IP_Address get_connected_host() const;
+ uint16_t get_connected_port() const;
+ virtual ConnectionStatus get_connection_status() const;
+ virtual void poll();
+ EMWSClient();
+ ~EMWSClient();
+};
+
+#endif // JAVASCRIPT_ENABLED
+
+#endif // EMWSCLIENT_H
diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp
new file mode 100644
index 0000000000..93665e6428
--- /dev/null
+++ b/modules/websocket/emws_peer.cpp
@@ -0,0 +1,173 @@
+/*************************************************************************/
+/* emws_peer.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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. */
+/*************************************************************************/
+#ifdef JAVASCRIPT_ENABLED
+
+#include "emws_peer.h"
+#include "core/io/ip.h"
+
+void EMWSPeer::set_sock(int p_sock) {
+
+ peer_sock = p_sock;
+ in_buffer.clear();
+ queue_count = 0;
+}
+
+void EMWSPeer::set_write_mode(WriteMode p_mode) {
+ write_mode = p_mode;
+}
+
+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();
+ }
+
+ 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++;
+}
+
+Error EMWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
+
+ int is_bin = write_mode == WebSocketPeer::WRITE_MODE_BINARY ? 1 : 0;
+
+ /* clang-format off */
+ EM_ASM({
+ var sock = Module.IDHandler.get($0);
+ var bytes_array = new Uint8Array($2);
+ var i = 0;
+
+ for(i=0; i<$2; i++) {
+ bytes_array[i] = getValue($1+i, 'i8');
+ }
+
+ if ($3) {
+ sock.send(bytes_array.buffer);
+ } else {
+ var string = new TextDecoder("utf-8").decode(bytes_array);
+ sock.send(string);
+ }
+ }, peer_sock, p_buffer, p_buffer_size, is_bin);
+ /* clang-format on */
+
+ return OK;
+};
+
+Error EMWSPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
+
+ if (queue_count == 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();
+
+ 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;
+
+ return OK;
+};
+
+int EMWSPeer::get_available_packet_count() const {
+
+ return queue_count;
+};
+
+bool EMWSPeer::was_string_packet() const {
+
+ return _was_string;
+};
+
+bool EMWSPeer::is_connected_to_host() const {
+
+ return peer_sock != -1;
+};
+
+void EMWSPeer::close() {
+
+ if (peer_sock != -1) {
+ /* clang-format off */
+ EM_ASM({
+ var sock = Module.IDHandler.get($0);
+ sock.close();
+ Module.IDHandler.remove($0);
+ }, peer_sock);
+ /* clang-format on */
+ }
+ peer_sock = -1;
+ queue_count = 0;
+ in_buffer.clear();
+};
+
+IP_Address EMWSPeer::get_connected_host() const {
+
+ return IP_Address();
+};
+
+uint16_t EMWSPeer::get_connected_port() const {
+
+ return 1025;
+};
+
+EMWSPeer::EMWSPeer() {
+ peer_sock = -1;
+ queue_count = 0;
+ _was_string = false;
+ in_buffer.resize(16);
+ write_mode = WRITE_MODE_BINARY;
+};
+
+EMWSPeer::~EMWSPeer() {
+
+ in_buffer.resize(0);
+ close();
+};
+
+#endif // JAVASCRIPT_ENABLED
diff --git a/modules/websocket/emws_peer.h b/modules/websocket/emws_peer.h
new file mode 100644
index 0000000000..a50d1874ba
--- /dev/null
+++ b/modules/websocket/emws_peer.h
@@ -0,0 +1,85 @@
+/*************************************************************************/
+/* emws_peer.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 EMWSPEER_H
+#define EMWSPEER_H
+
+#ifdef JAVASCRIPT_ENABLED
+
+#include "core/error_list.h"
+#include "core/io/packet_peer.h"
+#include "core/ring_buffer.h"
+#include "emscripten.h"
+#include "websocket_peer.h"
+
+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;
+
+public:
+ void read_msg(uint8_t *p_data, uint32_t p_size, bool p_is_string);
+ void set_sock(int sock);
+ 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 void close();
+ virtual bool is_connected_to_host() const;
+ virtual IP_Address get_connected_host() const;
+ virtual uint16_t get_connected_port() const;
+
+ virtual WriteMode get_write_mode() const;
+ 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();
+};
+
+#endif // JAVASCRIPT_ENABLED
+
+#endif // LSWPEER_H
diff --git a/modules/websocket/emws_server.cpp b/modules/websocket/emws_server.cpp
new file mode 100644
index 0000000000..60e9133225
--- /dev/null
+++ b/modules/websocket/emws_server.cpp
@@ -0,0 +1,67 @@
+/*************************************************************************/
+/* emws_server.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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. */
+/*************************************************************************/
+#ifdef JAVASCRIPT_ENABLED
+
+#include "emws_server.h"
+#include "core/os/os.h"
+
+Error EMWSServer::listen(int p_port, PoolVector<String> p_protocols, bool gd_mp_api) {
+
+ return FAILED;
+}
+
+bool EMWSServer::is_listening() const {
+ return false;
+}
+
+void EMWSServer::stop() {
+}
+
+bool EMWSServer::has_peer(int p_id) const {
+ return false;
+}
+
+Ref<WebSocketPeer> EMWSServer::get_peer(int p_id) const {
+ return NULL;
+}
+
+PoolVector<String> EMWSServer::get_protocols() const {
+ PoolVector<String> out;
+
+ return out;
+}
+
+EMWSServer::EMWSServer() {
+}
+
+EMWSServer::~EMWSServer() {
+}
+
+#endif // JAVASCRIPT_ENABLED
diff --git a/modules/websocket/emws_server.h b/modules/websocket/emws_server.h
new file mode 100644
index 0000000000..59f1d76346
--- /dev/null
+++ b/modules/websocket/emws_server.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* emws_server.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 EMWSSERVER_H
+#define EMWSSERVER_H
+
+#ifdef JAVASCRIPT_ENABLED
+
+#include "core/reference.h"
+#include "emws_peer.h"
+#include "websocket_server.h"
+
+class EMWSServer : public WebSocketServer {
+
+ GDCIIMPL(EMWSServer, WebSocketServer);
+
+public:
+ Error listen(int p_port, PoolVector<String> p_protocols = PoolVector<String>(), bool gd_mp_api = false);
+ void stop();
+ bool is_listening() const;
+ bool has_peer(int p_id) const;
+ Ref<WebSocketPeer> get_peer(int p_id) const;
+ virtual void poll();
+ virtual PoolVector<String> get_protocols() const;
+
+ EMWSServer();
+ ~EMWSServer();
+};
+
+#endif
+
+#endif // LWSSERVER_H
diff --git a/modules/websocket/lws_client.cpp b/modules/websocket/lws_client.cpp
new file mode 100644
index 0000000000..604b1886ad
--- /dev/null
+++ b/modules/websocket/lws_client.cpp
@@ -0,0 +1,203 @@
+/*************************************************************************/
+/* lws_client.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 JAVASCRIPT_ENABLED
+
+#include "lws_client.h"
+#include "core/io/ip.h"
+
+Error LWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocols) {
+
+ ERR_FAIL_COND_V(context != NULL, FAILED);
+
+ IP_Address addr;
+
+ if (!p_host.is_valid_ip_address()) {
+ addr = IP::get_singleton()->resolve_hostname(p_host);
+ } else {
+ addr = p_host;
+ }
+
+ ERR_FAIL_COND_V(!addr.is_valid(), ERR_INVALID_PARAMETER);
+
+ // prepare protocols
+ if (p_protocols.size() == 0) // default to binary protocol
+ p_protocols.append("binary");
+ _lws_make_protocols(this, &LWSClient::_lws_gd_callback, p_protocols, &_lws_ref);
+
+ // init lws client
+ struct lws_context_creation_info info;
+ struct lws_client_connect_info i;
+
+ memset(&i, 0, sizeof i);
+ memset(&info, 0, sizeof info);
+
+ info.port = CONTEXT_PORT_NO_LISTEN;
+ info.protocols = _lws_ref->lws_structs;
+ info.gid = -1;
+ info.uid = -1;
+ //info.ws_ping_pong_interval = 5;
+ info.user = _lws_ref;
+ context = lws_create_context(&info);
+
+ if (context == NULL) {
+ _lws_free_ref(_lws_ref);
+ _lws_ref = NULL;
+ ERR_EXPLAIN("Unable to create lws context");
+ ERR_FAIL_V(FAILED);
+ }
+
+ char abuf[1024];
+ char hbuf[1024];
+ char pbuf[2048];
+ String addr_str = (String)addr;
+ strncpy(abuf, addr_str.ascii().get_data(), 1024);
+ strncpy(hbuf, p_host.utf8().get_data(), 1024);
+ strncpy(pbuf, p_path.utf8().get_data(), 2048);
+
+ i.context = context;
+ i.protocol = _lws_ref->lws_names;
+ i.address = abuf;
+ i.host = hbuf;
+ i.path = pbuf;
+ i.port = p_port;
+ i.ssl_connection = p_ssl;
+
+ lws_client_connect_via_info(&i);
+ return OK;
+};
+
+void LWSClient::poll() {
+
+ _lws_poll();
+}
+
+int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
+
+ Ref<LWSPeer> peer = static_cast<Ref<LWSPeer> >(_peer);
+ LWSPeer::PeerData *peer_data = (LWSPeer::PeerData *)user;
+
+ switch (reason) {
+
+ case LWS_CALLBACK_CLIENT_ESTABLISHED:
+ peer->set_wsi(wsi);
+ peer_data->peer_id = 0;
+ peer_data->in_size = 0;
+ peer_data->in_count = 0;
+ peer_data->out_count = 0;
+ peer_data->rbw.resize(16);
+ peer_data->rbr.resize(16);
+ peer_data->force_close = false;
+ _on_connect(lws_get_protocol(wsi)->name);
+ break;
+
+ case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+ _on_error();
+ destroy_context();
+ return -1; // we should close the connection (would probably happen anyway)
+
+ case LWS_CALLBACK_CLOSED:
+ peer_data->in_count = 0;
+ peer_data->out_count = 0;
+ peer_data->rbw.resize(0);
+ peer_data->rbr.resize(0);
+ peer->close();
+ destroy_context();
+ _on_disconnect();
+ return 0; // we can end here
+
+ case LWS_CALLBACK_CLIENT_RECEIVE:
+ peer->read_wsi(in, len);
+ if (peer->get_available_packet_count() > 0)
+ _on_peer_packet();
+ break;
+
+ case LWS_CALLBACK_CLIENT_WRITEABLE:
+ if (peer_data->force_close)
+ return -1;
+
+ peer->write_wsi();
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+Ref<WebSocketPeer> LWSClient::get_peer(int p_peer_id) const {
+
+ return _peer;
+}
+
+NetworkedMultiplayerPeer::ConnectionStatus LWSClient::get_connection_status() const {
+
+ if (context == NULL)
+ return CONNECTION_DISCONNECTED;
+
+ if (_peer->is_connected_to_host())
+ return CONNECTION_CONNECTED;
+
+ return CONNECTION_CONNECTING;
+}
+
+void LWSClient::disconnect_from_host() {
+
+ if (context == NULL)
+ return;
+
+ _peer->close();
+ destroy_context();
+};
+
+IP_Address LWSClient::get_connected_host() const {
+
+ return IP_Address();
+};
+
+uint16_t LWSClient::get_connected_port() const {
+
+ return 1025;
+};
+
+LWSClient::LWSClient() {
+ context = NULL;
+ _lws_ref = NULL;
+ _peer = Ref<LWSPeer>(memnew(LWSPeer));
+};
+
+LWSClient::~LWSClient() {
+
+ invalidate_lws_ref(); // We do not want any more callback
+ disconnect_from_host();
+ _peer = Ref<LWSPeer>();
+};
+
+#endif // JAVASCRIPT_ENABLED
diff --git a/modules/websocket/lws_client.h b/modules/websocket/lws_client.h
new file mode 100644
index 0000000000..2e082175df
--- /dev/null
+++ b/modules/websocket/lws_client.h
@@ -0,0 +1,61 @@
+/*************************************************************************/
+/* lws_client.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 LWSCLIENT_H
+#define LWSCLIENT_H
+
+#ifndef JAVASCRIPT_ENABLED
+
+#include "core/error_list.h"
+#include "lws_helper.h"
+#include "lws_peer.h"
+#include "websocket_client.h"
+
+class LWSClient : public WebSocketClient {
+
+ GDCIIMPL(LWSClient, WebSocketClient);
+
+ LWS_HELPER(LWSClient);
+
+public:
+ Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocol = PoolVector<String>());
+ Ref<WebSocketPeer> get_peer(int p_peer_id) const;
+ void disconnect_from_host();
+ IP_Address get_connected_host() const;
+ uint16_t get_connected_port() const;
+ virtual ConnectionStatus get_connection_status() const;
+ virtual void poll();
+
+ LWSClient();
+ ~LWSClient();
+};
+
+#endif // JAVASCRIPT_ENABLED
+
+#endif // LWSCLIENT_H
diff --git a/modules/websocket/lws_helper.h b/modules/websocket/lws_helper.h
new file mode 100644
index 0000000000..a832d458b6
--- /dev/null
+++ b/modules/websocket/lws_helper.h
@@ -0,0 +1,214 @@
+/*************************************************************************/
+/* lws_helper.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 LWS_HELPER_H
+#define LWS_HELPER_H
+
+#include "core/io/stream_peer.h"
+#include "core/os/os.h"
+#include "core/reference.h"
+#include "core/ring_buffer.h"
+#include "lws_peer.h"
+
+struct _LWSRef {
+ bool free_context;
+ bool is_polling;
+ bool is_valid;
+ bool is_destroying;
+ void *obj;
+ struct lws_protocols *lws_structs;
+ char *lws_names;
+};
+
+static _LWSRef *_lws_create_ref(void *obj) {
+
+ _LWSRef *out = (_LWSRef *)memalloc(sizeof(_LWSRef));
+ out->is_destroying = false;
+ out->free_context = false;
+ out->is_polling = false;
+ out->obj = obj;
+ out->is_valid = true;
+ out->lws_structs = NULL;
+ out->lws_names = NULL;
+ return out;
+}
+
+static void _lws_free_ref(_LWSRef *ref) {
+ // Free strings and structs
+ memfree(ref->lws_structs);
+ memfree(ref->lws_names);
+ // Free ref
+ memfree(ref);
+}
+
+static bool _lws_destroy(struct lws_context *context, _LWSRef *ref) {
+ if (context == NULL || ref->is_destroying)
+ return false;
+
+ if (ref->is_polling) {
+ ref->free_context = true;
+ return false;
+ }
+
+ ref->is_destroying = true;
+ lws_context_destroy(context);
+ _lws_free_ref(ref);
+ return true;
+}
+
+static bool _lws_poll(struct lws_context *context, _LWSRef *ref) {
+
+ ERR_FAIL_COND_V(context == NULL, false);
+ ERR_FAIL_COND_V(ref == NULL, false);
+
+ ref->is_polling = true;
+ lws_service(context, 0);
+ ref->is_polling = false;
+
+ if (!ref->free_context)
+ return false; // Nothing to do
+
+ bool is_valid = ref->is_valid; // Might have been destroyed by poll
+
+ _lws_destroy(context, ref); // Will destroy context and ref
+
+ return is_valid; // If the object should NULL its context and ref
+}
+
+/*
+ * prepare the protocol_structs to be fed to context
+ * also prepare the protocol string used by the client
+ */
+static void _lws_make_protocols(void *p_obj, lws_callback_function *p_callback, PoolVector<String> p_names, _LWSRef **r_lws_ref) {
+ /* the input strings might go away after this call,
+ * we need to copy them. Will clear them when
+ * destroying the context */
+ int i;
+ int len = p_names.size();
+ size_t data_size = sizeof(struct LWSPeer::PeerData);
+ PoolVector<String>::Read pnr = p_names.read();
+
+ /*
+ * This is a reference connecting the object with lws
+ * keep track of status, mallocs, etc.
+ * Must survive as long the context
+ * Must be freed manually when context creation fails.
+ */
+ _LWSRef *ref = _lws_create_ref(p_obj);
+
+ /* LWS protocol structs */
+ ref->lws_structs = (struct lws_protocols *)memalloc(sizeof(struct lws_protocols) * (len + 2));
+
+ CharString strings = p_names.join(",").ascii();
+ int str_len = strings.length();
+
+ /* Joined string of protocols, double the size: comma separated first, NULL separated last */
+ ref->lws_names = (char *)memalloc((str_len + 1) * 2); /* plus the terminator */
+
+ char *names_ptr = ref->lws_names;
+ struct lws_protocols *structs_ptr = ref->lws_structs;
+
+ copymem(names_ptr, strings.get_data(), str_len);
+ names_ptr[str_len] = '\0'; /* NULL terminator */
+ /* NULL terminated strings to be used in protocol structs */
+ copymem(&names_ptr[str_len + 1], strings.get_data(), str_len);
+ names_ptr[(str_len * 2) + 1] = '\0'; /* NULL terminator */
+ int pos = str_len + 1;
+
+ /* the first protocol is always http-only */
+ structs_ptr[0].name = "http-only";
+ structs_ptr[0].callback = p_callback;
+ structs_ptr[0].per_session_data_size = data_size;
+ structs_ptr[0].rx_buffer_size = 0;
+ /* add user defined protocols */
+ for (i = 0; i < len; i++) {
+ structs_ptr[i + 1].name = (const char *)&names_ptr[pos];
+ structs_ptr[i + 1].callback = p_callback;
+ structs_ptr[i + 1].per_session_data_size = data_size;
+ structs_ptr[i + 1].rx_buffer_size = 0;
+ pos += pnr[i].ascii().length() + 1;
+ names_ptr[pos - 1] = '\0';
+ }
+ /* add protocols terminator */
+ structs_ptr[len + 1].name = NULL;
+ structs_ptr[len + 1].callback = NULL;
+ structs_ptr[len + 1].per_session_data_size = 0;
+ structs_ptr[len + 1].rx_buffer_size = 0;
+
+ *r_lws_ref = ref;
+}
+
+/* clang-format off */
+#define LWS_HELPER(CNAME) \
+protected: \
+ struct _LWSRef *_lws_ref; \
+ struct lws_context *context; \
+ \
+ static int _lws_gd_callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { \
+ \
+ if (wsi == NULL) { \
+ return 0; \
+ } \
+ \
+ struct _LWSRef *ref = (struct _LWSRef *)lws_context_user(lws_get_context(wsi)); \
+ if (!ref->is_valid) \
+ return 0; \
+ CNAME *helper = (CNAME *)ref->obj; \
+ return helper->_handle_cb(wsi, reason, user, in, len); \
+ } \
+ \
+ void invalidate_lws_ref() { \
+ if (_lws_ref != NULL) \
+ _lws_ref->is_valid = false; \
+ } \
+ \
+ void destroy_context() { \
+ if (_lws_destroy(context, _lws_ref)) { \
+ context = NULL; \
+ _lws_ref = NULL; \
+ } \
+ } \
+ \
+public: \
+ virtual int _handle_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); \
+ \
+ void _lws_poll() { \
+ ERR_FAIL_COND(context == NULL); \
+ \
+ if (::_lws_poll(context, _lws_ref)) { \
+ context = NULL; \
+ _lws_ref = NULL; \
+ } \
+ } \
+ \
+protected:
+
+ /* clang-format on */
+
+#endif // LWS_HELPER_H
diff --git a/modules/websocket/lws_peer.cpp b/modules/websocket/lws_peer.cpp
new file mode 100644
index 0000000000..fdaa79f9d4
--- /dev/null
+++ b/modules/websocket/lws_peer.cpp
@@ -0,0 +1,200 @@
+/*************************************************************************/
+/* lws_peer.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 JAVASCRIPT_ENABLED
+
+#include "lws_peer.h"
+#include "core/io/ip.h"
+
+void LWSPeer::set_wsi(struct lws *p_wsi) {
+ wsi = p_wsi;
+};
+
+void LWSPeer::set_write_mode(WriteMode p_mode) {
+ write_mode = p_mode;
+}
+
+LWSPeer::WriteMode LWSPeer::get_write_mode() const {
+ return write_mode;
+}
+
+Error LWSPeer::read_wsi(void *in, size_t len) {
+
+ ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
+
+ PeerData *peer_data = (PeerData *)(lws_wsi_user(wsi));
+ uint32_t size = peer_data->in_size;
+ uint8_t is_string = lws_frame_is_binary(wsi) ? 0 : 1;
+
+ if (peer_data->rbr.space_left() < len + 5) {
+ ERR_EXPLAIN("Buffer full! Dropping data");
+ ERR_FAIL_V(FAILED);
+ }
+
+ copymem(&(peer_data->input_buffer[size]), in, len);
+ size += len;
+
+ peer_data->in_size = size;
+ if (lws_is_final_fragment(wsi)) {
+ peer_data->rbr.write((uint8_t *)&size, 4);
+ peer_data->rbr.write((uint8_t *)&is_string, 1);
+ peer_data->rbr.write(peer_data->input_buffer, size);
+ peer_data->in_count++;
+ peer_data->in_size = 0;
+ }
+
+ return OK;
+}
+
+Error LWSPeer::write_wsi() {
+
+ ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
+
+ PeerData *peer_data = (PeerData *)(lws_wsi_user(wsi));
+ PoolVector<uint8_t> tmp;
+ int left = peer_data->rbw.data_left();
+ uint32_t to_write = 0;
+
+ if (left == 0 || peer_data->out_count == 0)
+ return OK;
+
+ peer_data->rbw.read((uint8_t *)&to_write, 4);
+ peer_data->out_count--;
+
+ if (left < to_write) {
+ peer_data->rbw.advance_read(left);
+ return FAILED;
+ }
+
+ tmp.resize(LWS_PRE + to_write);
+ peer_data->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);
+
+ if (peer_data->out_count > 0)
+ lws_callback_on_writable(wsi); // we want to write more!
+
+ return OK;
+}
+
+Error LWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
+
+ ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
+
+ PeerData *peer_data = (PeerData *)lws_wsi_user(wsi);
+ peer_data->rbw.write((uint8_t *)&p_buffer_size, 4);
+ peer_data->rbw.write(p_buffer, MIN(p_buffer_size, peer_data->rbw.space_left()));
+ peer_data->out_count++;
+
+ 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) {
+
+ ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
+
+ PeerData *peer_data = (PeerData *)lws_wsi_user(wsi);
+
+ if (peer_data->in_count == 0)
+ return ERR_UNAVAILABLE;
+
+ uint32_t to_read = 0;
+ uint32_t left = 0;
+ uint8_t is_string = 0;
+ r_buffer_size = 0;
+
+ peer_data->rbr.read((uint8_t *)&to_read, 4);
+ peer_data->in_count--;
+ left = peer_data->rbr.data_left();
+
+ if (left < to_read + 1) {
+ peer_data->rbr.advance_read(left);
+ return FAILED;
+ }
+
+ peer_data->rbr.read(&is_string, 1);
+ peer_data->rbr.read(packet_buffer, to_read);
+ *r_buffer = packet_buffer;
+ r_buffer_size = to_read;
+ _was_string = is_string;
+
+ return OK;
+};
+
+int LWSPeer::get_available_packet_count() const {
+
+ if (!is_connected_to_host())
+ return 0;
+
+ return ((PeerData *)lws_wsi_user(wsi))->in_count;
+};
+
+bool LWSPeer::was_string_packet() const {
+
+ return _was_string;
+};
+
+bool LWSPeer::is_connected_to_host() const {
+
+ return wsi != NULL;
+};
+
+void LWSPeer::close() {
+ if (wsi != NULL) {
+ struct lws *tmp = wsi;
+ PeerData *data = ((PeerData *)lws_wsi_user(wsi));
+ data->force_close = true;
+ wsi = NULL;
+ lws_callback_on_writable(tmp); // notify that we want to disconnect
+ }
+};
+
+IP_Address LWSPeer::get_connected_host() const {
+
+ return IP_Address();
+};
+
+uint16_t LWSPeer::get_connected_port() const {
+
+ return 1025;
+};
+
+LWSPeer::LWSPeer() {
+ wsi = NULL;
+ _was_string = false;
+ write_mode = WRITE_MODE_BINARY;
+};
+
+LWSPeer::~LWSPeer() {
+
+ close();
+};
+
+#endif // JAVASCRIPT_ENABLED
diff --git a/modules/websocket/lws_peer.h b/modules/websocket/lws_peer.h
new file mode 100644
index 0000000000..0a62b65d24
--- /dev/null
+++ b/modules/websocket/lws_peer.h
@@ -0,0 +1,92 @@
+/*************************************************************************/
+/* lws_peer.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 LWSPEER_H
+#define LWSPEER_H
+
+#ifndef JAVASCRIPT_ENABLED
+
+#include "core/error_list.h"
+#include "core/io/packet_peer.h"
+#include "core/ring_buffer.h"
+#include "libwebsockets.h"
+#include "lws_config.h"
+#include "websocket_peer.h"
+
+class LWSPeer : public WebSocketPeer {
+
+ GDCIIMPL(LWSPeer, WebSocketPeer);
+
+private:
+ enum {
+ PACKET_BUFFER_SIZE = 65536 - 5 // 4 bytes for the size, 1 for the type
+ };
+
+ uint8_t packet_buffer[PACKET_BUFFER_SIZE];
+ struct lws *wsi;
+ WriteMode write_mode;
+ bool _was_string;
+
+public:
+ struct PeerData {
+ uint32_t peer_id;
+ bool force_close;
+ RingBuffer<uint8_t> rbw;
+ RingBuffer<uint8_t> rbr;
+ mutable 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 void close();
+ virtual bool is_connected_to_host() const;
+ virtual IP_Address get_connected_host() const;
+ virtual uint16_t get_connected_port() const;
+
+ virtual WriteMode get_write_mode() const;
+ 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();
+
+ LWSPeer();
+ ~LWSPeer();
+};
+
+#endif // JAVASCRIPT_ENABLED
+
+#endif // LSWPEER_H
diff --git a/modules/websocket/lws_server.cpp b/modules/websocket/lws_server.cpp
new file mode 100644
index 0000000000..8a47ba557d
--- /dev/null
+++ b/modules/websocket/lws_server.cpp
@@ -0,0 +1,177 @@
+/*************************************************************************/
+/* lws_server.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 JAVASCRIPT_ENABLED
+
+#include "lws_server.h"
+#include "core/os/os.h"
+
+Error LWSServer::listen(int p_port, PoolVector<String> p_protocols, bool gd_mp_api) {
+
+ ERR_FAIL_COND_V(context != NULL, FAILED);
+
+ _is_multiplayer = gd_mp_api;
+
+ struct lws_context_creation_info info;
+ memset(&info, 0, sizeof info);
+
+ if (p_protocols.size() == 0) // default to binary protocol
+ p_protocols.append(String("binary"));
+
+ // Prepare lws protocol structs
+ _lws_make_protocols(this, &LWSServer::_lws_gd_callback, p_protocols, &_lws_ref);
+
+ info.port = p_port;
+ info.user = _lws_ref;
+ info.protocols = _lws_ref->lws_structs;
+ info.gid = -1;
+ info.uid = -1;
+ //info.ws_ping_pong_interval = 5;
+
+ context = lws_create_context(&info);
+
+ if (context == NULL) {
+ _lws_free_ref(_lws_ref);
+ _lws_ref = NULL;
+ ERR_EXPLAIN("Unable to create LWS context");
+ ERR_FAIL_V(FAILED);
+ }
+
+ return OK;
+}
+
+bool LWSServer::is_listening() const {
+ return context != NULL;
+}
+
+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;
+
+ switch (reason) {
+ case LWS_CALLBACK_HTTP:
+ // no http for now
+ // closing immediately returning -1;
+ return -1;
+
+ case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
+ // check header here?
+ break;
+
+ case LWS_CALLBACK_ESTABLISHED: {
+ int32_t id = _gen_unique_id();
+
+ Ref<LWSPeer> peer = Ref<LWSPeer>(memnew(LWSPeer));
+ peer->set_wsi(wsi);
+ _peer_map[id] = peer;
+
+ peer_data->peer_id = id;
+ peer_data->in_size = 0;
+ peer_data->in_count = 0;
+ peer_data->out_count = 0;
+ peer_data->rbw.resize(16);
+ peer_data->rbr.resize(16);
+ peer_data->force_close = false;
+
+ _on_connect(id, lws_get_protocol(wsi)->name);
+ break;
+ }
+
+ case LWS_CALLBACK_CLOSED: {
+ if (peer_data == NULL)
+ return 0;
+ int32_t id = peer_data->peer_id;
+ if (_peer_map.has(id)) {
+ _peer_map[id]->close();
+ _peer_map.erase(id);
+ }
+ peer_data->in_count = 0;
+ peer_data->out_count = 0;
+ peer_data->rbr.resize(0);
+ peer_data->rbw.resize(0);
+ _on_disconnect(id);
+ return 0; // we can end here
+ }
+
+ case LWS_CALLBACK_RECEIVE: {
+ int32_t id = peer_data->peer_id;
+ if (_peer_map.has(id)) {
+ static_cast<Ref<LWSPeer> >(_peer_map[id])->read_wsi(in, len);
+ if (_peer_map[id]->get_available_packet_count() > 0)
+ _on_peer_packet(id);
+ }
+ break;
+ }
+
+ case LWS_CALLBACK_SERVER_WRITEABLE: {
+ if (peer_data->force_close)
+ return -1;
+
+ int id = peer_data->peer_id;
+ if (_peer_map.has(id))
+ static_cast<Ref<LWSPeer> >(_peer_map[id])->write_wsi();
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+void LWSServer::stop() {
+ if (context == NULL)
+ return;
+
+ _peer_map.clear();
+ destroy_context();
+ context = NULL;
+}
+
+bool LWSServer::has_peer(int p_id) const {
+ return _peer_map.has(p_id);
+}
+
+Ref<WebSocketPeer> LWSServer::get_peer(int p_id) const {
+ ERR_FAIL_COND_V(!has_peer(p_id), NULL);
+ return _peer_map[p_id];
+}
+
+LWSServer::LWSServer() {
+ context = NULL;
+ _lws_ref = NULL;
+}
+
+LWSServer::~LWSServer() {
+ invalidate_lws_ref(); // we do not want any more callbacks
+ stop();
+}
+
+#endif // JAVASCRIPT_ENABLED
diff --git a/modules/websocket/lws_server.h b/modules/websocket/lws_server.h
new file mode 100644
index 0000000000..5f7ac4850a
--- /dev/null
+++ b/modules/websocket/lws_server.h
@@ -0,0 +1,63 @@
+/*************************************************************************/
+/* lws_server.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 LWSSERVER_H
+#define LWSSERVER_H
+
+#ifndef JAVASCRIPT_ENABLED
+
+#include "core/reference.h"
+#include "lws_helper.h"
+#include "lws_peer.h"
+#include "websocket_server.h"
+
+class LWSServer : public WebSocketServer {
+
+ GDCIIMPL(LWSServer, WebSocketServer);
+
+ LWS_HELPER(LWSServer);
+
+private:
+ Map<int, Ref<LWSPeer> > peer_map;
+
+public:
+ Error listen(int p_port, PoolVector<String> p_protocols = PoolVector<String>(), bool gd_mp_api = false);
+ void stop();
+ bool is_listening() const;
+ bool has_peer(int p_id) const;
+ Ref<WebSocketPeer> get_peer(int p_id) const;
+ virtual void poll() { _lws_poll(); }
+
+ LWSServer();
+ ~LWSServer();
+};
+
+#endif // JAVASCRIPT_ENABLED
+
+#endif // LWSSERVER_H
diff --git a/modules/websocket/register_types.cpp b/modules/websocket/register_types.cpp
new file mode 100644
index 0000000000..39d03ff1f0
--- /dev/null
+++ b/modules/websocket/register_types.cpp
@@ -0,0 +1,79 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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. */
+/*************************************************************************/
+#include "register_types.h"
+#include "error_macros.h"
+#ifdef JAVASCRIPT_ENABLED
+#include "emscripten.h"
+#include "emws_client.h"
+#include "emws_peer.h"
+#include "emws_server.h"
+#else
+#include "lws_client.h"
+#include "lws_peer.h"
+#include "lws_server.h"
+#endif
+
+void register_websocket_types() {
+#ifdef JAVASCRIPT_ENABLED
+ EM_ASM({
+ var IDHandler = {};
+ IDHandler["ids"] = {};
+ IDHandler["has"] = function(id) {
+ return IDHandler.ids.hasOwnProperty(id);
+ };
+ IDHandler["add"] = function(obj) {
+ var id = crypto.getRandomValues(new Int32Array(32))[0];
+ IDHandler.ids[id] = obj;
+ return id;
+ };
+ IDHandler["get"] = function(id) {
+ return IDHandler.ids[id];
+ };
+ IDHandler["remove"] = function(id) {
+ delete IDHandler.ids[id];
+ };
+ Module["IDHandler"] = IDHandler;
+ });
+ EMWSPeer::make_default();
+ EMWSClient::make_default();
+ EMWSServer::make_default();
+#else
+ LWSPeer::make_default();
+ LWSClient::make_default();
+ LWSServer::make_default();
+#endif
+
+ ClassDB::register_virtual_class<WebSocketMultiplayerPeer>();
+ ClassDB::register_custom_instance_class<WebSocketServer>();
+ ClassDB::register_custom_instance_class<WebSocketClient>();
+ ClassDB::register_custom_instance_class<WebSocketPeer>();
+}
+
+void unregister_websocket_types() {}
diff --git a/modules/websocket/register_types.h b/modules/websocket/register_types.h
new file mode 100644
index 0000000000..010d88789b
--- /dev/null
+++ b/modules/websocket/register_types.h
@@ -0,0 +1,31 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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. */
+/*************************************************************************/
+void register_websocket_types();
+void unregister_websocket_types();
diff --git a/modules/websocket/websocket_client.cpp b/modules/websocket/websocket_client.cpp
new file mode 100644
index 0000000000..f92a386988
--- /dev/null
+++ b/modules/websocket/websocket_client.cpp
@@ -0,0 +1,124 @@
+/*************************************************************************/
+/* websocket_client.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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. */
+/*************************************************************************/
+#include "websocket_client.h"
+
+GDCINULL(WebSocketClient);
+
+WebSocketClient::WebSocketClient() {
+}
+
+WebSocketClient::~WebSocketClient() {
+}
+
+Error WebSocketClient::connect_to_url(String p_url, PoolVector<String> p_protocols, bool gd_mp_api) {
+ _is_multiplayer = gd_mp_api;
+
+ String host = p_url;
+ String path = "/";
+ int p_len = -1;
+ int port = 80;
+ bool ssl = false;
+ if (host.begins_with("wss://")) {
+ ssl = true; // we should implement this
+ host = host.substr(6, host.length() - 6);
+ port = 443;
+ } else {
+ ssl = false;
+ if (host.begins_with("ws://"))
+ host = host.substr(5, host.length() - 5);
+ }
+
+ // Path
+ p_len = host.find("/");
+ if (p_len != -1) {
+ path = host.substr(p_len, host.length() - p_len);
+ host = host.substr(0, p_len);
+ }
+
+ // Port
+ p_len = host.find_last(":");
+ if (p_len != -1 && p_len == host.find(":")) {
+ port = host.substr(p_len, host.length() - p_len).to_int();
+ host = host.substr(0, p_len);
+ }
+
+ return connect_to_host(host, path, port, ssl, p_protocols);
+}
+
+bool WebSocketClient::is_server() const {
+
+ return false;
+}
+
+void WebSocketClient::_on_peer_packet() {
+
+ if (_is_multiplayer) {
+ _process_multiplayer(get_peer(1), 1);
+ } else {
+ emit_signal("data_received");
+ }
+}
+
+void WebSocketClient::_on_connect(String p_protocol) {
+
+ if (_is_multiplayer) {
+ // need to wait for ID confirmation...
+ } else {
+ emit_signal("connection_established", p_protocol);
+ }
+}
+
+void WebSocketClient::_on_disconnect() {
+
+ if (_is_multiplayer) {
+ emit_signal("connection_failed");
+ } else {
+ emit_signal("connection_closed");
+ }
+}
+
+void WebSocketClient::_on_error() {
+
+ if (_is_multiplayer) {
+ emit_signal("connection_failed");
+ } else {
+ emit_signal("connection_error");
+ }
+}
+
+void WebSocketClient::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("connect_to_url", "url", "protocols", "gd_mp_api"), &WebSocketClient::connect_to_url, DEFVAL(PoolVector<String>()), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("disconnect_from_host"), &WebSocketClient::disconnect_from_host);
+
+ ADD_SIGNAL(MethodInfo("data_received"));
+ ADD_SIGNAL(MethodInfo("connection_established", PropertyInfo(Variant::STRING, "protocol")));
+ ADD_SIGNAL(MethodInfo("connection_closed"));
+ ADD_SIGNAL(MethodInfo("connection_error"));
+}
diff --git a/modules/websocket/websocket_client.h b/modules/websocket/websocket_client.h
new file mode 100644
index 0000000000..0e87825222
--- /dev/null
+++ b/modules/websocket/websocket_client.h
@@ -0,0 +1,68 @@
+/*************************************************************************/
+/* websocket_client.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 WEBSOCKET_CLIENT_H
+#define WEBSOCKET_CLIENT_H
+
+#include "core/error_list.h"
+#include "websocket_multiplayer.h"
+#include "websocket_peer.h"
+
+class WebSocketClient : public WebSocketMultiplayerPeer {
+
+ GDCLASS(WebSocketClient, WebSocketMultiplayerPeer);
+ GDCICLASS(WebSocketClient);
+
+protected:
+ Ref<WebSocketPeer> _peer;
+
+ static void _bind_methods();
+
+public:
+ Error connect_to_url(String p_url, PoolVector<String> p_protocols = PoolVector<String>(), bool gd_mp_api = false);
+
+ virtual void poll() = 0;
+ virtual Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocol = PoolVector<String>()) = 0;
+ virtual void disconnect_from_host() = 0;
+ virtual IP_Address get_connected_host() const = 0;
+ virtual uint16_t get_connected_port() const = 0;
+
+ virtual bool is_server() const;
+ virtual ConnectionStatus get_connection_status() const = 0;
+
+ void _on_peer_packet();
+ void _on_connect(String p_protocol);
+ void _on_disconnect();
+ void _on_error();
+
+ WebSocketClient();
+ ~WebSocketClient();
+};
+
+#endif // WEBSOCKET_CLIENT_H
diff --git a/modules/websocket/websocket_macros.h b/modules/websocket/websocket_macros.h
new file mode 100644
index 0000000000..b5c2159806
--- /dev/null
+++ b/modules/websocket/websocket_macros.h
@@ -0,0 +1,63 @@
+/*************************************************************************/
+/* websocket_macros.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 WEBSOCKETMACTOS_H
+#define WEBSOCKETMACTOS_H
+
+/* clang-format off */
+#define GDCICLASS(CNAME) \
+public:\
+ static CNAME *(*_create)();\
+\
+ static Ref<CNAME > create_ref() {\
+\
+ if (!_create)\
+ return Ref<CNAME >();\
+ return Ref<CNAME >(_create());\
+ }\
+\
+ static CNAME *create() {\
+\
+ if (!_create)\
+ return NULL;\
+ return _create();\
+ }\
+protected:\
+
+#define GDCINULL(CNAME) \
+CNAME *(*CNAME::_create)() = NULL;
+
+#define GDCIIMPL(IMPNAME, CNAME) \
+public:\
+ static CNAME *_create() { return memnew(IMPNAME); }\
+ static void make_default() { CNAME::_create = IMPNAME::_create; }\
+protected:\
+/* clang-format on */
+
+#endif // WEBSOCKETMACTOS_H
diff --git a/modules/websocket/websocket_multiplayer.cpp b/modules/websocket/websocket_multiplayer.cpp
new file mode 100644
index 0000000000..8cd4dff38b
--- /dev/null
+++ b/modules/websocket/websocket_multiplayer.cpp
@@ -0,0 +1,361 @@
+/*************************************************************************/
+/* websocket_multiplayer.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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. */
+/*************************************************************************/
+#include "websocket_multiplayer.h"
+#include "core/os/os.h"
+
+WebSocketMultiplayerPeer::WebSocketMultiplayerPeer() {
+
+ _is_multiplayer = false;
+ _peer_id = 0;
+ _target_peer = 0;
+ _refusing = false;
+
+ _current_packet.source = 0;
+ _current_packet.destination = 0;
+ _current_packet.size = 0;
+ _current_packet.data = NULL;
+}
+
+WebSocketMultiplayerPeer::~WebSocketMultiplayerPeer() {
+
+ _clear();
+}
+
+int WebSocketMultiplayerPeer::_gen_unique_id() const {
+
+ uint32_t hash = 0;
+
+ while (hash == 0 || hash == 1) {
+
+ hash = hash_djb2_one_32(
+ (uint32_t)OS::get_singleton()->get_ticks_usec());
+ hash = hash_djb2_one_32(
+ (uint32_t)OS::get_singleton()->get_unix_time(), hash);
+ hash = hash_djb2_one_32(
+ (uint32_t)OS::get_singleton()->get_data_path().hash64(), hash);
+ hash = hash_djb2_one_32(
+ (uint32_t)((uint64_t)this), hash); //rely on aslr heap
+ hash = hash_djb2_one_32(
+ (uint32_t)((uint64_t)&hash), hash); //rely on aslr stack
+ hash = hash & 0x7FFFFFFF; // make it compatible with unsigned, since negatie id is used for exclusion
+ }
+
+ return hash;
+}
+void WebSocketMultiplayerPeer::_clear() {
+
+ _peer_map.clear();
+ if (_current_packet.data != NULL)
+ memfree(_current_packet.data);
+
+ for (List<Packet>::Element *E = _incoming_packets.front(); E; E = E->next()) {
+ memfree(E->get().data);
+ E->get().data = NULL;
+ }
+
+ _incoming_packets.clear();
+}
+
+void WebSocketMultiplayerPeer::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("get_peer", "peer_id"), &WebSocketMultiplayerPeer::get_peer);
+
+ ADD_SIGNAL(MethodInfo("peer_packet", PropertyInfo(Variant::INT, "peer_source")));
+}
+
+//
+// PacketPeer
+//
+int WebSocketMultiplayerPeer::get_available_packet_count() const {
+
+ ERR_FAIL_COND_V(!_is_multiplayer, ERR_UNCONFIGURED);
+
+ 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;
+ ERR_FAIL_COND_V(!_is_multiplayer, ERR_UNCONFIGURED);
+
+ if (_current_packet.data != NULL) {
+ memfree(_current_packet.data);
+ _current_packet.data = NULL;
+ }
+
+ _current_packet = _incoming_packets.front()->get();
+ _incoming_packets.pop_front();
+
+ *r_buffer = _current_packet.data;
+ r_buffer_size = _current_packet.size;
+
+ return OK;
+}
+
+Error WebSocketMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
+
+ ERR_FAIL_COND_V(!_is_multiplayer, ERR_UNCONFIGURED);
+
+ PoolVector<uint8_t> buffer = _make_pkt(SYS_NONE, get_unique_id(), _target_peer, p_buffer, p_buffer_size);
+
+ if (is_server()) {
+ return _server_relay(1, _target_peer, &(buffer.read()[0]), buffer.size());
+ } else {
+ return get_peer(1)->put_packet(&(buffer.read()[0]), buffer.size());
+ }
+}
+
+//
+// NetworkedMultiplayerPeer
+//
+void WebSocketMultiplayerPeer::set_transfer_mode(TransferMode p_mode) {
+
+ // Websocket uses TCP, reliable
+}
+
+NetworkedMultiplayerPeer::TransferMode WebSocketMultiplayerPeer::get_transfer_mode() const {
+
+ // Websocket uses TCP, reliable
+ return TRANSFER_MODE_RELIABLE;
+}
+
+void WebSocketMultiplayerPeer::set_target_peer(int p_target_peer) {
+
+ _target_peer = p_target_peer;
+}
+
+int WebSocketMultiplayerPeer::get_packet_peer() const {
+
+ ERR_FAIL_COND_V(!_is_multiplayer, 1);
+ ERR_FAIL_COND_V(_incoming_packets.size() == 0, 1);
+
+ return _incoming_packets.front()->get().source;
+}
+
+int WebSocketMultiplayerPeer::get_unique_id() const {
+
+ return _peer_id;
+}
+
+void WebSocketMultiplayerPeer::set_refuse_new_connections(bool p_enable) {
+
+ _refusing = p_enable;
+}
+
+bool WebSocketMultiplayerPeer::is_refusing_new_connections() const {
+
+ return _refusing;
+}
+
+void WebSocketMultiplayerPeer::_send_sys(Ref<WebSocketPeer> p_peer, uint8_t p_type, int32_t p_peer_id) {
+
+ ERR_FAIL_COND(!p_peer.is_valid());
+ ERR_FAIL_COND(!p_peer->is_connected_to_host());
+
+ PoolVector<uint8_t> message = _make_pkt(p_type, 1, 0, (uint8_t *)&p_peer_id, 4);
+ p_peer->put_packet(&(message.read()[0]), message.size());
+}
+
+PoolVector<uint8_t> WebSocketMultiplayerPeer::_make_pkt(uint32_t p_type, int32_t p_from, int32_t p_to, const uint8_t *p_data, uint32_t p_data_size) {
+
+ PoolVector<uint8_t> out;
+ out.resize(PROTO_SIZE + p_data_size);
+
+ PoolVector<uint8_t>::Write w = out.write();
+ copymem(&w[0], &p_type, 1);
+ copymem(&w[1], &p_from, 4);
+ copymem(&w[5], &p_to, 4);
+ copymem(&w[PROTO_SIZE], p_data, p_data_size);
+
+ return out;
+}
+
+void WebSocketMultiplayerPeer::_send_add(int32_t p_peer_id) {
+
+ // First of all, confirm the ID!
+ _send_sys(get_peer(p_peer_id), SYS_ID, p_peer_id);
+
+ // Then send the server peer (which will trigger connection_succeded in client)
+ _send_sys(get_peer(p_peer_id), SYS_ADD, 1);
+
+ for (Map<int, Ref<WebSocketPeer> >::Element *E = _peer_map.front(); E; E = E->next()) {
+ uint32_t id = E->key();
+ if (p_peer_id == id)
+ continue; // Skip the newwly added peer (already confirmed)
+
+ // Send new peer to others
+ _send_sys(get_peer(id), SYS_ADD, p_peer_id);
+ // Send others to new peer
+ _send_sys(get_peer(p_peer_id), SYS_ADD, id);
+ }
+}
+
+void WebSocketMultiplayerPeer::_send_del(int32_t p_peer_id) {
+ for (Map<int, Ref<WebSocketPeer> >::Element *E = _peer_map.front(); E; E = E->next()) {
+ uint32_t id = E->key();
+ if (p_peer_id != id)
+ _send_sys(get_peer(id), SYS_DEL, p_peer_id);
+ }
+}
+
+void WebSocketMultiplayerPeer::_store_pkt(int32_t p_source, int32_t p_dest, const uint8_t *p_data, uint32_t p_data_size) {
+ Packet packet;
+ packet.data = (uint8_t *)memalloc(p_data_size);
+ packet.size = p_data_size;
+ packet.source = p_source;
+ packet.destination = p_dest;
+ copymem(packet.data, &p_data[PROTO_SIZE], p_data_size);
+ _incoming_packets.push_back(packet);
+ emit_signal("peer_packet", p_source);
+}
+
+Error WebSocketMultiplayerPeer::_server_relay(int32_t p_from, int32_t p_to, const uint8_t *p_buffer, uint32_t p_buffer_size) {
+ if (p_to == 1) {
+
+ return OK; // Will not send to self
+
+ } else if (p_to == 0) {
+
+ for (Map<int, Ref<WebSocketPeer> >::Element *E = _peer_map.front(); E; E = E->next()) {
+ if (E->key() != p_from)
+ E->get()->put_packet(p_buffer, p_buffer_size);
+ }
+ return OK; // Sent to all but sender
+
+ } else if (p_to < 0) {
+
+ for (Map<int, Ref<WebSocketPeer> >::Element *E = _peer_map.front(); E; E = E->next()) {
+ if (E->key() != p_from && E->key() != -p_to)
+ E->get()->put_packet(p_buffer, p_buffer_size);
+ }
+ return OK; // Sent to all but sender and excluded
+
+ } else {
+
+ ERR_FAIL_COND_V(p_to == p_from, FAILED);
+
+ return get_peer(p_to)->put_packet(p_buffer, p_buffer_size); // Sending to specific peer
+ }
+}
+
+void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, uint32_t p_peer_id) {
+
+ ERR_FAIL_COND(!p_peer.is_valid());
+
+ const uint8_t *in_buffer;
+ int size = 0;
+ int data_size = 0;
+
+ Error err = p_peer->get_packet(&in_buffer, size);
+
+ ERR_FAIL_COND(err != OK);
+ ERR_FAIL_COND(size < PROTO_SIZE);
+
+ data_size = size - PROTO_SIZE;
+
+ uint8_t type = 0;
+ int32_t from = 0;
+ int32_t to = 0;
+ copymem(&type, in_buffer, 1);
+ copymem(&from, &in_buffer[1], 4);
+ copymem(&to, &in_buffer[5], 4);
+
+ if (is_server()) { // Server can resend
+
+ ERR_FAIL_COND(type != SYS_NONE); // Only server sends sys messages
+ ERR_FAIL_COND(from != p_peer_id); // Someone is cheating
+
+ _server_relay(from, to, in_buffer, size); // Relay if needed
+
+ if (to == 1) { // This is for the server
+
+ _store_pkt(from, to, in_buffer, data_size);
+
+ } else if (to == 0) {
+
+ // Broadcast, for us too
+ _store_pkt(from, to, in_buffer, data_size);
+
+ } else if (to < 0) {
+
+ // All but one, for us if not excluded
+ if (_peer_id != -p_peer_id)
+ _store_pkt(from, to, in_buffer, data_size);
+
+ } else {
+
+ // Send to specific peer
+ ERR_FAIL_COND(!_peer_map.has(to));
+ get_peer(to)->put_packet(in_buffer, size);
+ }
+
+ } else {
+
+ if (type == SYS_NONE) { // Payload message
+
+ _store_pkt(from, to, in_buffer, data_size);
+ return;
+ }
+
+ // System message
+ ERR_FAIL_COND(data_size < 4);
+ int id = 0;
+ copymem(&id, &in_buffer[PROTO_SIZE], 4);
+
+ switch (type) {
+
+ case SYS_ADD: // Add peer
+ _peer_map[id] = Ref<WebSocketPeer>();
+ emit_signal("peer_connected", id);
+ if (id == 1) // We just connected to the server
+ emit_signal("connection_succeeded");
+ break;
+
+ case SYS_DEL: // Remove peer
+ _peer_map.erase(id);
+ emit_signal("peer_disconnected", id);
+ break;
+ case SYS_ID: // Helo, server assigned ID
+ _peer_id = id;
+ break;
+ default:
+ ERR_EXPLAIN("Invalid multiplayer message");
+ ERR_FAIL();
+ break;
+ }
+ }
+}
diff --git a/modules/websocket/websocket_multiplayer.h b/modules/websocket/websocket_multiplayer.h
new file mode 100644
index 0000000000..e8e795e97f
--- /dev/null
+++ b/modules/websocket/websocket_multiplayer.h
@@ -0,0 +1,110 @@
+/*************************************************************************/
+/* websocket_multiplayer.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 WEBSOCKET_MULTIPLAYER_PEER_H
+#define WEBSOCKET_MULTIPLAYER_PEER_H
+
+#include "core/error_list.h"
+#include "core/io/networked_multiplayer_peer.h"
+#include "core/list.h"
+#include "websocket_peer.h"
+
+class WebSocketMultiplayerPeer : public NetworkedMultiplayerPeer {
+
+ GDCLASS(WebSocketMultiplayerPeer, NetworkedMultiplayerPeer);
+
+private:
+ PoolVector<uint8_t> _make_pkt(uint32_t p_type, int32_t p_from, int32_t p_to, const uint8_t *p_data, uint32_t p_data_size);
+ void _store_pkt(int32_t p_source, int32_t p_dest, const uint8_t *p_data, uint32_t p_data_size);
+ Error _server_relay(int32_t p_from, int32_t p_to, const uint8_t *p_buffer, uint32_t p_buffer_size);
+
+protected:
+ enum {
+ SYS_NONE = 0,
+ SYS_ADD = 1,
+ SYS_DEL = 2,
+ SYS_ID = 3,
+
+ PROTO_SIZE = 9,
+ SYS_PACKET_SIZE = 13,
+ MAX_PACKET_SIZE = 65536 - 14 // 5 websocket, 9 multiplayer
+ };
+
+ struct Packet {
+ int source;
+ int destination;
+ uint8_t *data;
+ uint32_t size;
+ };
+
+ List<Packet> _incoming_packets;
+ Map<int, Ref<WebSocketPeer> > _peer_map;
+ Packet _current_packet;
+
+ bool _is_multiplayer;
+ int _target_peer;
+ int _peer_id;
+ int _refusing;
+
+ static void _bind_methods();
+
+ void _send_add(int32_t p_peer_id);
+ void _send_sys(Ref<WebSocketPeer> p_peer, uint8_t p_type, int32_t p_peer_id);
+ void _send_del(int32_t p_peer_id);
+ int _gen_unique_id() const;
+
+public:
+ /* NetworkedMultiplayerPeer */
+ void set_transfer_mode(TransferMode p_mode);
+ TransferMode get_transfer_mode() const;
+ void set_target_peer(int p_peer_id);
+ int get_packet_peer() const;
+ int get_unique_id() const;
+ virtual bool is_server() const = 0;
+ void set_refuse_new_connections(bool p_enable);
+ bool is_refusing_new_connections() const;
+ virtual ConnectionStatus get_connection_status() const = 0;
+
+ /* PacketPeer */
+ virtual int get_available_packet_count() const;
+ virtual int get_max_packet_size() 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);
+
+ /* WebSocketPeer */
+ virtual Ref<WebSocketPeer> get_peer(int p_peer_id) const = 0;
+
+ void _process_multiplayer(Ref<WebSocketPeer> p_peer, uint32_t p_peer_id);
+ void _clear();
+
+ WebSocketMultiplayerPeer();
+ ~WebSocketMultiplayerPeer();
+};
+
+#endif // WEBSOCKET_MULTIPLAYER_PEER_H
diff --git a/modules/websocket/websocket_peer.cpp b/modules/websocket/websocket_peer.cpp
new file mode 100644
index 0000000000..a6fbb4481b
--- /dev/null
+++ b/modules/websocket/websocket_peer.cpp
@@ -0,0 +1,49 @@
+/*************************************************************************/
+/* websocket_peer.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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. */
+/*************************************************************************/
+#include "websocket_peer.h"
+
+GDCINULL(WebSocketPeer);
+
+WebSocketPeer::WebSocketPeer() {
+}
+
+WebSocketPeer::~WebSocketPeer() {
+}
+
+void WebSocketPeer::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_write_mode"), &WebSocketPeer::get_write_mode);
+ ClassDB::bind_method(D_METHOD("set_write_mode", "mode"), &WebSocketPeer::set_write_mode);
+ ClassDB::bind_method(D_METHOD("is_connected_to_host"), &WebSocketPeer::is_connected_to_host);
+ ClassDB::bind_method(D_METHOD("was_string_packet"), &WebSocketPeer::was_string_packet);
+ ClassDB::bind_method(D_METHOD("close"), &WebSocketPeer::close);
+
+ BIND_ENUM_CONSTANT(WRITE_MODE_TEXT);
+ BIND_ENUM_CONSTANT(WRITE_MODE_BINARY);
+}
diff --git a/modules/websocket/websocket_peer.h b/modules/websocket/websocket_peer.h
new file mode 100644
index 0000000000..f4d8ce3e38
--- /dev/null
+++ b/modules/websocket/websocket_peer.h
@@ -0,0 +1,73 @@
+/*************************************************************************/
+/* websocket_peer.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 WEBSOCKETPEER_H
+#define WEBSOCKETPEER_H
+
+#include "core/error_list.h"
+#include "core/io/packet_peer.h"
+#include "core/ring_buffer.h"
+#include "websocket_macros.h"
+
+class WebSocketPeer : public PacketPeer {
+
+ GDCLASS(WebSocketPeer, PacketPeer);
+ GDCICLASS(WebSocketPeer);
+
+public:
+ enum WriteMode {
+ WRITE_MODE_TEXT,
+ WRITE_MODE_BINARY,
+ };
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual int get_available_packet_count() const = 0;
+ virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) = 0;
+ virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) = 0;
+ virtual int get_max_packet_size() const = 0;
+
+ virtual WriteMode get_write_mode() const = 0;
+ virtual void set_write_mode(WriteMode p_mode) = 0;
+
+ virtual void close() = 0;
+
+ virtual bool is_connected_to_host() const = 0;
+ virtual IP_Address get_connected_host() const = 0;
+ virtual uint16_t get_connected_port() const = 0;
+ virtual bool was_string_packet() const = 0;
+
+ WebSocketPeer();
+ ~WebSocketPeer();
+};
+
+VARIANT_ENUM_CAST(WebSocketPeer::WriteMode);
+#endif // WEBSOCKETPEER_H
diff --git a/modules/websocket/websocket_server.cpp b/modules/websocket/websocket_server.cpp
new file mode 100644
index 0000000000..ba77019f55
--- /dev/null
+++ b/modules/websocket/websocket_server.cpp
@@ -0,0 +1,94 @@
+/*************************************************************************/
+/* websocket_server.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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. */
+/*************************************************************************/
+#include "websocket_server.h"
+
+GDCINULL(WebSocketServer);
+
+WebSocketServer::WebSocketServer() {
+ _peer_id = 1;
+}
+
+WebSocketServer::~WebSocketServer() {
+}
+
+void WebSocketServer::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("is_listening"), &WebSocketServer::is_listening);
+ ClassDB::bind_method(D_METHOD("listen", "port", "protocols", "gd_mp_api"), &WebSocketServer::listen, DEFVAL(PoolVector<String>()), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("stop"), &WebSocketServer::stop);
+ ClassDB::bind_method(D_METHOD("has_peer", "id"), &WebSocketServer::has_peer);
+
+ ADD_SIGNAL(MethodInfo("client_disconnected", PropertyInfo(Variant::INT, "id")));
+ ADD_SIGNAL(MethodInfo("client_connected", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "protocol")));
+ ADD_SIGNAL(MethodInfo("data_received", PropertyInfo(Variant::INT, "id")));
+}
+
+NetworkedMultiplayerPeer::ConnectionStatus WebSocketServer::get_connection_status() const {
+ if (is_listening())
+ return CONNECTION_CONNECTED;
+
+ return CONNECTION_DISCONNECTED;
+};
+
+bool WebSocketServer::is_server() const {
+
+ return true;
+}
+
+void WebSocketServer::_on_peer_packet(int32_t p_peer_id) {
+
+ if (_is_multiplayer) {
+ _process_multiplayer(get_peer(p_peer_id), p_peer_id);
+ } else {
+ emit_signal("data_received", p_peer_id);
+ }
+}
+
+void WebSocketServer::_on_connect(int32_t p_peer_id, String p_protocol) {
+
+ if (_is_multiplayer) {
+ // Send add to clients
+ _send_add(p_peer_id);
+ emit_signal("peer_connected", p_peer_id);
+ } else {
+ emit_signal("client_connected", p_peer_id, p_protocol);
+ }
+}
+
+void WebSocketServer::_on_disconnect(int32_t p_peer_id) {
+
+ if (_is_multiplayer) {
+ // Send delete to clients
+ _send_del(p_peer_id);
+ emit_signal("peer_disconnected", p_peer_id);
+ } else {
+ emit_signal("client_disconnected", p_peer_id);
+ }
+}
diff --git a/modules/websocket/websocket_server.h b/modules/websocket/websocket_server.h
new file mode 100644
index 0000000000..db188811fd
--- /dev/null
+++ b/modules/websocket/websocket_server.h
@@ -0,0 +1,63 @@
+/*************************************************************************/
+/* websocket_server.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 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 WEBSOCKET_H
+#define WEBSOCKET_H
+
+#include "core/reference.h"
+#include "websocket_multiplayer.h"
+#include "websocket_peer.h"
+
+class WebSocketServer : public WebSocketMultiplayerPeer {
+
+ GDCLASS(WebSocketServer, WebSocketMultiplayerPeer);
+ GDCICLASS(WebSocketServer);
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual void poll() = 0;
+ virtual Error listen(int p_port, PoolVector<String> p_protocols = PoolVector<String>(), bool gd_mp_api = false) = 0;
+ virtual void stop() = 0;
+ virtual bool is_listening() const = 0;
+ virtual bool has_peer(int p_id) const = 0;
+ virtual Ref<WebSocketPeer> get_peer(int p_id) const = 0;
+ virtual bool is_server() const;
+ ConnectionStatus get_connection_status() const;
+
+ void _on_peer_packet(int32_t p_peer_id);
+ void _on_connect(int32_t p_peer_id, String p_protocol);
+ void _on_disconnect(int32_t p_peer_id);
+
+ WebSocketServer();
+ ~WebSocketServer();
+};
+
+#endif // WEBSOCKET_H