summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/SCsub2
-rw-r--r--modules/arkit/SCsub10
-rw-r--r--modules/arkit/arkit_interface.h125
-rw-r--r--modules/arkit/arkit_interface.mm738
-rw-r--r--modules/arkit/arkit_session_delegate.h50
-rw-r--r--modules/arkit/arkit_session_delegate.mm56
-rw-r--r--modules/arkit/config.py5
-rw-r--r--modules/arkit/register_types.cpp45
-rw-r--r--modules/arkit/register_types.h32
-rw-r--r--modules/assimp/SCsub118
-rw-r--r--modules/assimp/editor_scene_importer_assimp.cpp32
-rw-r--r--modules/bullet/SCsub2
-rw-r--r--modules/bullet/rigid_body_bullet.cpp4
-rw-r--r--modules/csg/csg_gizmos.cpp14
-rw-r--r--modules/csg/doc_classes/CSGBox.xml8
-rw-r--r--modules/csg/doc_classes/CSGCylinder.xml12
-rw-r--r--modules/csg/doc_classes/CSGMesh.xml4
-rw-r--r--modules/csg/doc_classes/CSGPolygon.xml10
-rw-r--r--modules/csg/doc_classes/CSGPrimitive.xml2
-rw-r--r--modules/csg/doc_classes/CSGShape.xml12
-rw-r--r--modules/csg/doc_classes/CSGSphere.xml10
-rw-r--r--modules/csg/doc_classes/CSGTorus.xml12
-rw-r--r--modules/csg/icons/icon_c_s_g_box.svg6
-rw-r--r--modules/csg/icons/icon_c_s_g_capsule.svg6
-rw-r--r--modules/csg/icons/icon_c_s_g_combiner.svg8
-rw-r--r--modules/csg/icons/icon_c_s_g_cylinder.svg6
-rw-r--r--modules/csg/icons/icon_c_s_g_mesh.svg6
-rw-r--r--modules/csg/icons/icon_c_s_g_polygon.svg6
-rw-r--r--modules/csg/icons/icon_c_s_g_sphere.svg6
-rw-r--r--modules/csg/icons/icon_c_s_g_torus.svg6
-rw-r--r--modules/dds/texture_loader_dds.cpp2
-rw-r--r--modules/enet/SCsub2
-rw-r--r--modules/enet/doc_classes/NetworkedMultiplayerENet.xml12
-rw-r--r--modules/enet/networked_multiplayer_enet.cpp4
-rw-r--r--modules/freetype/SCsub8
-rw-r--r--modules/gdnative/arvr/arvr_interface_gdnative.cpp26
-rw-r--r--modules/gdnative/arvr/arvr_interface_gdnative.h2
-rw-r--r--modules/gdnative/doc_classes/GDNative.xml2
-rw-r--r--modules/gdnative/doc_classes/GDNativeLibrary.xml8
-rw-r--r--modules/gdnative/doc_classes/NativeScript.xml8
-rw-r--r--modules/gdnative/gdnative.cpp18
-rw-r--r--modules/gdnative/gdnative.h2
-rw-r--r--modules/gdnative/gdnative/array.cpp4
-rw-r--r--modules/gdnative/icons/icon_g_d_native_library.svg5
-rw-r--r--modules/gdnative/icons/icon_native_script.svg5
-rw-r--r--modules/gdnative/nativescript/SCsub1
-rw-r--r--modules/gdnative/net/multiplayer_peer_gdnative.cpp2
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.cpp7
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.h2
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.cpp18
-rw-r--r--modules/gdscript/gdscript.cpp2
-rw-r--r--modules/gdscript/gdscript.h2
-rw-r--r--modules/gdscript/gdscript_compiler.cpp2
-rw-r--r--modules/gdscript/gdscript_editor.cpp231
-rw-r--r--modules/gdscript/gdscript_function.cpp53
-rw-r--r--modules/gdscript/gdscript_parser.cpp57
-rw-r--r--modules/gdscript/gdscript_parser.h4
-rw-r--r--modules/gdscript/icons/icon_g_d_script.svg5
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml18
-rw-r--r--modules/gridmap/grid_map_editor_plugin.cpp2
-rw-r--r--modules/gridmap/icons/icon_grid_map.svg5
-rwxr-xr-xmodules/mbedtls/stream_peer_mbed_tls.cpp2
-rwxr-xr-xmodules/mbedtls/stream_peer_mbed_tls.h1
-rw-r--r--modules/mobile_vr/doc_classes/MobileVRInterface.xml14
-rw-r--r--modules/mono/build_scripts/make_android_mono_config.py69
-rw-r--r--modules/mono/build_scripts/make_cs_compressed_header.py21
-rw-r--r--modules/mono/build_scripts/mono_configure.py25
-rw-r--r--modules/mono/csharp_script.cpp15
-rw-r--r--modules/mono/editor/bindings_generator.cpp6
-rw-r--r--modules/mono/editor/godotsharp_editor.cpp15
-rw-r--r--modules/mono/editor/godotsharp_export.cpp13
-rw-r--r--modules/mono/glue/collections_glue.cpp8
-rw-r--r--modules/mono/godotsharp_dirs.cpp30
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp17
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp13
-rw-r--r--modules/mono/utils/android_utils.cpp68
-rw-r--r--modules/mono/utils/android_utils.h48
-rw-r--r--modules/opensimplex/doc_classes/NoiseTexture.xml12
-rw-r--r--modules/opensimplex/doc_classes/OpenSimplexNoise.xml10
-rw-r--r--modules/opensimplex/icons/icon_noise_texture.svg3
-rw-r--r--modules/opus/SCsub12
-rw-r--r--modules/regex/SCsub10
-rw-r--r--modules/regex/doc_classes/RegExMatch.xml8
-rw-r--r--modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml6
-rw-r--r--modules/svg/SCsub2
-rw-r--r--modules/theora/SCsub2
-rw-r--r--modules/upnp/SCsub5
-rw-r--r--modules/upnp/doc_classes/UPNP.xml6
-rw-r--r--modules/upnp/doc_classes/UPNPDevice.xml12
-rw-r--r--modules/vhacd/SCsub21
-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.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptComment.xml6
-rw-r--r--modules/visual_script/doc_classes/VisualScriptConstant.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptDeconstruct.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/VisualScriptFunctionCall.xml10
-rw-r--r--modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptInputAction.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptLocalVar.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptMathConstant.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptOperator.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPreload.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPropertyGet.xml6
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPropertySet.xml8
-rw-r--r--modules/visual_script/doc_classes/VisualScriptResourcePath.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptReturn.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSceneNode.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSelect.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSequence.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptTypeCast.xml4
-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/VisualScriptYield.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptYieldSignal.xml6
-rw-r--r--modules/visual_script/icons/icon_visual_script.svg6
-rw-r--r--modules/visual_script/visual_script_editor.cpp4
-rw-r--r--modules/webm/libvpx/SCsub4
-rw-r--r--modules/webrtc/doc_classes/WebRTCDataChannel.xml2
-rw-r--r--modules/webrtc/webrtc_data_channel_gdnative.cpp1
-rw-r--r--modules/websocket/SCsub105
-rw-r--r--modules/websocket/doc_classes/WebSocketClient.xml2
-rw-r--r--modules/websocket/doc_classes/WebSocketServer.xml2
-rw-r--r--modules/websocket/lws_client.cpp248
-rw-r--r--modules/websocket/lws_helper.cpp157
-rw-r--r--modules/websocket/lws_helper.h111
-rw-r--r--modules/websocket/lws_peer.cpp270
-rw-r--r--modules/websocket/lws_server.cpp225
-rw-r--r--modules/websocket/register_types.cpp11
-rw-r--r--modules/websocket/wsl_client.cpp362
-rw-r--r--modules/websocket/wsl_client.h (renamed from modules/websocket/lws_client.h)44
-rw-r--r--modules/websocket/wsl_peer.cpp339
-rw-r--r--modules/websocket/wsl_peer.h (renamed from modules/websocket/lws_peer.h)72
-rw-r--r--modules/websocket/wsl_server.cpp281
-rw-r--r--modules/websocket/wsl_server.h (renamed from modules/websocket/lws_server.h)52
138 files changed, 3107 insertions, 1633 deletions
diff --git a/modules/SCsub b/modules/SCsub
index 67f5893db4..36c2472c42 100644
--- a/modules/SCsub
+++ b/modules/SCsub
@@ -13,7 +13,7 @@ env.modules_sources = [
for x in env.module_list:
if (x in env.disabled_modules):
continue
- env_modules.Append(CPPFLAGS=["-DMODULE_" + x.upper() + "_ENABLED"])
+ env_modules.Append(CPPDEFINES=["MODULE_" + x.upper() + "_ENABLED"])
SConscript(x + "/SCsub")
if env.split_modules:
diff --git a/modules/arkit/SCsub b/modules/arkit/SCsub
new file mode 100644
index 0000000000..b43d936768
--- /dev/null
+++ b/modules/arkit/SCsub
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+Import('env')
+Import('env_modules')
+
+env_arkit = env_modules.Clone()
+
+# Add source files
+env_arkit.add_source_files(env.modules_sources, "*.cpp")
+env_arkit.add_source_files(env.modules_sources, "*.mm")
diff --git a/modules/arkit/arkit_interface.h b/modules/arkit/arkit_interface.h
new file mode 100644
index 0000000000..8129611287
--- /dev/null
+++ b/modules/arkit/arkit_interface.h
@@ -0,0 +1,125 @@
+/*************************************************************************/
+/* arkit_interface.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.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 ARKIT_INTERFACE_H
+#define ARKIT_INTERFACE_H
+
+#include "servers/arvr/arvr_interface.h"
+#include "servers/arvr/arvr_positional_tracker.h"
+#include "servers/camera/camera_feed.h"
+
+/**
+ @author Bastiaan Olij <mux213@gmail.com>
+
+ ARKit interface between iPhone and Godot
+*/
+
+// forward declaration for some needed objects
+class ARKitShader;
+
+class ARKitInterface : public ARVRInterface {
+ GDCLASS(ARKitInterface, ARVRInterface);
+
+private:
+ bool initialized;
+ bool session_was_started;
+ bool plane_detection_is_enabled;
+ bool light_estimation_is_enabled;
+ real_t ambient_intensity;
+ real_t ambient_color_temperature;
+
+ Transform transform;
+ CameraMatrix projection;
+ float eye_height, z_near, z_far;
+
+ Ref<CameraFeed> feed;
+ int image_width[2];
+ int image_height[2];
+ PoolVector<uint8_t> img_data[2];
+
+ struct anchor_map {
+ ARVRPositionalTracker *tracker;
+ unsigned char uuid[16];
+ };
+
+ ///@TODO should use memory map object from Godot?
+ unsigned int num_anchors;
+ unsigned int max_anchors;
+ anchor_map *anchors;
+ ARVRPositionalTracker *get_anchor_for_uuid(const unsigned char *p_uuid);
+ void remove_anchor_for_uuid(const unsigned char *p_uuid);
+ void remove_all_anchors();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void start_session();
+ void stop_session();
+
+ bool get_anchor_detection_is_enabled() const;
+ void set_anchor_detection_is_enabled(bool p_enable);
+ virtual int get_camera_feed_id();
+
+ bool get_light_estimation_is_enabled() const;
+ void set_light_estimation_is_enabled(bool p_enable);
+
+ real_t get_ambient_intensity() const;
+ real_t get_ambient_color_temperature() const;
+
+ /* while Godot has its own raycast logic this takes ARKits camera into account and hits on any ARAnchor */
+ Array raycast(Vector2 p_screen_coord);
+
+ void notification(int p_what);
+
+ virtual StringName get_name() const;
+ virtual int get_capabilities() const;
+
+ virtual bool is_initialized() const;
+ virtual bool initialize();
+ virtual void uninitialize();
+
+ virtual Size2 get_render_targetsize();
+ virtual bool is_stereo();
+ virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform);
+ virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far);
+ virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect);
+
+ virtual void process();
+
+ // called by delegate (void * because C++ and Obj-C don't always mix, should really change all platform/iphone/*.cpp files to .mm)
+ void _add_or_update_anchor(void *p_anchor);
+ void _remove_anchor(void *p_anchor);
+
+ ARKitInterface();
+ ~ARKitInterface();
+};
+
+#endif /* !ARKIT_INTERFACE_H */
diff --git a/modules/arkit/arkit_interface.mm b/modules/arkit/arkit_interface.mm
new file mode 100644
index 0000000000..de58f93276
--- /dev/null
+++ b/modules/arkit/arkit_interface.mm
@@ -0,0 +1,738 @@
+/*************************************************************************/
+/* arkit_interface.mm */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.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 "camera_ios.h"
+#include "core/os/input.h"
+#include "core/os/os.h"
+#include "scene/resources/surface_tool.h"
+#include "servers/visual/visual_server_globals.h"
+
+#import <ARKit/ARKit.h>
+#import <UIKit/UIKit.h>
+
+#include "arkit_interface.h"
+#include "arkit_session_delegate.h"
+
+// just a dirty workaround for now, declare these as globals. I'll probably encapsulate ARSession and associated logic into an mm object and change ARKitInterface to a normal cpp object that consumes it.
+ARSession *ar_session;
+ARKitSessionDelegate *ar_delegate;
+NSTimeInterval last_timestamp;
+
+/* this is called when we initialize or when we come back from having our app pushed to the background, just (re)start our session */
+void ARKitInterface::start_session() {
+ // We're active...
+ session_was_started = true;
+
+ // Ignore this if we're not initialized...
+ if (initialized) {
+ print_line("Starting ARKit session");
+ ARWorldTrackingConfiguration *configuration = [ARWorldTrackingConfiguration new];
+ configuration.lightEstimationEnabled = light_estimation_is_enabled;
+ if (plane_detection_is_enabled) {
+ configuration.planeDetection = ARPlaneDetectionVertical | ARPlaneDetectionHorizontal;
+ } else {
+ configuration.planeDetection = 0;
+ }
+
+ // make sure our camera is on
+ if (feed.is_valid()) {
+ feed->set_active(true);
+ }
+
+ [ar_session runWithConfiguration:configuration];
+ }
+}
+
+void ARKitInterface::stop_session() {
+ session_was_started = false;
+
+ // Ignore this if we're not initialized...
+ if (initialized) {
+ // make sure our camera is off
+ if (feed.is_valid()) {
+ feed->set_active(false);
+ }
+
+ [ar_session pause];
+ }
+}
+
+void ARKitInterface::notification(int p_what) {
+ // TODO, this is not being called, need to find out why, possibly because this is not a node.
+ // in that case we need to find a way to get these notifications!
+ switch (p_what) {
+ case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
+ print_line("Focus in");
+
+ start_session();
+ }; break;
+ case MainLoop::NOTIFICATION_WM_FOCUS_OUT: {
+ print_line("Focus out");
+
+ stop_session();
+ }; break;
+ default:
+ break;
+ }
+}
+
+bool ARKitInterface::get_anchor_detection_is_enabled() const {
+ return plane_detection_is_enabled;
+}
+
+void ARKitInterface::set_anchor_detection_is_enabled(bool p_enable) {
+ if (plane_detection_is_enabled != p_enable) {
+ plane_detection_is_enabled = p_enable;
+
+ // Restart our session (this will be ignore if we're not initialised)
+ if (session_was_started) {
+ start_session();
+ }
+ }
+}
+
+int ARKitInterface::get_camera_feed_id() {
+ if (feed.is_null()) {
+ return 0;
+ } else {
+ return feed->get_id();
+ }
+}
+
+bool ARKitInterface::get_light_estimation_is_enabled() const {
+ return light_estimation_is_enabled;
+}
+
+void ARKitInterface::set_light_estimation_is_enabled(bool p_enable) {
+ if (light_estimation_is_enabled != p_enable) {
+ light_estimation_is_enabled = p_enable;
+
+ // Restart our session (this will be ignore if we're not initialised)
+ if (session_was_started) {
+ start_session();
+ }
+ }
+}
+
+real_t ARKitInterface::get_ambient_intensity() const {
+ return ambient_intensity;
+}
+
+real_t ARKitInterface::get_ambient_color_temperature() const {
+ return ambient_color_temperature;
+}
+
+StringName ARKitInterface::get_name() const {
+ return "ARKit";
+}
+
+int ARKitInterface::get_capabilities() const {
+ return ARKitInterface::ARVR_MONO + ARKitInterface::ARVR_AR;
+}
+
+Array ARKitInterface::raycast(Vector2 p_screen_coord) {
+ Array arr;
+ Size2 screen_size = OS::get_singleton()->get_window_size();
+ CGPoint point;
+ point.x = p_screen_coord.x / screen_size.x;
+ point.y = p_screen_coord.y / screen_size.y;
+
+ ///@TODO maybe give more options here, for now we're taking just ARAchors into account that were found during plane detection keeping their size into account
+ NSArray<ARHitTestResult *> *results = [ar_session.currentFrame hittest:point types:ARHitTestResultTypeExistingPlaneUsingExtent];
+
+ for (ARHitTestResult *result in results) {
+ Transform transform;
+
+ matrix_float4x4 m44 = result.worldTransform;
+ transform.basis.elements[0].x = m44.columns[0][0];
+ transform.basis.elements[1].x = m44.columns[0][1];
+ transform.basis.elements[2].x = m44.columns[0][2];
+ transform.basis.elements[0].y = m44.columns[1][0];
+ transform.basis.elements[1].y = m44.columns[1][1];
+ transform.basis.elements[2].y = m44.columns[1][2];
+ transform.basis.elements[0].z = m44.columns[2][0];
+ transform.basis.elements[1].z = m44.columns[2][1];
+ transform.basis.elements[2].z = m44.columns[2][2];
+ transform.origin.x = m44.columns[3][0];
+ transform.origin.y = m44.columns[3][1];
+ transform.origin.z = m44.columns[3][2];
+
+ /* important, NOT scaled to world_scale !! */
+ arr.push_back(transform);
+ }
+
+ return arr;
+}
+
+void ARKitInterface::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_notification", "what"), &ARKitInterface::_notification);
+
+ ClassDB::bind_method(D_METHOD("set_light_estimation_is_enabled", "enable"), &ARKitInterface::set_light_estimation_is_enabled);
+ ClassDB::bind_method(D_METHOD("get_light_estimation_is_enabled"), &ARKitInterface::get_light_estimation_is_enabled);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_estimation"), "set_light_estimation_is_enabled", "get_light_estimation_is_enabled");
+
+ ClassDB::bind_method(D_METHOD("get_ambient_intensity"), &ARKitInterface::get_ambient_intensity);
+ ClassDB::bind_method(D_METHOD("get_ambient_color_temperature"), &ARKitInterface::get_ambient_color_temperature);
+
+ ClassDB::bind_method(D_METHOD("raycast", "screen_coord"), &ARKitInterface::raycast);
+}
+
+bool ARKitInterface::is_stereo() {
+ // this is a mono device...
+ return false;
+}
+
+bool ARKitInterface::is_initialized() const {
+ return initialized;
+}
+
+bool ARKitInterface::initialize() {
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL_V(arvr_server, false);
+
+ if (!initialized) {
+ print_line("initializing ARKit");
+
+ // create our ar session and delegate
+ ar_session = [ARSession new];
+ ar_delegate = [ARKitSessionDelegate new];
+ ar_delegate.arkit_interface = this;
+ ar_session.delegate = ar_delegate;
+
+ // reset our transform
+ transform = Transform();
+
+ // make this our primary interface
+ arvr_server->set_primary_interface(this);
+
+ // make sure we have our feed setup
+ if (feed.is_null()) {
+ feed.instance();
+ feed->set_name("ARKit");
+
+ CameraServer *cs = CameraServer::get_singleton();
+ if (cs != NULL) {
+ cs->add_feed(feed);
+ }
+ }
+ feed->set_active(true);
+
+ // yeah!
+ initialized = true;
+
+ // Start our session...
+ start_session();
+ }
+
+ return true;
+}
+
+void ARKitInterface::uninitialize() {
+ if (initialized) {
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ if (arvr_server != NULL) {
+ // no longer our primary interface
+ arvr_server->clear_primary_interface_if(this);
+ }
+
+ if (feed.is_valid()) {
+ CameraServer *cs = CameraServer::get_singleton();
+ if ((cs != NULL)) {
+ cs->remove_feed(feed);
+ }
+ feed.unref();
+ }
+
+ remove_all_anchors();
+
+ [ar_session release];
+ [ar_delegate release];
+ ar_session = NULL;
+ ar_delegate = NULL;
+ initialized = false;
+ session_was_started = false;
+ }
+}
+
+Size2 ARKitInterface::get_render_targetsize() {
+ _THREAD_SAFE_METHOD_
+
+ Size2 target_size = OS::get_singleton()->get_window_size();
+
+ return target_size;
+}
+
+Transform ARKitInterface::get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) {
+ _THREAD_SAFE_METHOD_
+
+ Transform transform_for_eye;
+
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL_V(arvr_server, transform_for_eye);
+
+ if (initialized) {
+ float world_scale = arvr_server->get_world_scale();
+
+ // just scale our origin point of our transform, note that we really shouldn't be using world_scale in ARKit but....
+ transform_for_eye = transform;
+ transform_for_eye.origin *= world_scale;
+
+ transform_for_eye = p_cam_transform * arvr_server->get_reference_frame() * transform_for_eye;
+ } else {
+ // huh? well just return what we got....
+ transform_for_eye = p_cam_transform;
+ }
+
+ return transform_for_eye;
+}
+
+CameraMatrix ARKitInterface::get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
+ // Remember our near and far, it will be used in process when we obtain our projection from our ARKit session.
+ z_near = p_z_near;
+ z_far = p_z_far;
+
+ return projection;
+}
+
+void ARKitInterface::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
+ _THREAD_SAFE_METHOD_
+
+ // We must have a valid render target
+ ERR_FAIL_COND(!p_render_target.is_valid());
+
+ // Because we are rendering to our device we must use our main viewport!
+ ERR_FAIL_COND(p_screen_rect == Rect2());
+
+ // get the size of our screen
+ Rect2 screen_rect = p_screen_rect;
+
+ // screen_rect.position.x += screen_rect.size.x;
+ // screen_rect.size.x = -screen_rect.size.x;
+ // screen_rect.position.y += screen_rect.size.y;
+ // screen_rect.size.y = -screen_rect.size.y;
+
+ VSG::rasterizer->set_current_render_target(RID());
+ VSG::rasterizer->blit_render_target_to_screen(p_render_target, screen_rect, 0);
+}
+
+ARVRPositionalTracker *ARKitInterface::get_anchor_for_uuid(const unsigned char *p_uuid) {
+ if (anchors == NULL) {
+ num_anchors = 0;
+ max_anchors = 10;
+ anchors = (anchor_map *)malloc(sizeof(anchor_map) * max_anchors);
+ }
+
+ ERR_FAIL_NULL_V(anchors, NULL);
+
+ for (unsigned int i = 0; i < num_anchors; i++) {
+ if (memcmp(anchors[i].uuid, p_uuid, 16) == 0) {
+ return anchors[i].tracker;
+ }
+ }
+
+ if (num_anchors + 1 == max_anchors) {
+ max_anchors += 10;
+ anchors = (anchor_map *)realloc(anchors, sizeof(anchor_map) * max_anchors);
+ ERR_FAIL_NULL_V(anchors, NULL);
+ }
+
+ ARVRPositionalTracker *new_tracker = memnew(ARVRPositionalTracker);
+ new_tracker->set_type(ARVRServer::TRACKER_ANCHOR);
+
+ char tracker_name[256];
+ sprintf(tracker_name, "Anchor %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", p_uuid[0], p_uuid[1], p_uuid[2], p_uuid[3], p_uuid[4], p_uuid[5], p_uuid[6], p_uuid[7], p_uuid[8], p_uuid[9], p_uuid[10], p_uuid[11], p_uuid[12], p_uuid[13], p_uuid[14], p_uuid[15]);
+
+ String name = tracker_name;
+ print_line("Adding tracker " + name);
+ new_tracker->set_name(name);
+
+ // add our tracker
+ ARVRServer::get_singleton()->add_tracker(new_tracker);
+ anchors[num_anchors].tracker = new_tracker;
+ memcpy(anchors[num_anchors].uuid, p_uuid, 16);
+ num_anchors++;
+
+ return new_tracker;
+}
+
+void ARKitInterface::remove_anchor_for_uuid(const unsigned char *p_uuid) {
+ if (anchors != NULL) {
+ for (unsigned int i = 0; i < num_anchors; i++) {
+ if (memcmp(anchors[i].uuid, p_uuid, 16) == 0) {
+ // remove our tracker
+ ARVRServer::get_singleton()->remove_tracker(anchors[i].tracker);
+ memdelete(anchors[i].tracker);
+
+ // bring remaining forward
+ for (unsigned int j = i + 1; j < num_anchors; j++) {
+ anchors[j - 1] = anchors[j];
+ };
+
+ // decrease count
+ num_anchors--;
+ return;
+ }
+ }
+ }
+}
+
+void ARKitInterface::remove_all_anchors() {
+ if (anchors != NULL) {
+ for (unsigned int i = 0; i < num_anchors; i++) {
+ // remove our tracker
+ ARVRServer::get_singleton()->remove_tracker(anchors[i].tracker);
+ memdelete(anchors[i].tracker);
+ };
+
+ free(anchors);
+ anchors = NULL;
+ num_anchors = 0;
+ }
+}
+
+void ARKitInterface::process() {
+ _THREAD_SAFE_METHOD_
+
+ if (@available(iOS 11.0, *)) {
+ if (initialized) {
+ // get our next ARFrame
+ ARFrame *current_frame = ar_session.currentFrame;
+ if (last_timestamp != current_frame.timestamp) {
+ // only process if we have a new frame
+ last_timestamp = current_frame.timestamp;
+
+ // get some info about our screen and orientation
+ Size2 screen_size = OS::get_singleton()->get_window_size();
+ UIDeviceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
+
+ // Grab our camera image for our backbuffer
+ CVPixelBufferRef pixelBuffer = current_frame.capturedImage;
+ if ((CVPixelBufferGetPlaneCount(pixelBuffer) == 2) && (feed != NULL)) {
+ // Plane 0 is our Y and Plane 1 is our CbCr buffer
+
+ // ignored, we check each plane separately
+ // image_width = CVPixelBufferGetWidth(pixelBuffer);
+ // image_height = CVPixelBufferGetHeight(pixelBuffer);
+
+ // printf("Pixel buffer %i - %i\n", image_width, image_height);
+
+ CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
+
+ // get our buffers
+ unsigned char *dataY = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
+ unsigned char *dataCbCr = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
+
+ if (dataY == NULL) {
+ print_line("Couldn't access Y pixel buffer data");
+ } else if (dataCbCr == NULL) {
+ print_line("Couldn't access CbCr pixel buffer data");
+ } else {
+ Ref<Image> img[2];
+ size_t extraLeft, extraRight, extraTop, extraBottom;
+
+ CVPixelBufferGetExtendedPixels(pixelBuffer, &extraLeft, &extraRight, &extraTop, &extraBottom);
+
+ {
+ // do Y
+ int new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0);
+ int new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0);
+ int bytes_per_row = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0);
+
+ if ((image_width[0] != new_width) || (image_height[0] != new_height)) {
+ printf("- Camera padding l:%lu r:%lu t:%lu b:%lu\n", extraLeft, extraRight, extraTop, extraBottom);
+ printf("- Camera Y plane size: %i, %i - %i\n", new_width, new_height, bytes_per_row);
+
+ image_width[0] = new_width;
+ image_height[0] = new_height;
+ img_data[0].resize(new_width * new_height);
+ }
+
+ PoolVector<uint8_t>::Write w = img_data[0].write();
+ if (new_width == bytes_per_row) {
+ memcpy(w.ptr(), dataY, new_width * new_height);
+ } else {
+ int offset_a = 0;
+ int offset_b = extraLeft + (extraTop * bytes_per_row);
+ for (int r = 0; r < new_height; r++) {
+ memcpy(w.ptr() + offset_a, dataY + offset_b, new_width);
+ offset_a += new_width;
+ offset_b += bytes_per_row;
+ }
+ }
+
+ img[0].instance();
+ img[0]->create(new_width, new_height, 0, Image::FORMAT_R8, img_data[0]);
+ }
+
+ {
+ // do CbCr
+ int new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1);
+ int new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1);
+ int bytes_per_row = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0);
+
+ if ((image_width[1] != new_width) || (image_height[1] != new_height)) {
+ printf("- Camera CbCr plane size: %i, %i - %i\n", new_width, new_height, bytes_per_row);
+
+ image_width[1] = new_width;
+ image_height[1] = new_height;
+ img_data[1].resize(2 * new_width * new_height);
+ }
+
+ PoolVector<uint8_t>::Write w = img_data[1].write();
+ if ((2 * new_width) == bytes_per_row) {
+ memcpy(w.ptr(), dataCbCr, 2 * new_width * new_height);
+ } else {
+ int offset_a = 0;
+ int offset_b = extraLeft + (extraTop * bytes_per_row);
+ for (int r = 0; r < new_height; r++) {
+ memcpy(w.ptr() + offset_a, dataCbCr + offset_b, 2 * new_width);
+ offset_a += 2 * new_width;
+ offset_b += bytes_per_row;
+ }
+ }
+
+ img[1].instance();
+ img[1]->create(new_width, new_height, 0, Image::FORMAT_RG8, img_data[1]);
+ }
+
+ // set our texture...
+ feed->set_YCbCr_imgs(img[0], img[1]);
+
+ // now build our transform to display this as a background image that matches our camera
+ CGAffineTransform affine_transform = [current_frame displayTransformForOrientation:orientation viewportSize:CGSizeMake(screen_size.width, screen_size.height)];
+
+ // we need to invert this, probably row v.s. column notation
+ affine_transform = CGAffineTransformInvert(affine_transform);
+
+ if (orientation != UIDeviceOrientationPortrait) {
+ affine_transform.b = -affine_transform.b;
+ affine_transform.d = -affine_transform.d;
+ affine_transform.ty = 1.0 - affine_transform.ty;
+ } else {
+ affine_transform.c = -affine_transform.c;
+ affine_transform.a = -affine_transform.a;
+ affine_transform.tx = 1.0 - affine_transform.tx;
+ }
+
+ Transform2D display_transform = Transform2D(
+ affine_transform.a, affine_transform.b,
+ affine_transform.c, affine_transform.d,
+ affine_transform.tx, affine_transform.ty);
+
+ feed->set_transform(display_transform);
+ }
+
+ // and unlock
+ CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
+ }
+
+ // Record light estimation to apply to our scene
+ if (light_estimation_is_enabled) {
+ ambient_intensity = current_frame.lightEstimate.ambientIntensity;
+
+ ///@TODO it's there, but not there.. what to do with this...
+ // https://developer.apple.com/documentation/arkit/arlightestimate?language=objc
+ // ambient_color_temperature = current_frame.lightEstimate.ambientColorTemperature;
+ }
+
+ // Process our camera
+ ARCamera *camera = current_frame.camera;
+
+ // strangely enough we have to states, rolling them up into one
+ if (camera.trackingState == ARTrackingStateNotAvailable) {
+ // no tracking, would be good if we black out the screen or something...
+ tracking_state = ARVRInterface::ARVR_NOT_TRACKING;
+ } else {
+ if (camera.trackingState == ARTrackingStateNormal) {
+ tracking_state = ARVRInterface::ARVR_NORMAL_TRACKING;
+ } else if (camera.trackingStateReason == ARTrackingStateReasonExcessiveMotion) {
+ tracking_state = ARVRInterface::ARVR_EXCESSIVE_MOTION;
+ } else if (camera.trackingStateReason == ARTrackingStateReasonInsufficientFeatures) {
+ tracking_state = ARVRInterface::ARVR_INSUFFICIENT_FEATURES;
+ } else {
+ tracking_state = ARVRInterface::ARVR_UNKNOWN_TRACKING;
+ }
+
+ // copy our current frame transform
+ matrix_float4x4 m44 = camera.transform;
+ if (orientation == UIDeviceOrientationLandscapeLeft) {
+ transform.basis.elements[0].x = m44.columns[0][0];
+ transform.basis.elements[1].x = m44.columns[0][1];
+ transform.basis.elements[2].x = m44.columns[0][2];
+ transform.basis.elements[0].y = m44.columns[1][0];
+ transform.basis.elements[1].y = m44.columns[1][1];
+ transform.basis.elements[2].y = m44.columns[1][2];
+ } else if (orientation == UIDeviceOrientationPortrait) {
+ transform.basis.elements[0].x = m44.columns[1][0];
+ transform.basis.elements[1].x = m44.columns[1][1];
+ transform.basis.elements[2].x = m44.columns[1][2];
+ transform.basis.elements[0].y = -m44.columns[0][0];
+ transform.basis.elements[1].y = -m44.columns[0][1];
+ transform.basis.elements[2].y = -m44.columns[0][2];
+ } else if (orientation == UIDeviceOrientationLandscapeRight) {
+ transform.basis.elements[0].x = -m44.columns[0][0];
+ transform.basis.elements[1].x = -m44.columns[0][1];
+ transform.basis.elements[2].x = -m44.columns[0][2];
+ transform.basis.elements[0].y = -m44.columns[1][0];
+ transform.basis.elements[1].y = -m44.columns[1][1];
+ transform.basis.elements[2].y = -m44.columns[1][2];
+ } else if (orientation == UIDeviceOrientationPortraitUpsideDown) {
+ // this may not be correct
+ transform.basis.elements[0].x = m44.columns[1][0];
+ transform.basis.elements[1].x = m44.columns[1][1];
+ transform.basis.elements[2].x = m44.columns[1][2];
+ transform.basis.elements[0].y = m44.columns[0][0];
+ transform.basis.elements[1].y = m44.columns[0][1];
+ transform.basis.elements[2].y = m44.columns[0][2];
+ }
+ transform.basis.elements[0].z = m44.columns[2][0];
+ transform.basis.elements[1].z = m44.columns[2][1];
+ transform.basis.elements[2].z = m44.columns[2][2];
+ transform.origin.x = m44.columns[3][0];
+ transform.origin.y = m44.columns[3][1];
+ transform.origin.z = m44.columns[3][2];
+
+ // copy our current frame projection, investigate using projectionMatrixWithViewportSize:orientation:zNear:zFar: so we can set our own near and far
+ m44 = [camera projectionMatrixForOrientation:orientation viewportSize:CGSizeMake(screen_size.width, screen_size.height) zNear:z_near zFar:z_far];
+ projection.matrix[0][0] = m44.columns[0][0];
+ projection.matrix[1][0] = m44.columns[1][0];
+ projection.matrix[2][0] = m44.columns[2][0];
+ projection.matrix[3][0] = m44.columns[3][0];
+ projection.matrix[0][1] = m44.columns[0][1];
+ projection.matrix[1][1] = m44.columns[1][1];
+ projection.matrix[2][1] = m44.columns[2][1];
+ projection.matrix[3][1] = m44.columns[3][1];
+ projection.matrix[0][2] = m44.columns[0][2];
+ projection.matrix[1][2] = m44.columns[1][2];
+ projection.matrix[2][2] = m44.columns[2][2];
+ projection.matrix[3][2] = m44.columns[3][2];
+ projection.matrix[0][3] = m44.columns[0][3];
+ projection.matrix[1][3] = m44.columns[1][3];
+ projection.matrix[2][3] = m44.columns[2][3];
+ projection.matrix[3][3] = m44.columns[3][3];
+ }
+ }
+ }
+ }
+}
+
+void ARKitInterface::_add_or_update_anchor(void *p_anchor) {
+ _THREAD_SAFE_METHOD_
+
+ ARAnchor *anchor = (ARAnchor *)p_anchor;
+
+ unsigned char uuid[16];
+ [anchor.identifier getUUIDBytes:uuid];
+
+ ARVRPositionalTracker *tracker = get_anchor_for_uuid(uuid);
+ if (tracker != NULL) {
+ // lets update our mesh! (using Arjens code as is for now)
+ // we should also probably limit how often we do this...
+
+ // can we safely cast this?
+ ARPlaneAnchor *planeAnchor = (ARPlaneAnchor *)anchor;
+
+ if (planeAnchor.geometry.triangleCount > 0) {
+ Ref<SurfaceTool> surftool;
+ surftool.instance();
+ surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
+
+ for (int j = planeAnchor.geometry.triangleCount * 3 - 1; j >= 0; j--) {
+ int16_t index = planeAnchor.geometry.triangleIndices[j];
+ simd_float3 vrtx = planeAnchor.geometry.vertices[index];
+ simd_float2 textcoord = planeAnchor.geometry.textureCoordinates[index];
+ surftool->add_uv(Vector2(textcoord[0], textcoord[1]));
+ surftool->add_color(Color(0.8, 0.8, 0.8));
+ surftool->add_vertex(Vector3(vrtx[0], vrtx[1], vrtx[2]));
+ }
+
+ surftool->generate_normals();
+ tracker->set_mesh(surftool->commit());
+ } else {
+ Ref<Mesh> nomesh;
+ tracker->set_mesh(nomesh);
+ }
+
+ // Note, this also contains a scale factor which gives us an idea of the size of the anchor
+ // We may extract that in our ARVRAnchor class
+ Basis b;
+ matrix_float4x4 m44 = anchor.transform;
+ b.elements[0].x = m44.columns[0][0];
+ b.elements[1].x = m44.columns[0][1];
+ b.elements[2].x = m44.columns[0][2];
+ b.elements[0].y = m44.columns[1][0];
+ b.elements[1].y = m44.columns[1][1];
+ b.elements[2].y = m44.columns[1][2];
+ b.elements[0].z = m44.columns[2][0];
+ b.elements[1].z = m44.columns[2][1];
+ b.elements[2].z = m44.columns[2][2];
+ tracker->set_orientation(b);
+ tracker->set_rw_position(Vector3(m44.columns[3][0], m44.columns[3][1], m44.columns[3][2]));
+ }
+}
+
+void ARKitInterface::_remove_anchor(void *p_anchor) {
+ _THREAD_SAFE_METHOD_
+
+ ARAnchor *anchor = (ARAnchor *)p_anchor;
+
+ unsigned char uuid[16];
+ [anchor.identifier getUUIDBytes:uuid];
+
+ remove_anchor_for_uuid(uuid);
+}
+
+ARKitInterface::ARKitInterface() {
+ initialized = false;
+ session_was_started = false;
+ plane_detection_is_enabled = false;
+ light_estimation_is_enabled = false;
+ ar_session = NULL;
+ z_near = 0.01;
+ z_far = 1000.0;
+ projection.set_perspective(60.0, 1.0, z_near, z_far, false);
+ anchors = NULL;
+ num_anchors = 0;
+ ambient_intensity = 1.0;
+ ambient_color_temperature = 1.0;
+ image_width[0] = 0;
+ image_width[1] = 0;
+ image_height[0] = 0;
+ image_height[1] = 0;
+}
+
+ARKitInterface::~ARKitInterface() {
+ remove_all_anchors();
+
+ // and make sure we cleanup if we haven't already
+ if (is_initialized()) {
+ uninitialize();
+ }
+}
diff --git a/modules/arkit/arkit_session_delegate.h b/modules/arkit/arkit_session_delegate.h
new file mode 100644
index 0000000000..afe093656b
--- /dev/null
+++ b/modules/arkit/arkit_session_delegate.h
@@ -0,0 +1,50 @@
+/*************************************************************************/
+/* arkit_session_delegate.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.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 ARKIT_SESSION_DELEGATE_H
+#define ARKIT_SESSION_DELEGATE_H
+
+#import <ARKit/ARKit.h>
+#import <UIKit/UIKit.h>
+
+class ARKitInterface;
+
+@interface ARKitSessionDelegate : NSObject <ARSessionDelegate> {
+ ARKitInterface *arkit_interface;
+}
+
+@property(nonatomic) ARKitInterface *arkit_interface;
+
+- (void)session:(ARSession *)session didAddAnchors:(NSArray<ARAnchor *> *)anchors;
+- (void)session:(ARSession *)session didRemoveAnchors:(NSArray<ARAnchor *> *)anchors;
+- (void)session:(ARSession *)session didUpdateAnchors:(NSArray<ARAnchor *> *)anchors;
+@end
+
+#endif /* !ARKIT_SESSION_DELEGATE_H */
diff --git a/modules/arkit/arkit_session_delegate.mm b/modules/arkit/arkit_session_delegate.mm
new file mode 100644
index 0000000000..56485c987c
--- /dev/null
+++ b/modules/arkit/arkit_session_delegate.mm
@@ -0,0 +1,56 @@
+/*************************************************************************/
+/* arkit_session_delegate.mm */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.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 "arkit_session_delegate.h"
+#include "arkit_interface.h"
+
+@implementation ARKitSessionDelegate
+
+@synthesize arkit_interface;
+
+- (void)session:(ARSession *)session didAddAnchors:(NSArray<ARAnchor *> *)anchors {
+ for (ARAnchor *anchor in anchors) {
+ arkit_interface->_add_or_update_anchor(anchor);
+ }
+}
+
+- (void)session:(ARSession *)session didRemoveAnchors:(NSArray<ARAnchor *> *)anchors {
+ for (ARAnchor *anchor in anchors) {
+ arkit_interface->_remove_anchor(anchor);
+ }
+}
+
+- (void)session:(ARSession *)session didUpdateAnchors:(NSArray<ARAnchor *> *)anchors {
+ for (ARAnchor *anchor in anchors) {
+ arkit_interface->_add_or_update_anchor(anchor);
+ }
+}
+
+@end \ No newline at end of file
diff --git a/modules/arkit/config.py b/modules/arkit/config.py
new file mode 100644
index 0000000000..96e41826c5
--- /dev/null
+++ b/modules/arkit/config.py
@@ -0,0 +1,5 @@
+def can_build(env, platform):
+ return platform == 'iphone'
+
+def configure(env):
+ pass
diff --git a/modules/arkit/register_types.cpp b/modules/arkit/register_types.cpp
new file mode 100644
index 0000000000..af35828004
--- /dev/null
+++ b/modules/arkit/register_types.cpp
@@ -0,0 +1,45 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 "arkit_interface.h"
+
+void register_arkit_types() {
+ // does it make sense to register the class?
+
+ Ref<ARKitInterface> arkit_interface;
+ arkit_interface.instance();
+ ARVRServer::get_singleton()->add_interface(arkit_interface);
+}
+
+void unregister_arkit_types() {
+ // should clean itself up nicely :)
+}
diff --git a/modules/arkit/register_types.h b/modules/arkit/register_types.h
new file mode 100644
index 0000000000..6ed2065de2
--- /dev/null
+++ b/modules/arkit/register_types.h
@@ -0,0 +1,32 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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_arkit_types();
+void unregister_arkit_types();
diff --git a/modules/assimp/SCsub b/modules/assimp/SCsub
index 0da7e432e2..8a77e4f803 100644
--- a/modules/assimp/SCsub
+++ b/modules/assimp/SCsub
@@ -17,60 +17,60 @@ env_assimp.Prepend(CPPPATH=['#thirdparty/zlib/'])
env_assimp.Prepend(CPPPATH=['#thirdparty/assimp/contrib/openddlparser/include'])
env_assimp.Prepend(CPPPATH=['#thirdparty/assimp/contrib/rapidjson/include'])
env_assimp.Prepend(CPPPATH=['.'])
-#env_assimp.Append(CPPFLAGS=['-DASSIMP_DOUBLE_PRECISION']) # TODO default to what godot is compiled with for future double support
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_BOOST_WORKAROUND'])
-env_assimp.Append(CPPFLAGS=['-DOPENDDLPARSER_BUILD'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_OWN_ZLIB'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_EXPORT'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_X_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_AMF_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_3DS_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_MD3_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_MD5_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_MDL_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_MD2_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_PLY_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_ASE_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_OBJ_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_HMP_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_SMD_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_MDC_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_MD5_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_STL_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_LWO_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_DXF_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_NFF_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_RAW_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_SIB_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_OFF_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_AC_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_BVH_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_IRRMESH_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_IRR_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_Q3D_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_B3D_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_COLLADA_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_TERRAGEN_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_CSM_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_3D_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_LWS_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_OGRE_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_OPENGEX_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_MS3D_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_COB_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_BLEND_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_Q3BSP_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_NDO_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_STEP_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_IFC_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_XGL_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_ASSBIN_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_GLTF_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_C4D_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_3MF_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_X3D_IMPORTER'])
+#env_assimp.Append(CPPDEFINES=['ASSIMP_DOUBLE_PRECISION']) # TODO default to what godot is compiled with for future double support
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_BOOST_WORKAROUND'])
+env_assimp.Append(CPPDEFINES=['OPENDDLPARSER_BUILD'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_OWN_ZLIB'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_EXPORT'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_X_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_AMF_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_3DS_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_MD3_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_MD5_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_MDL_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_MD2_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_PLY_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_ASE_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_OBJ_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_HMP_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_SMD_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_MDC_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_MD5_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_STL_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_LWO_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_DXF_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_NFF_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_RAW_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_SIB_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_OFF_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_AC_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_BVH_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_IRRMESH_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_IRR_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_Q3D_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_B3D_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_COLLADA_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_TERRAGEN_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_CSM_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_3D_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_LWS_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_OGRE_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_OPENGEX_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_MS3D_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_COB_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_BLEND_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_Q3BSP_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_NDO_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_STEP_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_IFC_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_XGL_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_ASSBIN_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_GLTF_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_C4D_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_3MF_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_X3D_IMPORTER'])
-env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_SINGLETHREADED'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_SINGLETHREADED'])
if (not env.msvc):
env_assimp.Append(CXXFLAGS=['-std=c++11'])
@@ -78,14 +78,14 @@ elif (env.msvc == False and env['platform'] == 'windows'):
env_assimp.Append(LDFLAGS=['-pthread'])
if(env['platform'] == 'windows'):
- env_assimp.Append(CPPFLAGS=['-DPLATFORM_WINDOWS'])
- env_assimp.Append(CPPFLAGS=['-DPLATFORM=WINDOWS'])
+ env_assimp.Append(CPPDEFINES=['PLATFORM_WINDOWS'])
+ env_assimp.Append(CPPDEFINES=[('PLATFORM', 'WINDOWS')])
elif(env['platform'] == 'x11'):
- env_assimp.Append(CPPFLAGS=['-DPLATFORM_LINUX'])
- env_assimp.Append(CPPFLAGS=['-DPLATFORM=LINUX'])
+ env_assimp.Append(CPPDEFINES=['PLATFORM_LINUX'])
+ env_assimp.Append(CPPDEFINES=[('PLATFORM', 'LINUX')])
elif(env['platform'] == 'osx'):
- env_assimp.Append(CPPFLAGS=['-DPLATFORM_DARWIN'])
- env_assimp.Append(CPPFLAGS=['-DPLATFORM=DARWIN'])
+ env_assimp.Append(CPPDEFINES=['PLATFORM_DARWIN'])
+ env_assimp.Append(CPPDEFINES=[('PLATFORM', 'DARWIN')])
env_thirdparty = env_assimp.Clone()
env_thirdparty.disable_warnings()
diff --git a/modules/assimp/editor_scene_importer_assimp.cpp b/modules/assimp/editor_scene_importer_assimp.cpp
index 8c3c04674b..093e2f3006 100644
--- a/modules/assimp/editor_scene_importer_assimp.cpp
+++ b/modules/assimp/editor_scene_importer_assimp.cpp
@@ -848,7 +848,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta
if (AI_SUCCESS == ai_material->GetTexture(tex_normal, 0, &ai_filename, NULL, NULL, NULL, NULL, map_mode)) {
filename = _assimp_raw_string_to_string(ai_filename);
- String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/");
+ String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
bool found = false;
_find_texture_path(state.path, path, found);
if (found) {
@@ -869,7 +869,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta
if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_NORMAL_TEXTURE, ai_filename)) {
filename = _assimp_raw_string_to_string(ai_filename);
- String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/");
+ String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
bool found = false;
_find_texture_path(state.path, path, found);
if (found) {
@@ -892,7 +892,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta
if (AI_SUCCESS == ai_material->GetTexture(tex_emissive, 0, &ai_filename, NULL, NULL, NULL, NULL, map_mode)) {
filename = _assimp_raw_string_to_string(ai_filename);
- String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/");
+ String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
bool found = false;
_find_texture_path(state.path, path, found);
if (found) {
@@ -914,7 +914,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta
aiTextureMapMode map_mode[2];
if (AI_SUCCESS == ai_material->GetTexture(tex_albedo, 0, &ai_filename, NULL, NULL, NULL, NULL, map_mode)) {
filename = _assimp_raw_string_to_string(ai_filename);
- String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/");
+ String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
bool found = false;
_find_texture_path(state.path, path, found);
if (found) {
@@ -944,7 +944,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta
aiTextureMapMode map_mode[2];
if (AI_SUCCESS == ai_material->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE, &tex_gltf_base_color_path, NULL, NULL, NULL, NULL, map_mode)) {
String filename = _assimp_raw_string_to_string(tex_gltf_base_color_path);
- String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/");
+ String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
bool found = false;
_find_texture_path(state.path, path, found);
if (found) {
@@ -973,7 +973,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta
aiString tex_fbx_pbs_base_color_path = aiString();
if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_BASE_COLOR_TEXTURE, tex_fbx_pbs_base_color_path)) {
String filename = _assimp_raw_string_to_string(tex_fbx_pbs_base_color_path);
- String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/");
+ String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
bool found = false;
_find_texture_path(state.path, path, found);
if (found) {
@@ -1005,7 +1005,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta
aiString tex_fbx_pbs_normal_path = aiString();
if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_NORMAL_TEXTURE, tex_fbx_pbs_normal_path)) {
String filename = _assimp_raw_string_to_string(tex_fbx_pbs_normal_path);
- String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/");
+ String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
bool found = false;
_find_texture_path(state.path, path, found);
if (found) {
@@ -1027,7 +1027,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta
aiString tex_fbx_stingray_normal_path = aiString();
if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_NORMAL_TEXTURE, tex_fbx_stingray_normal_path)) {
String filename = _assimp_raw_string_to_string(tex_fbx_stingray_normal_path);
- String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/");
+ String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
bool found = false;
_find_texture_path(state.path, path, found);
if (found) {
@@ -1045,7 +1045,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta
aiString tex_fbx_pbs_base_color_path = aiString();
if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_COLOR_TEXTURE, tex_fbx_pbs_base_color_path)) {
String filename = _assimp_raw_string_to_string(tex_fbx_pbs_base_color_path);
- String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/");
+ String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
bool found = false;
_find_texture_path(state.path, path, found);
if (found) {
@@ -1077,7 +1077,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta
aiString tex_fbx_pbs_emissive_path = aiString();
if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_TEXTURE, tex_fbx_pbs_emissive_path)) {
String filename = _assimp_raw_string_to_string(tex_fbx_pbs_emissive_path);
- String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/");
+ String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
bool found = false;
_find_texture_path(state.path, path, found);
if (found) {
@@ -1107,7 +1107,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta
aiString tex_gltf_pbr_metallicroughness_path;
if (AI_SUCCESS == ai_material->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE, &tex_gltf_pbr_metallicroughness_path)) {
String filename = _assimp_raw_string_to_string(tex_gltf_pbr_metallicroughness_path);
- String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/");
+ String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
bool found = false;
_find_texture_path(state.path, path, found);
if (found) {
@@ -1134,7 +1134,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta
aiString tex_fbx_pbs_metallic_path;
if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_TEXTURE, tex_fbx_pbs_metallic_path)) {
String filename = _assimp_raw_string_to_string(tex_fbx_pbs_metallic_path);
- String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/");
+ String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
bool found = false;
_find_texture_path(state.path, path, found);
if (found) {
@@ -1154,7 +1154,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta
aiString tex_fbx_pbs_rough_path;
if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_TEXTURE, tex_fbx_pbs_rough_path)) {
String filename = _assimp_raw_string_to_string(tex_fbx_pbs_rough_path);
- String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/");
+ String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
bool found = false;
_find_texture_path(state.path, path, found);
if (found) {
@@ -1177,7 +1177,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta
aiString tex_fbx_pbs_metallic_path;
if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_METALNESS_TEXTURE, tex_fbx_pbs_metallic_path)) {
String filename = _assimp_raw_string_to_string(tex_fbx_pbs_metallic_path);
- String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/");
+ String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
bool found = false;
_find_texture_path(state.path, path, found);
if (found) {
@@ -1197,7 +1197,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta
aiString tex_fbx_pbs_rough_path;
if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_TEXTURE, tex_fbx_pbs_rough_path)) {
String filename = _assimp_raw_string_to_string(tex_fbx_pbs_rough_path);
- String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/");
+ String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
bool found = false;
_find_texture_path(state.path, path, found);
if (found) {
@@ -1684,7 +1684,7 @@ void EditorSceneImporterAssimp::_find_texture_path(const String &p_path, _Direct
path = name;
return;
}
- String name_ignore_sub_directory = p_path.get_base_dir() + "/" + path.get_file().get_basename() + extension;
+ String name_ignore_sub_directory = p_path.get_base_dir().plus_file(path.get_file().get_basename()) + extension;
if (dir.file_exists(name_ignore_sub_directory)) {
found = true;
path = name_ignore_sub_directory;
diff --git a/modules/bullet/SCsub b/modules/bullet/SCsub
index 2fe7a1b4c0..ecc8a9b481 100644
--- a/modules/bullet/SCsub
+++ b/modules/bullet/SCsub
@@ -192,7 +192,7 @@ if env['builtin_bullet']:
else:
env_bullet.Prepend(CPPPATH=[thirdparty_dir])
# if env['target'] == "debug" or env['target'] == "release_debug":
- # env_bullet.Append(CPPFLAGS=['-DBT_DEBUG'])
+ # env_bullet.Append(CPPDEFINES=['BT_DEBUG'])
env_thirdparty = env_bullet.Clone()
env_thirdparty.disable_warnings()
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index 733a900396..085cce9733 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -866,7 +866,7 @@ void RigidBodyBullet::on_enter_area(AreaBullet *p_area) {
if (p_area->is_spOv_gravityPoint()) {
++countGravityPointSpaces;
- assert(0 < countGravityPointSpaces);
+ ERR_FAIL_COND(countGravityPointSpaces <= 0);
}
}
@@ -888,7 +888,7 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) {
if (wasTheAreaFound) {
if (p_area->is_spOv_gravityPoint()) {
--countGravityPointSpaces;
- assert(0 <= countGravityPointSpaces);
+ ERR_FAIL_COND(countGravityPointSpaces < 0);
}
--areaWhereIamCount;
diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp
index d4069b901f..1e590c5cb4 100644
--- a/modules/csg/csg_gizmos.cpp
+++ b/modules/csg/csg_gizmos.cpp
@@ -120,6 +120,10 @@ void CSGShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_i
Vector3 ra, rb;
Geometry::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb);
float d = ra.x;
+ if (SpatialEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
+ }
+
if (d < 0.001)
d = 0.001;
@@ -135,6 +139,10 @@ void CSGShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_i
Vector3 ra, rb;
Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = ra[p_idx];
+ if (SpatialEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
+ }
+
if (d < 0.001)
d = 0.001;
@@ -154,6 +162,9 @@ void CSGShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_i
Vector3 ra, rb;
Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = axis.dot(ra);
+ if (SpatialEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
+ }
if (d < 0.001)
d = 0.001;
@@ -173,6 +184,9 @@ void CSGShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_i
Vector3 ra, rb;
Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = axis.dot(ra);
+ if (SpatialEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
+ }
if (d < 0.001)
d = 0.001;
diff --git a/modules/csg/doc_classes/CSGBox.xml b/modules/csg/doc_classes/CSGBox.xml
index e508468415..d100c01205 100644
--- a/modules/csg/doc_classes/CSGBox.xml
+++ b/modules/csg/doc_classes/CSGBox.xml
@@ -11,16 +11,16 @@
<methods>
</methods>
<members>
- <member name="depth" type="float" setter="set_depth" getter="get_depth">
+ <member name="depth" type="float" setter="set_depth" getter="get_depth" default="2.0">
Depth of the box measured from the center of the box.
</member>
- <member name="height" type="float" setter="set_height" getter="get_height">
+ <member name="height" type="float" setter="set_height" getter="get_height" default="2.0">
Height of the box measured from the center of the box.
</member>
- <member name="material" type="Material" setter="set_material" getter="get_material">
+ <member name="material" type="Material" setter="set_material" getter="get_material" default="null">
The material used to render the box.
</member>
- <member name="width" type="float" setter="set_width" getter="get_width">
+ <member name="width" type="float" setter="set_width" getter="get_width" default="2.0">
Width of the box measured from the center of the box.
</member>
</members>
diff --git a/modules/csg/doc_classes/CSGCylinder.xml b/modules/csg/doc_classes/CSGCylinder.xml
index 24c3f8ba2e..643eb7c7f4 100644
--- a/modules/csg/doc_classes/CSGCylinder.xml
+++ b/modules/csg/doc_classes/CSGCylinder.xml
@@ -11,22 +11,22 @@
<methods>
</methods>
<members>
- <member name="cone" type="bool" setter="set_cone" getter="is_cone">
+ <member name="cone" type="bool" setter="set_cone" getter="is_cone" default="false">
If [code]true[/code] a cone is created, the [member radius] will only apply to one side.
</member>
- <member name="height" type="float" setter="set_height" getter="get_height">
+ <member name="height" type="float" setter="set_height" getter="get_height" default="1.0">
The height of the cylinder.
</member>
- <member name="material" type="Material" setter="set_material" getter="get_material">
+ <member name="material" type="Material" setter="set_material" getter="get_material" default="null">
The material used to render the cylinder.
</member>
- <member name="radius" type="float" setter="set_radius" getter="get_radius">
+ <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
The radius of the cylinder.
</member>
- <member name="sides" type="int" setter="set_sides" getter="get_sides">
+ <member name="sides" type="int" setter="set_sides" getter="get_sides" default="8">
The number of sides of the cylinder, the higher this number the more detail there will be in the cylinder.
</member>
- <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces">
+ <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="true">
If [code]true[/code] the normals of the cylinder are set to give a smooth effect making the cylinder seem rounded. If [code]false[/code] the cylinder will have a flat shaded look.
</member>
</members>
diff --git a/modules/csg/doc_classes/CSGMesh.xml b/modules/csg/doc_classes/CSGMesh.xml
index afe0bc262d..daa08decb6 100644
--- a/modules/csg/doc_classes/CSGMesh.xml
+++ b/modules/csg/doc_classes/CSGMesh.xml
@@ -11,9 +11,9 @@
<methods>
</methods>
<members>
- <member name="material" type="Material" setter="set_material" getter="get_material">
+ <member name="material" type="Material" setter="set_material" getter="get_material" default="null">
</member>
- <member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh">
+ <member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh" default="null">
The mesh resource to use as a CSG shape.
</member>
</members>
diff --git a/modules/csg/doc_classes/CSGPolygon.xml b/modules/csg/doc_classes/CSGPolygon.xml
index 2c5d298222..48f5d730cc 100644
--- a/modules/csg/doc_classes/CSGPolygon.xml
+++ b/modules/csg/doc_classes/CSGPolygon.xml
@@ -11,13 +11,13 @@
<methods>
</methods>
<members>
- <member name="depth" type="float" setter="set_depth" getter="get_depth">
+ <member name="depth" type="float" setter="set_depth" getter="get_depth" default="1.0">
Extrusion depth when [member mode] is [constant MODE_DEPTH].
</member>
- <member name="material" type="Material" setter="set_material" getter="get_material">
+ <member name="material" type="Material" setter="set_material" getter="get_material" default="null">
Material to use for the resulting mesh.
</member>
- <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="CSGPolygon.Mode">
+ <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="CSGPolygon.Mode" default="0">
Extrusion mode.
</member>
<member name="path_continuous_u" type="bool" setter="set_path_continuous_u" getter="is_path_continuous_u">
@@ -38,10 +38,10 @@
<member name="path_rotation" type="int" setter="set_path_rotation" getter="get_path_rotation" enum="CSGPolygon.PathRotation">
The method by which each slice is rotated along the path when [member mode] is [constant MODE_PATH].
</member>
- <member name="polygon" type="PoolVector2Array" setter="set_polygon" getter="get_polygon">
+ <member name="polygon" type="PoolVector2Array" setter="set_polygon" getter="get_polygon" default="PoolVector2Array( 0, 0, 0, 1, 1, 1, 1, 0 )">
Point array that defines the shape that we'll extrude.
</member>
- <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces">
+ <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="false">
Generates smooth normals so smooth shading is applied to our mesh.
</member>
<member name="spin_degrees" type="float" setter="set_spin_degrees" getter="get_spin_degrees">
diff --git a/modules/csg/doc_classes/CSGPrimitive.xml b/modules/csg/doc_classes/CSGPrimitive.xml
index 869e4006fe..6c2f837637 100644
--- a/modules/csg/doc_classes/CSGPrimitive.xml
+++ b/modules/csg/doc_classes/CSGPrimitive.xml
@@ -10,7 +10,7 @@
<methods>
</methods>
<members>
- <member name="invert_faces" type="bool" setter="set_invert_faces" getter="is_inverting_faces">
+ <member name="invert_faces" type="bool" setter="set_invert_faces" getter="is_inverting_faces" default="false">
Invert the faces of the mesh.
</member>
</members>
diff --git a/modules/csg/doc_classes/CSGShape.xml b/modules/csg/doc_classes/CSGShape.xml
index 7fa7c78534..91f54f8246 100644
--- a/modules/csg/doc_classes/CSGShape.xml
+++ b/modules/csg/doc_classes/CSGShape.xml
@@ -64,23 +64,23 @@
</method>
</methods>
<members>
- <member name="calculate_tangents" type="bool" setter="set_calculate_tangents" getter="is_calculating_tangents">
+ <member name="calculate_tangents" type="bool" setter="set_calculate_tangents" getter="is_calculating_tangents" default="true">
Calculate tangents for the CSG shape which allows the use of normal maps. This is only applied on the root shape, this setting is ignored on any child.
</member>
- <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer">
+ <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
The physics layers this area is in.
Collidable objects can exist in any of 32 different layers. These layers work like a tagging system, and are not visual. A collidable can use these layers to select with which objects it can collide, using the collision_mask property.
A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A.
</member>
- <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask">
+ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
The physics layers this CSG shape scans for collisions.
</member>
- <member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape.Operation">
+ <member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape.Operation" default="0">
The operation that is performed on this shape. This is ignored for the first CSG child node as the operation is between this node and the previous child of this nodes parent.
</member>
- <member name="snap" type="float" setter="set_snap" getter="get_snap">
+ <member name="snap" type="float" setter="set_snap" getter="get_snap" default="0.001">
</member>
- <member name="use_collision" type="bool" setter="set_use_collision" getter="is_using_collision">
+ <member name="use_collision" type="bool" setter="set_use_collision" getter="is_using_collision" default="false">
Adds a collision shape to the physics engine for our CSG shape. This will always act like a static body. Note that the collision shape is still active even if the CSG shape itself is hidden.
</member>
</members>
diff --git a/modules/csg/doc_classes/CSGSphere.xml b/modules/csg/doc_classes/CSGSphere.xml
index 2a12cf84db..0a62644179 100644
--- a/modules/csg/doc_classes/CSGSphere.xml
+++ b/modules/csg/doc_classes/CSGSphere.xml
@@ -11,19 +11,19 @@
<methods>
</methods>
<members>
- <member name="material" type="Material" setter="set_material" getter="get_material">
+ <member name="material" type="Material" setter="set_material" getter="get_material" default="null">
The material used to render the sphere.
</member>
- <member name="radial_segments" type="int" setter="set_radial_segments" getter="get_radial_segments">
+ <member name="radial_segments" type="int" setter="set_radial_segments" getter="get_radial_segments" default="12">
Number of vertical slices for the sphere.
</member>
- <member name="radius" type="float" setter="set_radius" getter="get_radius">
+ <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
Radius of the sphere.
</member>
- <member name="rings" type="int" setter="set_rings" getter="get_rings">
+ <member name="rings" type="int" setter="set_rings" getter="get_rings" default="6">
Number of horizontal slices for the sphere.
</member>
- <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces">
+ <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="true">
If [code]true[/code] the normals of the sphere are set to give a smooth effect making the sphere seem rounded. If [code]false[/code] the sphere will have a flat shaded look.
</member>
</members>
diff --git a/modules/csg/doc_classes/CSGTorus.xml b/modules/csg/doc_classes/CSGTorus.xml
index 0d4437d87f..156fb185e7 100644
--- a/modules/csg/doc_classes/CSGTorus.xml
+++ b/modules/csg/doc_classes/CSGTorus.xml
@@ -11,22 +11,22 @@
<methods>
</methods>
<members>
- <member name="inner_radius" type="float" setter="set_inner_radius" getter="get_inner_radius">
+ <member name="inner_radius" type="float" setter="set_inner_radius" getter="get_inner_radius" default="2.0">
The inner radius of the torus.
</member>
- <member name="material" type="Material" setter="set_material" getter="get_material">
+ <member name="material" type="Material" setter="set_material" getter="get_material" default="null">
The material used to render the torus.
</member>
- <member name="outer_radius" type="float" setter="set_outer_radius" getter="get_outer_radius">
+ <member name="outer_radius" type="float" setter="set_outer_radius" getter="get_outer_radius" default="3.0">
The outer radius of the torus.
</member>
- <member name="ring_sides" type="int" setter="set_ring_sides" getter="get_ring_sides">
+ <member name="ring_sides" type="int" setter="set_ring_sides" getter="get_ring_sides" default="6">
The number of edges each ring of the torus is constructed of.
</member>
- <member name="sides" type="int" setter="set_sides" getter="get_sides">
+ <member name="sides" type="int" setter="set_sides" getter="get_sides" default="8">
The number of slices the torus is constructed of.
</member>
- <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces">
+ <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="true">
If [code]true[/code] the normals of the torus are set to give a smooth effect making the torus seem rounded. If [code]false[/code] the torus will have a flat shaded look.
</member>
</members>
diff --git a/modules/csg/icons/icon_c_s_g_box.svg b/modules/csg/icons/icon_c_s_g_box.svg
new file mode 100644
index 0000000000..67e34df444
--- /dev/null
+++ b/modules/csg/icons/icon_c_s_g_box.svg
@@ -0,0 +1,6 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<g transform="translate(0 -1036.4)">
+<path transform="translate(0 1036.4)" d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1h-2zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1v-1z" fill="#84c2ff"/>
+<path transform="translate(0 1036.4)" d="m8 0.94531-7 3.5v7.2227l7 3.5 0.29492-0.14844c-0.18282-0.30101-0.29492-0.64737-0.29492-1.0195v-2c0-0.72651 0.40824-1.3664 1-1.7168v-1.6699l4-2v1.3867h1c0.36419 0 0.70336 0.10754 1 0.2832v-3.8379zm0 2.1152 3.9395 1.9707-3.9395 1.9688-3.9395-1.9688zm-5 3.5527 4 2v3.9414l-4-2.002z" fill="#fc9c9c" stroke-width="1.0667"/>
+</g>
+</svg>
diff --git a/modules/csg/icons/icon_c_s_g_capsule.svg b/modules/csg/icons/icon_c_s_g_capsule.svg
new file mode 100644
index 0000000000..92a7b5a870
--- /dev/null
+++ b/modules/csg/icons/icon_c_s_g_capsule.svg
@@ -0,0 +1,6 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<g>
+<path d="m8 1c-2.7527 0-5 2.2418-5 4.9902v4.0176c0 2.7484 2.2473 4.9922 5 4.9922 0.092943 0 0.18367-0.008623 0.27539-0.013672-0.17055-0.29341-0.27539-0.62792-0.27539-0.98633v-2c0-0.72887 0.41095-1.3691 1.0059-1.7188v-0.28125c0.34771-0.034464 0.68259-0.10691 1.0156-0.19922 0.10394-0.99856 0.95603-1.8008 1.9785-1.8008h1v-2.0098c0-2.7484-2.2473-4.9902-5-4.9902zm-1.0059 2.127v4.8574c-0.66556-0.1047-1.2974-0.37231-1.9941-0.66211v-1.3223c0-1.3474 0.79841-2.4642 1.9941-2.873zm2.0117 0c1.1957 0.4088 1.9941 1.5256 1.9941 2.873v1.3457c-0.68406 0.3054-1.3142 0.57292-1.9941 0.66602v-4.8848zm-4.0059 6.334c0.67836 0.2231 1.3126 0.44599 1.9941 0.52539v2.8848c-1.1957-0.4092-1.9941-1.5237-1.9941-2.8711v-0.53906z" fill="#fc9c9c"/>
+<path d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1z" fill="#84c2ff"/>
+</g>
+</svg>
diff --git a/modules/csg/icons/icon_c_s_g_combiner.svg b/modules/csg/icons/icon_c_s_g_combiner.svg
new file mode 100644
index 0000000000..cce2902e24
--- /dev/null
+++ b/modules/csg/icons/icon_c_s_g_combiner.svg
@@ -0,0 +1,8 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<g transform="translate(0 -1036.4)">
+<path transform="translate(0 1036.4)" d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1h-2zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1v-1z" fill="#84c2ff"/>
+<g fill="#fc9c9c">
+<path transform="translate(0 1036.4)" d="m3 1c-1.1046 0-2 0.89543-2 2h2zm2 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2c0-1.1046-0.89543-2-2-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4v2h2v-2zm0 4c0 1.1046 0.89543 2 2 2v-2zm4 0v2h2v-2z" fill="#fc9c9c"/>
+</g>
+</g>
+</svg>
diff --git a/modules/csg/icons/icon_c_s_g_cylinder.svg b/modules/csg/icons/icon_c_s_g_cylinder.svg
new file mode 100644
index 0000000000..645a74c79b
--- /dev/null
+++ b/modules/csg/icons/icon_c_s_g_cylinder.svg
@@ -0,0 +1,6 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 14.999999 14.999999" xmlns="http://www.w3.org/2000/svg">
+<g>
+<path transform="scale(.9375)" d="m8 1c-1.7469 0-3.328 0.22648-4.5586 0.63672-0.61528 0.20512-1.1471 0.45187-1.5898 0.80078-0.44272 0.34891-0.85156 0.88101-0.85156 1.5625v8c0 0.68149 0.40884 1.2155 0.85156 1.5645 0.44272 0.34891 0.97457 0.59577 1.5898 0.80078 1.2306 0.41024 2.8117 0.63477 4.5586 0.63477 0.095648 0 0.18467-0.008426 0.2793-0.009766-0.1722-0.29446-0.2793-0.62995-0.2793-0.99023v-1c-1.5668 0-2.9867-0.2195-3.9277-0.5332-0.46329-0.15435-0.90474-0.33752-1.0723-0.4668v-5.8125c0.1468 0.058667 0.2835 0.12515 0.44141 0.17773 1.2306 0.41024 2.8117 0.63477 4.5586 0.63477s3.328-0.22453 4.5586-0.63477c0.15791-0.052267 0.29461-0.11864 0.44141-0.17773v1.8125h1c0.36396 0 0.70348 0.10774 1 0.2832v-4.2832c0-0.68149-0.40884-1.2136-0.85156-1.5625-0.44272-0.34891-0.97457-0.59566-1.5898-0.80078-1.2306-0.41024-2.8117-0.63672-4.5586-0.63672zm0 2c1.5668 0 2.9867 0.22145 3.9277 0.53516 0.46368 0.15456 0.80138 0.33741 0.96875 0.4668-0.16752 0.12928-0.50546 0.3105-0.96875 0.46484-0.94102 0.31371-2.361 0.5332-3.9277 0.5332s-2.9867-0.2195-3.9277-0.5332c-0.46329-0.15435-0.80123-0.33556-0.96875-0.46484 0.16737-0.12939 0.50507-0.31224 0.96875-0.4668 0.94102-0.31371 2.361-0.53516 3.9277-0.53516z" fill="#fc9c9c" stroke-width="1.0667"/>
+<path d="m11.25 8.4375c-0.51938 0-0.9375 0.41812-0.9375 0.9375v0.9375h1.875v1.875h0.9375c0.51938 0 0.9375-0.41812 0.9375-0.9375v-1.875c0-0.51938-0.41812-0.9375-0.9375-0.9375zm0.9375 3.75h-1.875v-1.875h-0.9375c-0.51938 0-0.9375 0.41812-0.9375 0.9375v1.875c0 0.51938 0.41812 0.9375 0.9375 0.9375h1.875c0.51938 0 0.9375-0.41812 0.9375-0.9375z" fill="#84c2ff"/>
+</g>
+</svg>
diff --git a/modules/csg/icons/icon_c_s_g_mesh.svg b/modules/csg/icons/icon_c_s_g_mesh.svg
new file mode 100644
index 0000000000..6e940a4aa5
--- /dev/null
+++ b/modules/csg/icons/icon_c_s_g_mesh.svg
@@ -0,0 +1,6 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<g>
+<path d="m3 1c-1.1046 0-2 0.89543-2 2 5.649e-4 0.71397 0.38169 1.3735 1 1.7305v6.541c-0.61771 0.35663-0.99874 1.0152-1 1.7285 0 1.1046 0.89543 2 2 2 0.71397-5.65e-4 1.3735-0.38169 1.7305-1h3.2695v-2h-3.2715c-0.17478-0.30301-0.42598-0.55488-0.72852-0.73047v-5.8555l4.916 4.916c0.31428-0.20669 0.68609-0.33008 1.084-0.33008 0-0.3979 0.12338-0.76971 0.33008-1.084l-4.916-4.916h5.8574c0.17478 0.30301 0.42598 0.55488 0.72852 0.73047v3.2695h2v-3.2715c0.61771-0.35663 0.99874-1.0152 1-1.7285 0-1.1046-0.89543-2-2-2-0.71397 5.648e-4 -1.3735 0.38169-1.7305 1h-6.541c-0.35663-0.61771-1.0152-0.99874-1.7285-1z" fill="#fc9c9c"/>
+<path d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1z" fill="#84c2ff"/>
+</g>
+</svg>
diff --git a/modules/csg/icons/icon_c_s_g_polygon.svg b/modules/csg/icons/icon_c_s_g_polygon.svg
new file mode 100644
index 0000000000..71b03cb8e6
--- /dev/null
+++ b/modules/csg/icons/icon_c_s_g_polygon.svg
@@ -0,0 +1,6 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<g transform="translate(0 -1036.4)">
+<path transform="translate(0 1036.4)" d="m7.9629 1.002c-0.14254 0.00487-0.28238 0.04016-0.41016 0.10352l-6 3c-0.33878 0.16944-0.55276 0.51574-0.55273 0.89453v5.832c-0.105 0.61631 0.37487 1.1768 1 1.168h5v2c2.16e-5 0.67546 0.64487 1.1297 1.2617 0.95898-0.16118-0.28721-0.26172-0.61135-0.26172-0.95898v-2c0-0.72673 0.40794-1.3664 1-1.7168v-1.666l4-2v1.3828h1c0.36397 0 0.70348 0.10774 1 0.2832v-3.2773c6e-6 -0.00195 6e-6 -0.0039094 0-0.0058594 2.6e-5 -0.37879-0.21395-0.72509-0.55273-0.89453l-6-3c-0.15022-0.074574-0.31679-0.11017-0.48438-0.10352zm0.037109 2.1172l3.7637 1.8809-2.7637 1.3809v-1.3809c-5.52e-5 -0.55226-0.44774-0.99994-1-1h-1.7617l1.7617-0.88086zm-5 2.8809h4v4h-4v-4z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#fc9c9c" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/>
+<path transform="translate(0 1036.4)" d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1h-2zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1v-1z" fill="#84c2ff"/>
+</g>
+</svg>
diff --git a/modules/csg/icons/icon_c_s_g_sphere.svg b/modules/csg/icons/icon_c_s_g_sphere.svg
new file mode 100644
index 0000000000..f81b566993
--- /dev/null
+++ b/modules/csg/icons/icon_c_s_g_sphere.svg
@@ -0,0 +1,6 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<g>
+<path d="m8 1c-3.8541 0-7 3.1459-7 7 0 3.8542 3.1459 7 7 7 0.093042 0 0.18321-0.01004 0.27539-0.013672-0.17055-0.29341-0.27539-0.62792-0.27539-0.98633v-2c0-0.72673 0.40794-1.3664 1-1.7168v-0.33398c0.34074-0.019259 0.67728-0.069097 1.0156-0.10547 0.083091-1.0187 0.94713-1.8438 1.9844-1.8438h2c0.35841 0 0.69292 0.10484 0.98633 0.27539 0.003633-0.092184 0.013672-0.18235 0.013672-0.27539 0-3.8541-3.1459-7-7-7zm-1 2.0977v4.8711c-1.2931-0.071342-2.6061-0.29819-3.9434-0.69141 0.30081-2.0978 1.8852-3.7665 3.9434-4.1797zm2 0c2.0549 0.41253 3.637 2.0767 3.9414 4.1699-1.3046 0.36677-2.6158 0.60259-3.9414 0.6875v-4.8574zm-5.7793 6.2988c1.2733 0.31892 2.5337 0.50215 3.7793 0.5625v2.9414c-1.8291-0.36719-3.266-1.7339-3.7793-3.5039z" fill="#fc9c9c"/>
+<path d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1z" fill="#84c2ff"/>
+</g>
+</svg>
diff --git a/modules/csg/icons/icon_c_s_g_torus.svg b/modules/csg/icons/icon_c_s_g_torus.svg
new file mode 100644
index 0000000000..3d30aa47b2
--- /dev/null
+++ b/modules/csg/icons/icon_c_s_g_torus.svg
@@ -0,0 +1,6 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<g transform="translate(0 -1036.4)">
+<path transform="translate(0 1036.4)" d="m8 3c-1.8145 0-3.4691 0.41721-4.7461 1.1621-1.277 0.745-2.2539 1.9082-2.2539 3.3379 0 1.4298 0.9769 2.5949 2.2539 3.3398 1.277 0.7449 2.9316 1.1602 4.7461 1.1602 0-1.0907 0.90931-2 2-2 0-0.080836 0.013744-0.15778 0.023438-0.23633-0.61769 0.14673-1.3008 0.23633-2.0234 0.23633-1.4992 0-2.8437-0.36687-3.7383-0.88867-0.89456-0.5219-1.2617-1.108-1.2617-1.6113 0-0.5032 0.36716-1.0876 1.2617-1.6094 0.89456-0.5219 2.2391-0.89062 3.7383-0.89062s2.8437 0.36872 3.7383 0.89062c0.89456 0.5218 1.2617 1.1062 1.2617 1.6094 0 0.15978-0.053679 0.32822-0.13281 0.5h1.1328c0.32481 0 0.62893 0.088408 0.90234 0.23047 0.057552-0.23582 0.097656-0.47718 0.097656-0.73047 0-1.4297-0.9769-2.5929-2.2539-3.3379-1.277-0.7449-2.9316-1.1621-4.7461-1.1621z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#fc9c9c" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/>
+<path transform="translate(0 1036.4)" d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1h-2zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1v-1z" fill="#84c2ff"/>
+</g>
+</svg>
diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp
index 50fdc8ab20..197b41b30c 100644
--- a/modules/dds/texture_loader_dds.cpp
+++ b/modules/dds/texture_loader_dds.cpp
@@ -31,7 +31,7 @@
#include "texture_loader_dds.h"
#include "core/os/file_access.h"
-#define PF_FOURCC(s) (((s)[3] << 24U) | ((s)[2] << 16U) | ((s)[1] << 8U) | ((s)[0]))
+#define PF_FOURCC(s) ((uint32_t)(((s)[3] << 24U) | ((s)[2] << 16U) | ((s)[1] << 8U) | ((s)[0])))
enum {
DDS_MAGIC = 0x20534444,
diff --git a/modules/enet/SCsub b/modules/enet/SCsub
index 78d8d43414..485c33b1a8 100644
--- a/modules/enet/SCsub
+++ b/modules/enet/SCsub
@@ -22,7 +22,7 @@ if env['builtin_enet']:
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_enet.Prepend(CPPPATH=[thirdparty_dir])
- env_enet.Append(CPPFLAGS=["-DGODOT_ENET"])
+ env_enet.Append(CPPDEFINES=["GODOT_ENET"])
env_thirdparty = env_enet.Clone()
env_thirdparty.disable_warnings()
diff --git a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
index 8a8511c008..84ed5fd9ee 100644
--- a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
+++ b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
@@ -106,16 +106,16 @@
</method>
</methods>
<members>
- <member name="always_ordered" type="bool" setter="set_always_ordered" getter="is_always_ordered">
+ <member name="always_ordered" type="bool" setter="set_always_ordered" getter="is_always_ordered" default="false">
Enforce ordered packets when using [constant NetworkedMultiplayerPeer.TRANSFER_MODE_UNRELIABLE] (thus behaving similarly to [constant NetworkedMultiplayerPeer.TRANSFER_MODE_UNRELIABLE_ORDERED]). This is the only way to use ordering with the RPC system.
</member>
- <member name="channel_count" type="int" setter="set_channel_count" getter="get_channel_count">
- The number of channels to be used by ENet. Default: [code]3[/code]. Channels are used to separate different kinds of data. In reliable or ordered mode, for example, the packet delivery order is ensured on a per channel basis.
+ <member name="channel_count" type="int" setter="set_channel_count" getter="get_channel_count" default="3">
+ The number of channels to be used by ENet. Channels are used to separate different kinds of data. In reliable or ordered mode, for example, the packet delivery order is ensured on a per channel basis.
</member>
- <member name="compression_mode" type="int" setter="set_compression_mode" getter="get_compression_mode" enum="NetworkedMultiplayerENet.CompressionMode">
- The compression method used for network packets. These have different tradeoffs of compression speed versus bandwidth, you may need to test which one works best for your use case if you use compression at all. Default value: [constant COMPRESS_NONE].
+ <member name="compression_mode" type="int" setter="set_compression_mode" getter="get_compression_mode" enum="NetworkedMultiplayerENet.CompressionMode" default="0">
+ The compression method used for network packets. These have different tradeoffs of compression speed versus bandwidth, you may need to test which one works best for your use case if you use compression at all.
</member>
- <member name="transfer_channel" type="int" setter="set_transfer_channel" getter="get_transfer_channel">
+ <member name="transfer_channel" type="int" setter="set_transfer_channel" getter="get_transfer_channel" default="-1">
Set the default channel to be used to transfer data. By default, this value is [code]-1[/code] which means that ENet will only use 2 channels, one for reliable and one for unreliable packets. Channel [code]0[/code] is reserved, and cannot be used. Setting this member to any value between [code]0[/code] and [member channel_count] (excluded) will force ENet to use that channel for sending data.
</member>
</members>
diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp
index dcb4b7fd75..a5a356ced2 100644
--- a/modules/enet/networked_multiplayer_enet.cpp
+++ b/modules/enet/networked_multiplayer_enet.cpp
@@ -882,7 +882,9 @@ NetworkedMultiplayerENet::NetworkedMultiplayerENet() {
NetworkedMultiplayerENet::~NetworkedMultiplayerENet() {
- close_connection();
+ if (active) {
+ close_connection();
+ }
}
// Sets IP for ENet to bind when using create_server or create_client
diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub
index 0ea581220e..b47377cbc4 100644
--- a/modules/freetype/SCsub
+++ b/modules/freetype/SCsub
@@ -65,16 +65,16 @@ if env['builtin_freetype']:
# Also needed in main env for scene/
env.Prepend(CPPPATH=[thirdparty_dir + "/include"])
- env_freetype.Append(CPPFLAGS=['-DFT2_BUILD_LIBRARY', '-DFT_CONFIG_OPTION_USE_PNG'])
+ env_freetype.Append(CPPDEFINES=['FT2_BUILD_LIBRARY', 'FT_CONFIG_OPTION_USE_PNG'])
if (env['target'] != 'release'):
- env_freetype.Append(CPPFLAGS=['-DZLIB_DEBUG'])
+ env_freetype.Append(CPPDEFINES=['ZLIB_DEBUG'])
# Also requires libpng headers
if env['builtin_libpng']:
env_freetype.Prepend(CPPPATH=["#thirdparty/libpng"])
sfnt = thirdparty_dir + 'src/sfnt/sfnt.c'
- # Must be done after all CPPFLAGS are being set so we can copy them.
+ # Must be done after all CPPDEFINES are being set so we can copy them.
if env['platform'] == 'javascript':
# Forcibly undefine this macro so SIMD is not used in this file,
# since currently unsupported in WASM
@@ -103,4 +103,4 @@ if env['builtin_freetype']:
# Godot source files
env_freetype.add_source_files(env.modules_sources, "*.cpp")
# Used in scene/, needs to be in main env
-env.Append(CPPFLAGS=['-DFREETYPE_ENABLED'])
+env.Append(CPPDEFINES=['FREETYPE_ENABLED'])
diff --git a/modules/gdnative/arvr/arvr_interface_gdnative.cpp b/modules/gdnative/arvr/arvr_interface_gdnative.cpp
index da01f573ce..64e2c362b2 100644
--- a/modules/gdnative/arvr/arvr_interface_gdnative.cpp
+++ b/modules/gdnative/arvr/arvr_interface_gdnative.cpp
@@ -33,9 +33,13 @@
#include "servers/arvr/arvr_positional_tracker.h"
#include "servers/visual/visual_server_globals.h"
+void ARVRInterfaceGDNative::_bind_methods() {
+ ADD_PROPERTY_DEFAULT("interface_is_initialized", false);
+ ADD_PROPERTY_DEFAULT("ar_is_anchor_detection_enabled", false);
+}
+
ARVRInterfaceGDNative::ARVRInterfaceGDNative() {
- // testing
- printf("Construct gdnative interface\n");
+ print_verbose("Construct gdnative interface\n");
// we won't have our data pointer until our library gets set
data = NULL;
@@ -44,9 +48,9 @@ ARVRInterfaceGDNative::ARVRInterfaceGDNative() {
}
ARVRInterfaceGDNative::~ARVRInterfaceGDNative() {
- printf("Destruct gdnative interface\n");
+ print_verbose("Destruct gdnative interface\n");
- if (is_initialized()) {
+ if (interface != NULL && is_initialized()) {
uninitialize();
};
@@ -99,13 +103,10 @@ int ARVRInterfaceGDNative::get_capabilities() const {
}
bool ARVRInterfaceGDNative::get_anchor_detection_is_enabled() const {
- bool enabled;
ERR_FAIL_COND_V(interface == NULL, false);
- enabled = interface->get_anchor_detection_is_enabled(data);
-
- return enabled;
+ return interface->get_anchor_detection_is_enabled(data);
}
void ARVRInterfaceGDNative::set_anchor_detection_is_enabled(bool p_enable) {
@@ -137,21 +138,16 @@ bool ARVRInterfaceGDNative::is_stereo() {
}
bool ARVRInterfaceGDNative::is_initialized() const {
- bool initialized;
ERR_FAIL_COND_V(interface == NULL, false);
- initialized = interface->is_initialized(data);
-
- return initialized;
+ return interface->is_initialized(data);
}
bool ARVRInterfaceGDNative::initialize() {
- bool initialized;
-
ERR_FAIL_COND_V(interface == NULL, false);
- initialized = interface->initialize(data);
+ bool initialized = interface->initialize(data);
if (initialized) {
// if we successfully initialize our interface and we don't have a primary interface yet, this becomes our primary interface
diff --git a/modules/gdnative/arvr/arvr_interface_gdnative.h b/modules/gdnative/arvr/arvr_interface_gdnative.h
index 651e5c8715..ab7090876a 100644
--- a/modules/gdnative/arvr/arvr_interface_gdnative.h
+++ b/modules/gdnative/arvr/arvr_interface_gdnative.h
@@ -49,6 +49,8 @@ protected:
const godot_arvr_interface_gdnative *interface;
void *data;
+ static void _bind_methods();
+
public:
/** general interface information **/
ARVRInterfaceGDNative();
diff --git a/modules/gdnative/doc_classes/GDNative.xml b/modules/gdnative/doc_classes/GDNative.xml
index 8750ddc56d..95ed1fc048 100644
--- a/modules/gdnative/doc_classes/GDNative.xml
+++ b/modules/gdnative/doc_classes/GDNative.xml
@@ -33,7 +33,7 @@
</method>
</methods>
<members>
- <member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library">
+ <member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library" default="null">
</member>
</members>
<constants>
diff --git a/modules/gdnative/doc_classes/GDNativeLibrary.xml b/modules/gdnative/doc_classes/GDNativeLibrary.xml
index 8bfd386b8d..7e1cac243a 100644
--- a/modules/gdnative/doc_classes/GDNativeLibrary.xml
+++ b/modules/gdnative/doc_classes/GDNativeLibrary.xml
@@ -23,13 +23,13 @@
<members>
<member name="config_file" type="ConfigFile" setter="set_config_file" getter="get_config_file">
</member>
- <member name="load_once" type="bool" setter="set_load_once" getter="should_load_once">
+ <member name="load_once" type="bool" setter="set_load_once" getter="should_load_once" default="true">
</member>
- <member name="reloadable" type="bool" setter="set_reloadable" getter="is_reloadable">
+ <member name="reloadable" type="bool" setter="set_reloadable" getter="is_reloadable" default="true">
</member>
- <member name="singleton" type="bool" setter="set_singleton" getter="is_singleton">
+ <member name="singleton" type="bool" setter="set_singleton" getter="is_singleton" default="false">
</member>
- <member name="symbol_prefix" type="String" setter="set_symbol_prefix" getter="get_symbol_prefix">
+ <member name="symbol_prefix" type="String" setter="set_symbol_prefix" getter="get_symbol_prefix" default="&quot;godot_&quot;">
</member>
</members>
<constants>
diff --git a/modules/gdnative/doc_classes/NativeScript.xml b/modules/gdnative/doc_classes/NativeScript.xml
index ac8b793b22..460471386d 100644
--- a/modules/gdnative/doc_classes/NativeScript.xml
+++ b/modules/gdnative/doc_classes/NativeScript.xml
@@ -51,13 +51,13 @@
</method>
</methods>
<members>
- <member name="class_name" type="String" setter="set_class_name" getter="get_class_name">
+ <member name="class_name" type="String" setter="set_class_name" getter="get_class_name" default="&quot;&quot;">
</member>
- <member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library">
+ <member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library" default="null">
</member>
- <member name="script_class_icon_path" type="String" setter="set_script_class_icon_path" getter="get_script_class_icon_path">
+ <member name="script_class_icon_path" type="String" setter="set_script_class_icon_path" getter="get_script_class_icon_path" default="&quot;&quot;">
</member>
- <member name="script_class_name" type="String" setter="set_script_class_name" getter="get_script_class_name">
+ <member name="script_class_name" type="String" setter="set_script_class_name" getter="get_script_class_name" default="&quot;&quot;">
</member>
</members>
<constants>
diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp
index a27935bfe2..4eb9a2a0a3 100644
--- a/modules/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative.cpp
@@ -48,7 +48,7 @@ static const bool default_reloadable = true;
// Defined in gdnative_api_struct.gen.cpp
extern const godot_gdnative_core_api_struct api_struct;
-Map<String, Vector<Ref<GDNative> > > *GDNativeLibrary::loaded_libraries = NULL;
+Map<String, Vector<Ref<GDNative> > > GDNativeLibrary::loaded_libraries;
GDNativeLibrary::GDNativeLibrary() {
config_file.instance();
@@ -57,10 +57,6 @@ GDNativeLibrary::GDNativeLibrary() {
load_once = default_load_once;
singleton = default_singleton;
reloadable = default_reloadable;
-
- if (GDNativeLibrary::loaded_libraries == NULL) {
- GDNativeLibrary::loaded_libraries = memnew((Map<String, Vector<Ref<GDNative> > >));
- }
}
GDNativeLibrary::~GDNativeLibrary() {
@@ -318,10 +314,10 @@ bool GDNative::initialize() {
#endif
if (library->should_load_once()) {
- if (GDNativeLibrary::loaded_libraries->has(lib_path)) {
+ if (GDNativeLibrary::loaded_libraries.has(lib_path)) {
// already loaded. Don't load again.
// copy some of the stuff instead
- this->native_handle = (*GDNativeLibrary::loaded_libraries)[lib_path][0]->native_handle;
+ this->native_handle = GDNativeLibrary::loaded_libraries[lib_path][0]->native_handle;
initialized = true;
return true;
}
@@ -377,11 +373,11 @@ bool GDNative::initialize() {
initialized = true;
- if (library->should_load_once() && !GDNativeLibrary::loaded_libraries->has(lib_path)) {
+ if (library->should_load_once() && !GDNativeLibrary::loaded_libraries.has(lib_path)) {
Vector<Ref<GDNative> > gdnatives;
gdnatives.resize(1);
gdnatives.write[0] = Ref<GDNative>(this);
- GDNativeLibrary::loaded_libraries->insert(lib_path, gdnatives);
+ GDNativeLibrary::loaded_libraries.insert(lib_path, gdnatives);
}
return true;
@@ -395,7 +391,7 @@ bool GDNative::terminate() {
}
if (library->should_load_once()) {
- Vector<Ref<GDNative> > *gdnatives = &(*GDNativeLibrary::loaded_libraries)[library->get_current_library_path()];
+ Vector<Ref<GDNative> > *gdnatives = &GDNativeLibrary::loaded_libraries[library->get_current_library_path()];
if (gdnatives->size() > 1) {
// there are other GDNative's still using this library, so we actually don't terminate
gdnatives->erase(Ref<GDNative>(this));
@@ -405,7 +401,7 @@ bool GDNative::terminate() {
// we're the last one, terminate!
gdnatives->clear();
// whew this looks scary, but all it does is remove the entry completely
- GDNativeLibrary::loaded_libraries->erase(GDNativeLibrary::loaded_libraries->find(library->get_current_library_path()));
+ GDNativeLibrary::loaded_libraries.erase(GDNativeLibrary::loaded_libraries.find(library->get_current_library_path()));
}
}
diff --git a/modules/gdnative/gdnative.h b/modules/gdnative/gdnative.h
index 005d1d2bff..408af26753 100644
--- a/modules/gdnative/gdnative.h
+++ b/modules/gdnative/gdnative.h
@@ -47,7 +47,7 @@ class GDNative;
class GDNativeLibrary : public Resource {
GDCLASS(GDNativeLibrary, Resource);
- static Map<String, Vector<Ref<GDNative> > > *loaded_libraries;
+ static Map<String, Vector<Ref<GDNative> > > loaded_libraries;
friend class GDNativeLibraryResourceLoader;
friend class GDNative;
diff --git a/modules/gdnative/gdnative/array.cpp b/modules/gdnative/gdnative/array.cpp
index 6849ff03d7..1ef8e9f900 100644
--- a/modules/gdnative/gdnative/array.cpp
+++ b/modules/gdnative/gdnative/array.cpp
@@ -305,13 +305,13 @@ void GDAPI godot_array_sort_custom(godot_array *p_self, godot_object *p_obj, con
godot_int GDAPI godot_array_bsearch(godot_array *p_self, const godot_variant *p_value, const godot_bool p_before) {
Array *self = (Array *)p_self;
- return self->bsearch((const Variant *)p_value, p_before);
+ return self->bsearch(*(const Variant *)p_value, p_before);
}
godot_int GDAPI godot_array_bsearch_custom(godot_array *p_self, const godot_variant *p_value, godot_object *p_obj, const godot_string *p_func, const godot_bool p_before) {
Array *self = (Array *)p_self;
const String *func = (const String *)p_func;
- return self->bsearch_custom((const Variant *)p_value, (Object *)p_obj, *func, p_before);
+ return self->bsearch_custom(*(const Variant *)p_value, (Object *)p_obj, *func, p_before);
}
void GDAPI godot_array_destroy(godot_array *p_self) {
diff --git a/modules/gdnative/icons/icon_g_d_native_library.svg b/modules/gdnative/icons/icon_g_d_native_library.svg
new file mode 100644
index 0000000000..b494c7af6e
--- /dev/null
+++ b/modules/gdnative/icons/icon_g_d_native_library.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<g transform="translate(0 -1036.4)">
+<path transform="translate(0 1036.4)" d="m7 1l-0.56445 2.2578a5 5 0 0 0 -0.68945 0.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -0.28516 0.68555l-2.2539 0.5625v2l2.2578 0.56445a5 5 0 0 0 0.2793 0.6875l-1.1934 1.9902 1.4141 1.4141 1.9941-1.1953a5 5 0 0 0 0.68555 0.28516l0.5625 2.2539v-5.2695a2 2 0 0 1 -1 -1.7305 2 2 0 0 1 1 -1.7285v-0.27148h1 4.5762a5 5 0 0 0 -0.11328 -0.25195l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -0.68555 -0.28516l-0.5625-2.2539h-2zm2 7v1 5 1h5c0.55228 0 1-0.4477 1-1v-5c0-0.5523-0.44772-1-1-1v4l-1-1-1 1v-4h-3z" fill="#e0e0e0"/>
+</g>
+</svg>
diff --git a/modules/gdnative/icons/icon_native_script.svg b/modules/gdnative/icons/icon_native_script.svg
new file mode 100644
index 0000000000..fb9e135627
--- /dev/null
+++ b/modules/gdnative/icons/icon_native_script.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<g transform="translate(0 -1036.4)">
+<path transform="translate(0 1036.4)" d="m7 1l-0.56445 2.2578a5 5 0 0 0 -0.68945 0.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -0.28516 0.68555l-2.2539 0.5625h3v1 1h2v-0.95117a2 2 0 0 1 0 -0.048828 2 2 0 0 1 2 -2 2 2 0 0 1 2 2v1h5v-2l-2.2578-0.56445a5 5 0 0 0 -0.2793 -0.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -0.68555 -0.28516l-0.5625-2.2539h-2zm-6 7v4 4h2a3 3 0 0 0 3 -3 3 3 0 0 0 -3 -3v-2h-2zm6 0v2h2v-2h-2zm3 2v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3 -3h-2zm-7 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1v-2zm4 0v4h2v-4h-2z" fill="#e0e0e0"/>
+</g>
+</svg>
diff --git a/modules/gdnative/nativescript/SCsub b/modules/gdnative/nativescript/SCsub
index 5841ad5531..92c9d6630d 100644
--- a/modules/gdnative/nativescript/SCsub
+++ b/modules/gdnative/nativescript/SCsub
@@ -4,7 +4,6 @@ Import('env')
Import('env_gdnative')
env_gdnative.add_source_files(env.modules_sources, '*.cpp')
-env_gdnative.Append(CPPFLAGS=['-DGDAPI_BUILT_IN'])
if "platform" in env and env["platform"] in ["x11", "iphone"]:
env.Append(LINKFLAGS=["-rdynamic"])
diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.cpp b/modules/gdnative/net/multiplayer_peer_gdnative.cpp
index bdeba149d2..d2c95efa77 100644
--- a/modules/gdnative/net/multiplayer_peer_gdnative.cpp
+++ b/modules/gdnative/net/multiplayer_peer_gdnative.cpp
@@ -113,6 +113,8 @@ NetworkedMultiplayerPeer::ConnectionStatus MultiplayerPeerGDNative::get_connecti
}
void MultiplayerPeerGDNative::_bind_methods() {
+ ADD_PROPERTY_DEFAULT("transfer_mode", TRANSFER_MODE_UNRELIABLE);
+ ADD_PROPERTY_DEFAULT("refuse_new_connections", true);
}
extern "C" {
diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp
index 7cb47ec623..9de073fc8e 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_language.cpp
@@ -159,7 +159,7 @@ String PluginScriptLanguage::make_function(const String &p_class, const String &
return String();
}
-Error PluginScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<String> *r_options, bool &r_force, String &r_call_hint) {
+Error PluginScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_force, String &r_call_hint) {
if (_desc.complete_code) {
Array options;
godot_error tmp = _desc.complete_code(
@@ -171,7 +171,8 @@ Error PluginScriptLanguage::complete_code(const String &p_code, const String &p_
&r_force,
(godot_string *)&r_call_hint);
for (int i = 0; i < options.size(); i++) {
- r_options->push_back(String(options[i]));
+ ScriptCodeCompletionOption option(options[i], ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ r_options->push_back(option);
}
return (Error)tmp;
}
@@ -216,7 +217,7 @@ void PluginScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_
Dictionary constants;
_desc.get_public_constants(_data, (godot_dictionary *)&constants);
for (const Variant *key = constants.next(); key; key = constants.next(key)) {
- Variant value = constants[key];
+ Variant value = constants[*key];
p_constants->push_back(Pair<String, Variant>(*key, value));
}
}
diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h
index a11e916975..7b3844d0b0 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.h
+++ b/modules/gdnative/pluginscript/pluginscript_language.h
@@ -81,7 +81,7 @@ public:
virtual bool can_inherit_from_file() { return true; }
virtual int find_function(const String &p_function, const String &p_code) const;
virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const;
- virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<String> *r_options, bool &r_force, String &r_call_hint);
+ virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_force, String &r_call_hint);
virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const;
virtual void add_global_constant(const StringName &p_variable, const Variant &p_value);
diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp
index 1d6f9db349..3ecb29404a 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_script.cpp
@@ -229,6 +229,8 @@ void PluginScript::set_source_code(const String &p_code) {
}
Error PluginScript::reload(bool p_keep_state) {
+ ERR_FAIL_COND_V(!_language, ERR_UNCONFIGURED);
+
_language->lock();
ERR_FAIL_COND_V(!p_keep_state && _instances.size(), ERR_ALREADY_IN_USE);
_language->unlock();
@@ -284,7 +286,7 @@ Error PluginScript::reload(bool p_keep_state) {
Dictionary *members = (Dictionary *)&manifest.member_lines;
for (const Variant *key = members->next(); key != NULL; key = members->next(key)) {
- _member_lines[*key] = (*members)[key];
+ _member_lines[*key] = (*members)[*key];
}
Array *methods = (Array *)&manifest.methods;
for (int i = 0; i < methods->size(); ++i) {
@@ -473,6 +475,8 @@ MultiplayerAPI::RPCMode PluginScript::get_rset_mode(const StringName &p_variable
PluginScript::PluginScript() :
_data(NULL),
+ _desc(NULL),
+ _language(NULL),
_tool(false),
_valid(false),
_script_list(this) {
@@ -490,11 +494,15 @@ void PluginScript::init(PluginScriptLanguage *language) {
}
PluginScript::~PluginScript() {
- _desc->finish(_data);
+ if (_desc && _data) {
+ _desc->finish(_data);
+ }
#ifdef DEBUG_ENABLED
- _language->lock();
- _language->_script_list.remove(&_script_list);
- _language->unlock();
+ if (_language) {
+ _language->lock();
+ _language->_script_list.remove(&_script_list);
+ _language->unlock();
+ }
#endif
}
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 95f3c12806..bc28f7009e 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -332,7 +332,7 @@ ScriptInstance *GDScript::instance_create(Object *p_this) {
}
Variant::CallError unchecked_error;
- return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this), unchecked_error);
+ return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this) != NULL, unchecked_error);
}
PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this) {
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 1756f6eabc..a5ad23c75d 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -458,7 +458,7 @@ public:
virtual bool can_inherit_from_file() { return true; }
virtual int find_function(const String &p_function, const String &p_code) const;
virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const;
- virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<String> *r_options, bool &r_forced, String &r_call_hint);
+ virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint);
#ifdef TOOLS_ENABLED
virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result);
#endif
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index caffe04700..4c976bd2e0 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -1259,8 +1259,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
ERR_FAIL_V(-1); //unreachable code
} break;
}
-
- ERR_FAIL_V(-1); //unreachable code
}
Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::BlockNode *p_block, int p_stack_level, int p_break_addr, int p_continue_addr) {
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 6c77968f44..78a1bfc99b 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -509,12 +509,14 @@ struct GDScriptCompletionIdentifier {
assigned_expression(NULL) {}
};
-static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Set<String> &r_list) {
+static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String, ScriptCodeCompletionOption> &r_list) {
const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
for (int i = 0; i < p_dir->get_file_count(); i++) {
- r_list.insert(quote_style + p_dir->get_file_path(i) + quote_style);
+ ScriptCodeCompletionOption option(p_dir->get_file_path(i), ScriptCodeCompletionOption::KIND_FILE_PATH);
+ option.insert_text = quote_style + option.display + quote_style;
+ r_list.insert(option.display, option);
}
for (int i = 0; i < p_dir->get_subdir_count(); i++) {
@@ -1807,14 +1809,15 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio
return arghint;
}
-static void _find_enumeration_candidates(const String p_enum_hint, Set<String> &r_result) {
+static void _find_enumeration_candidates(const String p_enum_hint, Map<String, ScriptCodeCompletionOption> &r_result) {
if (p_enum_hint.find(".") == -1) {
// Global constant
StringName current_enum = p_enum_hint;
for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) {
if (GlobalConstants::get_global_constant_enum(i) == current_enum) {
- r_result.insert(GlobalConstants::get_global_constant_name(i));
+ ScriptCodeCompletionOption option(GlobalConstants::get_global_constant_name(i), ScriptCodeCompletionOption::KIND_ENUM);
+ r_result.insert(option.display, option);
}
}
} else {
@@ -1829,15 +1832,17 @@ static void _find_enumeration_candidates(const String p_enum_hint, Set<String> &
ClassDB::get_enum_constants(class_name, enum_name, &enum_constants);
for (List<StringName>::Element *E = enum_constants.front(); E; E = E->next()) {
String candidate = class_name + "." + E->get();
- r_result.insert(candidate);
+ ScriptCodeCompletionOption option(candidate, ScriptCodeCompletionOption::KIND_ENUM);
+ r_result.insert(option.display, option);
}
}
}
-static void _find_identifiers_in_block(const GDScriptCompletionContext &p_context, Set<String> &r_result) {
+static void _find_identifiers_in_block(const GDScriptCompletionContext &p_context, Map<String, ScriptCodeCompletionOption> &r_result) {
for (Map<StringName, GDScriptParser::LocalVarNode *>::Element *E = p_context.block->variables.front(); E; E = E->next()) {
if (E->get()->line < p_context.line) {
- r_result.insert(E->key().operator String());
+ ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_VARIABLE);
+ r_result.insert(option.display, option);
}
}
if (p_context.block->parent_block) {
@@ -1847,40 +1852,47 @@ static void _find_identifiers_in_block(const GDScriptCompletionContext &p_contex
}
}
-static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Set<String> &r_result);
+static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result);
-static void _find_identifiers_in_class(const GDScriptCompletionContext &p_context, bool p_static, bool p_only_functions, bool p_parent_only, Set<String> &r_result) {
+static void _find_identifiers_in_class(const GDScriptCompletionContext &p_context, bool p_static, bool p_only_functions, bool p_parent_only, Map<String, ScriptCodeCompletionOption> &r_result) {
if (!p_parent_only) {
if (!p_static && !p_only_functions) {
for (int i = 0; i < p_context._class->variables.size(); i++) {
- r_result.insert(p_context._class->variables[i].identifier);
+ ScriptCodeCompletionOption option(p_context._class->variables[i].identifier, ScriptCodeCompletionOption::KIND_MEMBER);
+ r_result.insert(option.display, option);
}
}
if (!p_only_functions) {
for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = p_context._class->constant_expressions.front(); E; E = E->next()) {
- r_result.insert(E->key());
+ ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_CONSTANT);
+ r_result.insert(option.display, option);
}
for (int i = 0; i < p_context._class->subclasses.size(); i++) {
- r_result.insert(p_context._class->subclasses[i]->name);
+ ScriptCodeCompletionOption option(p_context._class->subclasses[i]->name, ScriptCodeCompletionOption::KIND_CLASS);
+ r_result.insert(option.display, option);
}
}
for (int i = 0; i < p_context._class->static_functions.size(); i++) {
+ ScriptCodeCompletionOption option(p_context._class->static_functions[i]->name.operator String(), ScriptCodeCompletionOption::KIND_FUNCTION);
if (p_context._class->static_functions[i]->arguments.size()) {
- r_result.insert(p_context._class->static_functions[i]->name.operator String() + "(");
+ option.insert_text += "(";
} else {
- r_result.insert(p_context._class->static_functions[i]->name.operator String() + "()");
+ option.insert_text += "()";
}
+ r_result.insert(option.display, option);
}
if (!p_static) {
for (int i = 0; i < p_context._class->functions.size(); i++) {
+ ScriptCodeCompletionOption option(p_context._class->functions[i]->name.operator String(), ScriptCodeCompletionOption::KIND_FUNCTION);
if (p_context._class->functions[i]->arguments.size()) {
- r_result.insert(p_context._class->functions[i]->name.operator String() + "(");
+ option.insert_text += "(";
} else {
- r_result.insert(p_context._class->functions[i]->name.operator String() + "()");
+ option.insert_text += "()";
}
+ r_result.insert(option.display, option);
}
}
}
@@ -1898,12 +1910,14 @@ static void _find_identifiers_in_class(const GDScriptCompletionContext &p_contex
_find_identifiers_in_base(c, base_type, p_only_functions, r_result);
}
-static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Set<String> &r_result) {
+static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result) {
GDScriptParser::DataType base_type = p_base.type;
bool _static = base_type.is_meta_type;
if (_static && base_type.kind != GDScriptParser::DataType::BUILTIN) {
- r_result.insert("new(");
+ ScriptCodeCompletionOption option("new", ScriptCodeCompletionOption::KIND_FUNCTION);
+ option.insert_text += "(";
+ r_result.insert(option.display, option);
}
while (base_type.has_type) {
@@ -1921,26 +1935,31 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
if (script.is_valid()) {
if (!_static && !p_only_functions) {
for (const Set<StringName>::Element *E = script->get_members().front(); E; E = E->next()) {
- r_result.insert(E->get().operator String());
+ ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_MEMBER);
+ r_result.insert(option.display, option);
}
}
if (!p_only_functions) {
for (const Map<StringName, Variant>::Element *E = script->get_constants().front(); E; E = E->next()) {
- r_result.insert(E->key().operator String());
+ ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CONSTANT);
+ r_result.insert(option.display, option);
}
}
for (const Map<StringName, GDScriptFunction *>::Element *E = script->get_member_functions().front(); E; E = E->next()) {
if (!_static || E->get()->is_static()) {
+ ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_FUNCTION);
if (E->get()->get_argument_count()) {
- r_result.insert(E->key().operator String() + "(");
+ option.insert_text += "(";
} else {
- r_result.insert(E->key().operator String() + "()");
+ option.insert_text += "()";
}
+ r_result.insert(option.display, option);
}
}
if (!p_only_functions) {
for (const Map<StringName, Ref<GDScript> >::Element *E = script->get_subclasses().front(); E; E = E->next()) {
- r_result.insert(E->key().operator String());
+ ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
+ r_result.insert(option.display, option);
}
}
base_type = GDScriptParser::DataType();
@@ -1964,25 +1983,29 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
List<PropertyInfo> members;
scr->get_script_property_list(&members);
for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) {
- r_result.insert(E->get().name);
+ ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER);
+ r_result.insert(option.display, option);
}
}
if (!p_only_functions) {
Map<StringName, Variant> constants;
scr->get_constants(&constants);
for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
- r_result.insert(E->key().operator String());
+ ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CONSTANT);
+ r_result.insert(option.display, option);
}
}
List<MethodInfo> methods;
scr->get_script_method_list(&methods);
for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
+ ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION);
if (E->get().arguments.size()) {
- r_result.insert(E->get().name + "(");
+ option.insert_text += "(";
} else {
- r_result.insert(E->get().name + "()");
+ option.insert_text += "()";
}
+ r_result.insert(option.display, option);
}
Ref<Script> base_script = scr->get_base_script();
@@ -2009,7 +2032,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
List<String> constants;
ClassDB::get_integer_constant_list(type, &constants);
for (List<String>::Element *E = constants.front(); E; E = E->next()) {
- r_result.insert(E->get());
+ ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CONSTANT);
+ r_result.insert(option.display, option);
}
if (!_static) {
@@ -2022,7 +2046,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
if (E->get().name.find("/") != -1) {
continue;
}
- r_result.insert(E->get().name);
+ ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER);
+ r_result.insert(option.display, option);
}
}
}
@@ -2035,11 +2060,13 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
if (E->get().name.begins_with("_")) {
continue;
}
+ ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION);
if (E->get().arguments.size()) {
- r_result.insert(E->get().name + "(");
+ option.insert_text += "(";
} else {
- r_result.insert(E->get().name + "()");
+ option.insert_text += "()";
}
+ r_result.insert(option.display, option);
}
}
@@ -2058,7 +2085,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) {
if (String(E->get().name).find("/") == -1) {
- r_result.insert(E->get().name);
+ ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER);
+ r_result.insert(option.display, option);
}
}
}
@@ -2066,11 +2094,13 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
List<MethodInfo> methods;
tmp.get_method_list(&methods);
for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
+ ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION);
if (E->get().arguments.size()) {
- r_result.insert(E->get().name + "(");
+ option.insert_text += "(";
} else {
- r_result.insert(E->get().name + "()");
+ option.insert_text += "()";
}
+ r_result.insert(option.display, option);
}
return;
@@ -2082,7 +2112,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
}
}
-static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p_only_functions, Set<String> &r_result) {
+static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result) {
const GDScriptParser::BlockNode *block = p_context.block;
@@ -2091,7 +2121,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p
const GDScriptParser::FunctionNode *f = p_context.function;
for (int i = 0; i < f->arguments.size(); i++) {
- r_result.insert(f->arguments[i].operator String());
+ ScriptCodeCompletionOption option(f->arguments[i].operator String(), ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ r_result.insert(option.display, option);
}
}
@@ -2116,11 +2147,13 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p
for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
MethodInfo mi = GDScriptFunctions::get_info(GDScriptFunctions::Function(i));
+ ScriptCodeCompletionOption option(String(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))), ScriptCodeCompletionOption::KIND_FUNCTION);
if (mi.arguments.size() || (mi.flags & METHOD_FLAG_VARARG)) {
- r_result.insert(String(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))) + "(");
+ option.insert_text += "(";
} else {
- r_result.insert(String(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))) + "()");
+ option.insert_text += "()";
}
+ r_result.insert(option.display, option);
}
static const char *_type_names[Variant::VARIANT_MAX] = {
@@ -2130,7 +2163,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p
};
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- r_result.insert(_type_names[i]);
+ ScriptCodeCompletionOption option(_type_names[i], ScriptCodeCompletionOption::KIND_CLASS);
+ r_result.insert(option.display, option);
}
static const char *_keywords[] = {
@@ -2144,7 +2178,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p
const char **kw = _keywords;
while (*kw) {
- r_result.insert(*kw);
+ ScriptCodeCompletionOption option(*kw, ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ r_result.insert(option.display, option);
kw++;
}
@@ -2158,7 +2193,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p
}
String path = ProjectSettings::get_singleton()->get(s);
if (path.begins_with("*")) {
- r_result.insert(s.get_slice("/", 1));
+ ScriptCodeCompletionOption option(s.get_slice("/", 1), ScriptCodeCompletionOption::KIND_CONSTANT);
+ r_result.insert(option.display, option);
}
}
@@ -2166,16 +2202,18 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p
List<StringName> named_scripts;
ScriptServer::get_global_class_list(&named_scripts);
for (List<StringName>::Element *E = named_scripts.front(); E; E = E->next()) {
- r_result.insert(E->get().operator String());
+ ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
+ r_result.insert(option.display, option);
}
// Native classes
for (const Map<StringName, int>::Element *E = GDScriptLanguage::get_singleton()->get_global_map().front(); E; E = E->next()) {
- r_result.insert(E->key().operator String());
+ ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
+ r_result.insert(option.display, option);
}
}
-static void _find_call_arguments(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, Set<String> &r_result, String &r_arghint) {
+static void _find_call_arguments(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, Map<String, ScriptCodeCompletionOption> &r_result, String &r_arghint) {
Variant base = p_base.value;
GDScriptParser::DataType base_type = p_base.type;
@@ -2199,7 +2237,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) {
for (int i = 0; i < base_type.class_type->_signals.size(); i++) {
- r_result.insert(quote_style + base_type.class_type->_signals[i].name.operator String() + quote_style);
+ ScriptCodeCompletionOption option(base_type.class_type->_signals[i].name.operator String(), ScriptCodeCompletionOption::KIND_SIGNAL);
+ option.insert_text = quote_style + option.display + quote_style;
+ r_result.insert(option.display, option);
}
}
@@ -2212,7 +2252,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
List<MethodInfo> signals;
gds->get_script_signal_list(&signals);
for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
- r_result.insert(quote_style + E->get().name + quote_style);
+ ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_SIGNAL);
+ option.insert_text = quote_style + option.display + quote_style;
+ r_result.insert(option.display, option);
}
}
Ref<GDScript> base_script = gds->get_base_script();
@@ -2250,7 +2292,8 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
List<String> options;
obj->get_argument_options(p_method, p_argidx, &options);
for (List<String>::Element *F = options.front(); F; F = F->next()) {
- r_result.insert(F->get());
+ ScriptCodeCompletionOption option(F->get(), ScriptCodeCompletionOption::KIND_FUNCTION);
+ r_result.insert(option.display, option);
}
}
}
@@ -2271,7 +2314,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
List<MethodInfo> signals;
ClassDB::get_signal_list(class_name, &signals);
for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
- r_result.insert(quote_style + E->get().name + quote_style);
+ ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_SIGNAL);
+ option.insert_text = quote_style + option.display + quote_style;
+ r_result.insert(option.display, option);
}
}
@@ -2286,7 +2331,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
continue;
}
String name = s.get_slice("/", 1);
- r_result.insert(quote_style + "/root/" + name + quote_style);
+ ScriptCodeCompletionOption option("/root/" + name, ScriptCodeCompletionOption::KIND_NODE_PATH);
+ option.insert_text = quote_style + option.display + quote_style;
+ r_result.insert(option.display, option);
}
}
@@ -2300,7 +2347,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
continue;
}
String name = s.get_slice("/", 1);
- r_result.insert(quote_style + name + quote_style);
+ ScriptCodeCompletionOption option(name, ScriptCodeCompletionOption::KIND_CONSTANT);
+ option.insert_text = quote_style + option.display + quote_style;
+ r_result.insert(option.display, option);
}
}
@@ -2333,7 +2382,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
}
}
-static void _find_call_arguments(GDScriptCompletionContext &p_context, const GDScriptParser::Node *p_node, int p_argidx, Set<String> &r_result, bool &r_forced, String &r_arghint) {
+static void _find_call_arguments(GDScriptCompletionContext &p_context, const GDScriptParser::Node *p_node, int p_argidx, Map<String, ScriptCodeCompletionOption> &r_result, bool &r_forced, String &r_arghint) {
const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
@@ -2451,17 +2500,19 @@ static void _find_call_arguments(GDScriptCompletionContext &p_context, const GDS
_find_call_arguments(p_context, ci, function, p_argidx, _static, r_result, r_arghint);
if (function == "connect" && p_argidx == 2) {
- Set<String> methods;
+ Map<String, ScriptCodeCompletionOption> methods;
_find_identifiers_in_base(p_context, connect_base, true, methods);
- for (Set<String>::Element *E = methods.front(); E; E = E->next()) {
- r_result.insert(quote_style + E->get().replace("(", "").replace(")", "") + quote_style);
+ for (Map<String, ScriptCodeCompletionOption>::Element *E = methods.front(); E; E = E->next()) {
+ ScriptCodeCompletionOption &option = E->value();
+ option.insert_text = quote_style + option.display + quote_style;
+ r_result.insert(option.display, option);
}
}
r_forced = r_result.size() > 0;
}
-Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<String> *r_options, bool &r_forced, String &r_call_hint) {
+Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) {
const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
@@ -2469,7 +2520,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
parser.parse(p_code, p_path.get_base_dir(), false, p_path, true);
r_forced = false;
- Set<String> options;
+ Map<String, ScriptCodeCompletionOption> options;
GDScriptCompletionContext context;
context._class = parser.get_completion_class();
context.block = parser.get_completion_block();
@@ -2490,7 +2541,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
List<StringName> constants;
Variant::get_constants_for_type(parser.get_completion_built_in_constant(), &constants);
for (List<StringName>::Element *E = constants.front(); E; E = E->next()) {
- options.insert(E->get().operator String());
+ ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_CONSTANT);
+ options.insert(option.display, option);
}
} break;
case GDScriptParser::COMPLETION_PARENT_FUNCTION: {
@@ -2498,7 +2550,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
} break;
case GDScriptParser::COMPLETION_FUNCTION: {
is_function = true;
- } // fallthrough
+ FALLTHROUGH;
+ }
case GDScriptParser::COMPLETION_IDENTIFIER: {
_find_identifiers(context, is_function, options);
} break;
@@ -2514,9 +2567,11 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
r_forced = true;
String idopt = opt.unquote();
if (idopt.replace("/", "_").is_valid_identifier()) {
- options.insert(idopt);
+ ScriptCodeCompletionOption option(idopt, ScriptCodeCompletionOption::KIND_NODE_PATH);
+ options.insert(option.display, option);
} else {
- options.insert(opt);
+ ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_NODE_PATH);
+ options.insert(option.display, option);
}
}
}
@@ -2531,13 +2586,15 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
continue;
}
String name = s.get_slice("/", 1);
- options.insert(quote_style + "/root/" + name + quote_style);
+ ScriptCodeCompletionOption option(quote_style + "/root/" + name + quote_style, ScriptCodeCompletionOption::KIND_NODE_PATH);
+ options.insert(option.display, option);
}
}
} break;
case GDScriptParser::COMPLETION_METHOD: {
is_function = true;
- } // fallthrough
+ FALLTHROUGH;
+ }
case GDScriptParser::COMPLETION_INDEX: {
const GDScriptParser::Node *node = parser.get_completion_node();
if (node->type != GDScriptParser::Node::TYPE_OPERATOR) {
@@ -2653,7 +2710,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
}
method_hint += ":";
- options.insert(method_hint);
+ ScriptCodeCompletionOption option(method_hint, ScriptCodeCompletionOption::KIND_FUNCTION);
+ options.insert(option.display, option);
}
} break;
case GDScriptParser::COMPLETION_YIELD: {
@@ -2671,7 +2729,9 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
switch (base_type.kind) {
case GDScriptParser::DataType::CLASS: {
for (int i = 0; i < base_type.class_type->_signals.size(); i++) {
- options.insert(quote_style + base_type.class_type->_signals[i].name.operator String() + quote_style);
+ ScriptCodeCompletionOption option(base_type.class_type->_signals[i].name.operator String(), ScriptCodeCompletionOption::KIND_SIGNAL);
+ option.insert_text = quote_style + option.display + quote_style;
+ options.insert(option.display, option);
}
base_type = base_type.class_type->base_type;
} break;
@@ -2682,7 +2742,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
List<MethodInfo> signals;
scr->get_script_signal_list(&signals);
for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
- options.insert(quote_style + E->get().name + quote_style);
+ ScriptCodeCompletionOption option(quote_style + E->get().name + quote_style, ScriptCodeCompletionOption::KIND_SIGNAL);
+ options.insert(option.display, option);
}
Ref<Script> base_script = scr->get_base_script();
if (base_script.is_valid()) {
@@ -2709,7 +2770,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
List<MethodInfo> signals;
ClassDB::get_signal_list(class_name, &signals);
for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
- options.insert(quote_style + E->get().name + quote_style);
+ ScriptCodeCompletionOption option(quote_style + E->get().name + quote_style, ScriptCodeCompletionOption::KIND_SIGNAL);
+ options.insert(option.display, option);
}
} break;
default: {
@@ -2746,18 +2808,21 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
c.line = E->value().expression->line;
if (_guess_expression_type(c, E->value().expression, constant)) {
if (constant.type.has_type && constant.type.is_meta_type) {
- options.insert(E->key().operator String());
+ ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
+ options.insert(option.display, option);
}
}
}
for (int i = 0; i < clss->subclasses.size(); i++) {
if (clss->subclasses[i]->name != StringName()) {
- options.insert(clss->subclasses[i]->name.operator String());
+ ScriptCodeCompletionOption option(clss->subclasses[i]->name.operator String(), ScriptCodeCompletionOption::KIND_CLASS);
+ options.insert(option.display, option);
}
}
clss = clss->owner;
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- options.insert(Variant::get_type_name((Variant::Type)i));
+ ScriptCodeCompletionOption option(Variant::get_type_name((Variant::Type)i), ScriptCodeCompletionOption::KIND_CLASS);
+ options.insert(option.display, option);
}
}
@@ -2771,18 +2836,21 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
if (Engine::get_singleton()->has_singleton(class_name)) {
continue;
}
- options.insert(class_name);
+ ScriptCodeCompletionOption option(class_name, ScriptCodeCompletionOption::KIND_CLASS);
+ options.insert(option.display, option);
}
// Named scripts
List<StringName> named_scripts;
ScriptServer::get_global_class_list(&named_scripts);
for (List<StringName>::Element *E = named_scripts.front(); E; E = E->next()) {
- options.insert(E->get().operator String());
+ ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
+ options.insert(option.display, option);
}
if (parser.get_completion_identifier_is_function()) {
- options.insert("void");
+ ScriptCodeCompletionOption option("void", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ options.insert(option.display, option);
}
r_forced = true;
} break;
@@ -2829,13 +2897,15 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
c2.line = E->value().expression->line;
if (_guess_expression_type(c2, E->value().expression, constant)) {
if (constant.type.has_type && constant.type.is_meta_type) {
- options.insert(E->key().operator String());
+ ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
+ options.insert(option.display, option);
}
}
}
for (int i = 0; i < base_type.class_type->subclasses.size(); i++) {
if (base_type.class_type->subclasses[i]->name != StringName()) {
- options.insert(base_type.class_type->subclasses[i]->name.operator String());
+ ScriptCodeCompletionOption option(base_type.class_type->subclasses[i]->name.operator String(), ScriptCodeCompletionOption::KIND_CLASS);
+ options.insert(option.display, option);
}
}
@@ -2853,7 +2923,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
Ref<Script> const_scr = E->value();
if (const_scr.is_valid()) {
- options.insert(E->key().operator String());
+ ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
+ options.insert(option.display, option);
}
}
Ref<Script> base_script = scr->get_base_script();
@@ -2875,7 +2946,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
} break;
}
- for (Set<String>::Element *E = options.front(); E; E = E->next()) {
+ for (Map<String, ScriptCodeCompletionOption>::Element *E = options.front(); E; E = E->next()) {
r_options->push_back(E->get());
}
@@ -2884,7 +2955,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
#else
-Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<String> *r_options, bool &r_forced, String &r_call_hint) {
+Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) {
return OK;
}
@@ -3234,7 +3305,8 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol
case GDScriptParser::COMPLETION_PARENT_FUNCTION:
case GDScriptParser::COMPLETION_FUNCTION: {
is_function = true;
- } // fallthrough
+ FALLTHROUGH;
+ }
case GDScriptParser::COMPLETION_IDENTIFIER: {
if (!is_function) {
@@ -3365,7 +3437,8 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol
} break;
case GDScriptParser::COMPLETION_METHOD: {
is_function = true;
- } // fallthrough
+ FALLTHROUGH;
+ }
case GDScriptParser::COMPLETION_INDEX: {
const GDScriptParser::Node *node = parser.get_completion_node();
if (node->type != GDScriptParser::Node::TYPE_OPERATOR) {
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index bae5eca218..d5e74c07c9 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -1556,14 +1556,14 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
//error
// function, file, line, error, explanation
String err_file;
- if (p_instance)
+ if (p_instance && p_instance->script->is_valid() && p_instance->script->path != "")
err_file = p_instance->script->path;
else if (script)
err_file = script->path;
if (err_file == "")
err_file = "<built-in>";
String err_func = name;
- if (p_instance && p_instance->script->name != "")
+ if (p_instance && p_instance->script->is_valid() && p_instance->script->name != "")
err_func = p_instance->script->name + "." + err_func;
int err_line = line;
if (err_text == "") {
@@ -1591,15 +1591,26 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GDScriptLanguage::get_singleton()->script_frame_time += time_taken - function_call_time;
}
- if (ScriptDebugger::get_singleton())
- GDScriptLanguage::get_singleton()->exit_function();
+ bool yielded = retvalue.is_ref() && Object::cast_to<GDScriptFunctionState>(retvalue);
+
+ // Check if this is the last time the function is resuming from yield
+ // Will be true if never yielded as well
+ // When it's the last resume it will postpone the exit from stack,
+ // so the debugger knows which function triggered the resume of the next function (if any)
+ if (!p_state || yielded) {
+ if (ScriptDebugger::get_singleton())
+ GDScriptLanguage::get_singleton()->exit_function();
#endif
- if (_stack_size) {
- //free stack
- for (int i = 0; i < _stack_size; i++)
- stack[i].~Variant();
+ if (_stack_size) {
+ //free stack
+ for (int i = 0; i < _stack_size; i++)
+ stack[i].~Variant();
+ }
+
+#ifdef DEBUG_ENABLED
}
+#endif
return retvalue;
}
@@ -1775,7 +1786,7 @@ Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_ar
if (state.instance_id && !ObjectDB::get_instance(state.instance_id)) {
#ifdef DEBUG_ENABLED
- ERR_EXPLAIN("Resumed after yield, but class instance is gone");
+ ERR_EXPLAIN("Resumed function '" + String(function->get_name()) + "()' after yield, but class instance is gone. At script: " + state.script->get_path() + ":" + itos(state.line));
ERR_FAIL_V(Variant());
#else
return Variant();
@@ -1838,6 +1849,17 @@ Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_ar
}
}
+#ifdef DEBUG_ENABLED
+ if (ScriptDebugger::get_singleton())
+ GDScriptLanguage::get_singleton()->exit_function();
+ if (state.stack_size) {
+ //free stack
+ Variant *stack = (Variant *)state.stack.ptr();
+ for (int i = 0; i < state.stack_size; i++)
+ stack[i].~Variant();
+ }
+#endif
+
return ret;
}
@@ -1860,7 +1882,7 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) {
ERR_FAIL_COND_V(!function, Variant());
if (state.instance_id && !ObjectDB::get_instance(state.instance_id)) {
#ifdef DEBUG_ENABLED
- ERR_EXPLAIN("Resumed after yield, but class instance is gone");
+ ERR_EXPLAIN("Resumed function '" + String(function->get_name()) + "()' after yield, but class instance is gone. At script: " + state.script->get_path() + ":" + itos(state.line));
ERR_FAIL_V(Variant());
#else
return Variant();
@@ -1892,6 +1914,17 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) {
} else {
emit_signal("completed", ret);
}
+
+#ifdef DEBUG_ENABLED
+ if (ScriptDebugger::get_singleton())
+ GDScriptLanguage::get_singleton()->exit_function();
+ if (state.stack_size) {
+ //free stack
+ Variant *stack = (Variant *)state.stack.ptr();
+ for (int i = 0; i < state.stack_size; i++)
+ stack[i].~Variant();
+ }
+#endif
}
return ret;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index a4a27c39d7..c5c86fda0a 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -125,7 +125,7 @@ bool GDScriptParser::_enter_indent_block(BlockNode *p_block) {
}
}
-bool GDScriptParser::_parse_arguments(Node *p_parent, Vector<Node *> &p_args, bool p_static, bool p_can_codecomplete) {
+bool GDScriptParser::_parse_arguments(Node *p_parent, Vector<Node *> &p_args, bool p_static, bool p_can_codecomplete, bool p_parsing_constant) {
if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {
tokenizer->advance();
@@ -149,7 +149,7 @@ bool GDScriptParser::_parse_arguments(Node *p_parent, Vector<Node *> &p_args, bo
return false;
}
- Node *arg = _parse_expression(p_parent, p_static);
+ Node *arg = _parse_expression(p_parent, p_static, false, p_parsing_constant);
if (!arg) {
return false;
}
@@ -463,7 +463,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
}
if (!path.is_abs_path() && base_path != "")
- path = base_path + "/" + path;
+ path = base_path.plus_file(path);
path = path.replace("///", "//").simplify_path();
if (path == self_path) {
@@ -639,7 +639,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
id->name = identifier;
op->arguments.push_back(id);
- if (!_parse_arguments(op, op->arguments, p_static, true))
+ if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant))
return NULL;
expr = op;
@@ -731,7 +731,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
completion_node = op;
}
if (!replaced) {
- if (!_parse_arguments(op, op->arguments, p_static, true))
+ if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant))
return NULL;
expr = op;
}
@@ -826,11 +826,12 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
}
// Check parents for the constant
- if (!bfn && cln->extends_file != StringName()) {
- Ref<GDScript> parent = ResourceLoader::load(cln->extends_file);
- if (parent.is_valid() && parent->is_valid()) {
+ if (!bfn) {
+ // Using current_class instead of cln here, since cln is const*
+ _determine_inheritance(current_class, false);
+ if (cln->base_type.has_type && cln->base_type.kind == DataType::GDSCRIPT && cln->base_type.script_type->is_valid()) {
Map<StringName, Variant> parent_constants;
- parent->get_constants(&parent_constants);
+ current_class->base_type.script_type->get_constants(&parent_constants);
if (parent_constants.has(identifier)) {
ConstantNode *constant = alloc_node<ConstantNode>();
constant->value = parent_constants[identifier];
@@ -1112,7 +1113,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
}
} else {
tokenizer->advance();
- if (!_parse_arguments(op, op->arguments, p_static)) {
+ if (!_parse_arguments(op, op->arguments, p_static, false, p_parsing_constant)) {
return NULL;
}
}
@@ -1164,22 +1165,14 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
tokenizer->advance();
IdentifierNode *id = alloc_node<IdentifierNode>();
- if (tokenizer->get_token() == GDScriptTokenizer::TK_BUILT_IN_FUNC) {
- //small hack so built in funcs don't obfuscate methods
-
- id->name = GDScriptFunctions::get_func_name(tokenizer->get_token_built_in_func());
- tokenizer->advance();
-
- } else {
- StringName identifier;
- if (_get_completable_identifier(COMPLETION_METHOD, identifier)) {
- completion_node = op;
- //indexing stuff
- }
-
- id->name = identifier;
+ StringName identifier;
+ if (_get_completable_identifier(COMPLETION_METHOD, identifier)) {
+ completion_node = op;
+ //indexing stuff
}
+ id->name = identifier;
+
op->arguments.push_back(expr); // call what
op->arguments.push_back(id); // call func
//get arguments
@@ -1188,7 +1181,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
_make_completable_call(0);
completion_node = op;
}
- if (!_parse_arguments(op, op->arguments, p_static, true))
+ if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant))
return NULL;
expr = op;
@@ -5158,9 +5151,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
}
-void GDScriptParser::_determine_inheritance(ClassNode *p_class) {
+void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive) {
- if (p_class->extends_used) {
+ if (p_class->base_type.has_type) {
+ // Already determined
+ } else if (p_class->extends_used) {
//do inheritance
String path = p_class->extends_file;
@@ -5355,9 +5350,11 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class) {
p_class->base_type.native_type = "Reference";
}
- // Recursively determine subclasses
- for (int i = 0; i < p_class->subclasses.size(); i++) {
- _determine_inheritance(p_class->subclasses[i]);
+ if (p_recursive) {
+ // Recursively determine subclasses
+ for (int i = 0; i < p_class->subclasses.size(); i++) {
+ _determine_inheritance(p_class->subclasses[i], p_recursive);
+ }
}
}
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 5e4de11357..62d7bdb393 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -582,7 +582,7 @@ private:
#endif // DEBUG_ENABLED
bool _recover_from_completion();
- bool _parse_arguments(Node *p_parent, Vector<Node *> &p_args, bool p_static, bool p_can_codecomplete = false);
+ bool _parse_arguments(Node *p_parent, Vector<Node *> &p_args, bool p_static, bool p_can_codecomplete = false, bool p_parsing_constant = false);
bool _enter_indent_block(BlockNode *p_block = NULL);
bool _parse_newline();
Node *_parse_expression(Node *p_parent, bool p_static, bool p_allow_assign = false, bool p_parsing_constant = false);
@@ -599,7 +599,7 @@ private:
void _parse_class(ClassNode *p_class);
bool _end_statement();
- void _determine_inheritance(ClassNode *p_class);
+ void _determine_inheritance(ClassNode *p_class, bool p_recursive = true);
bool _parse_type(DataType &r_type, bool p_can_be_void = false);
DataType _resolve_type(const DataType &p_source, int p_line);
DataType _type_from_variant(const Variant &p_value) const;
diff --git a/modules/gdscript/icons/icon_g_d_script.svg b/modules/gdscript/icons/icon_g_d_script.svg
new file mode 100644
index 0000000000..953bb9ae9e
--- /dev/null
+++ b/modules/gdscript/icons/icon_g_d_script.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<g transform="translate(0 -1036.4)">
+<path transform="translate(0 1036.4)" d="m7 1l-0.56445 2.2578a5 5 0 0 0 -0.68945 0.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -0.28516 0.68555l-2.2539 0.5625v2l2.2578 0.56445a5 5 0 0 0 0.2793 0.6875l-1.1934 1.9902 1.4141 1.4141 1.9941-1.1953a5 5 0 0 0 0.68555 0.28516l0.5625 2.2539h2l0.56445-2.2578a5 5 0 0 0 0.6875 -0.2793l1.9902 1.1934 1.4141-1.4141-1.1953-1.9941a5 5 0 0 0 0.28516 -0.68555l2.2539-0.5625v-2l-2.2578-0.56445a5 5 0 0 0 -0.2793 -0.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -0.68555 -0.28516l-0.5625-2.2539h-2zm1 5a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2 -2 2 2 0 0 1 2 -2z" fill="#e0e0e0"/>
+</g>
+</svg>
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index 951a49e0c1..325432579f 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -189,28 +189,28 @@
</method>
</methods>
<members>
- <member name="cell_center_x" type="bool" setter="set_center_x" getter="get_center_x">
+ <member name="cell_center_x" type="bool" setter="set_center_x" getter="get_center_x" default="true">
If [code]true[/code], grid items are centered on the X axis.
</member>
- <member name="cell_center_y" type="bool" setter="set_center_y" getter="get_center_y">
+ <member name="cell_center_y" type="bool" setter="set_center_y" getter="get_center_y" default="true">
If [code]true[/code], grid items are centered on the Y axis.
</member>
- <member name="cell_center_z" type="bool" setter="set_center_z" getter="get_center_z">
+ <member name="cell_center_z" type="bool" setter="set_center_z" getter="get_center_z" default="true">
If [code]true[/code], grid items are centered on the Z axis.
</member>
- <member name="cell_octant_size" type="int" setter="set_octant_size" getter="get_octant_size">
+ <member name="cell_octant_size" type="int" setter="set_octant_size" getter="get_octant_size" default="8">
The size of each octant measured in number of cells. This applies to all three axis.
</member>
- <member name="cell_scale" type="float" setter="set_cell_scale" getter="get_cell_scale">
+ <member name="cell_scale" type="float" setter="set_cell_scale" getter="get_cell_scale" default="1.0">
</member>
- <member name="cell_size" type="Vector3" setter="set_cell_size" getter="get_cell_size">
+ <member name="cell_size" type="Vector3" setter="set_cell_size" getter="get_cell_size" default="Vector3( 2, 2, 2 )">
The dimensions of the grid's cells.
</member>
- <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer">
+ <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
</member>
- <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask">
+ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
</member>
- <member name="mesh_library" type="MeshLibrary" setter="set_mesh_library" getter="get_mesh_library">
+ <member name="mesh_library" type="MeshLibrary" setter="set_mesh_library" getter="get_mesh_library" default="null">
The assigned [MeshLibrary].
</member>
<member name="theme" type="MeshLibrary" setter="set_theme" getter="get_theme">
diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp
index 03619aa0bd..20e454c218 100644
--- a/modules/gridmap/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/grid_map_editor_plugin.cpp
@@ -235,7 +235,7 @@ void GridMapEditor::_menu_option(int p_option) {
options->get_popup()->set_item_checked(idx, !options->get_popup()->is_item_checked(idx));
} break;
- case MENU_OPTION_SELECTION_DUPLICATE: // fallthrough
+ case MENU_OPTION_SELECTION_DUPLICATE:
case MENU_OPTION_SELECTION_CUT: {
if (!(selection.active && input_action == INPUT_NONE))
break;
diff --git a/modules/gridmap/icons/icon_grid_map.svg b/modules/gridmap/icons/icon_grid_map.svg
new file mode 100644
index 0000000000..eafe1211f2
--- /dev/null
+++ b/modules/gridmap/icons/icon_grid_map.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<g transform="translate(0 -1036.4)">
+<path transform="translate(0 1036.4)" d="m8 1-6 3v8l6 3 6-3v-2l-2-1-4 2-2-1v-4l2-1v-2l2-1zm4 2-2 1v2l2 1 2-1v-2z" fill="#fc9c9c" fill-opacity=".99608"/>
+</g>
+</svg>
diff --git a/modules/mbedtls/stream_peer_mbed_tls.cpp b/modules/mbedtls/stream_peer_mbed_tls.cpp
index 3541eff25a..4bb7557150 100755
--- a/modules/mbedtls/stream_peer_mbed_tls.cpp
+++ b/modules/mbedtls/stream_peer_mbed_tls.cpp
@@ -33,8 +33,6 @@
#include "core/io/stream_peer_tcp.h"
#include "core/os/file_access.h"
-#include <mbedtls/platform_util.h>
-
static void my_debug(void *ctx, int level,
const char *file, int line,
const char *str) {
diff --git a/modules/mbedtls/stream_peer_mbed_tls.h b/modules/mbedtls/stream_peer_mbed_tls.h
index 3ddbea3ce4..ab87b779c1 100755
--- a/modules/mbedtls/stream_peer_mbed_tls.h
+++ b/modules/mbedtls/stream_peer_mbed_tls.h
@@ -37,7 +37,6 @@
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/debug.h>
#include <mbedtls/entropy.h>
-#include <mbedtls/net.h>
#include <mbedtls/ssl.h>
#include <stdio.h>
diff --git a/modules/mobile_vr/doc_classes/MobileVRInterface.xml b/modules/mobile_vr/doc_classes/MobileVRInterface.xml
index 8cd63b304a..a132333a87 100644
--- a/modules/mobile_vr/doc_classes/MobileVRInterface.xml
+++ b/modules/mobile_vr/doc_classes/MobileVRInterface.xml
@@ -18,25 +18,25 @@
<methods>
</methods>
<members>
- <member name="display_to_lens" type="float" setter="set_display_to_lens" getter="get_display_to_lens">
+ <member name="display_to_lens" type="float" setter="set_display_to_lens" getter="get_display_to_lens" default="4.0">
The distance between the display and the lenses inside of the device in centimeters.
</member>
- <member name="display_width" type="float" setter="set_display_width" getter="get_display_width">
+ <member name="display_width" type="float" setter="set_display_width" getter="get_display_width" default="14.5">
The width of the display in centimeters.
</member>
- <member name="eye_height" type="float" setter="set_eye_height" getter="get_eye_height">
+ <member name="eye_height" type="float" setter="set_eye_height" getter="get_eye_height" default="1.85">
The height at which the camera is placed in relation to the ground (i.e. [ARVROrigin] node).
</member>
- <member name="iod" type="float" setter="set_iod" getter="get_iod">
+ <member name="iod" type="float" setter="set_iod" getter="get_iod" default="6.0">
The interocular distance, also known as the interpupillary distance. The distance between the pupils of the left and right eye.
</member>
- <member name="k1" type="float" setter="set_k1" getter="get_k1">
+ <member name="k1" type="float" setter="set_k1" getter="get_k1" default="0.215">
The k1 lens factor is one of the two constants that define the strength of the lens used and directly influences the lens distortion effect.
</member>
- <member name="k2" type="float" setter="set_k2" getter="get_k2">
+ <member name="k2" type="float" setter="set_k2" getter="get_k2" default="0.215">
The k2 lens factor, see k1.
</member>
- <member name="oversample" type="float" setter="set_oversample" getter="get_oversample">
+ <member name="oversample" type="float" setter="set_oversample" getter="get_oversample" default="1.5">
The oversample setting. Because of the lens distortion we have to render our buffers at a higher resolution then the screen can natively handle. A value between 1.5 and 2.0 often provides good results but at the cost of performance.
</member>
</members>
diff --git a/modules/mono/build_scripts/make_android_mono_config.py b/modules/mono/build_scripts/make_android_mono_config.py
new file mode 100644
index 0000000000..cd9210897d
--- /dev/null
+++ b/modules/mono/build_scripts/make_android_mono_config.py
@@ -0,0 +1,69 @@
+
+def generate_compressed_config(config_src, output_dir):
+ import os.path
+ from compat import byte_to_str
+
+ # Header file
+ with open(os.path.join(output_dir, 'android_mono_config.gen.h'), 'w') as header:
+ header.write('''/* THIS FILE IS GENERATED DO NOT EDIT */
+#ifndef ANDROID_MONO_CONFIG_GEN_H
+#define ANDROID_MONO_CONFIG_GEN_H
+
+#ifdef ANDROID_ENABLED
+
+#include "core/ustring.h"
+
+String get_godot_android_mono_config();
+
+#endif // ANDROID_ENABLED
+
+#endif // ANDROID_MONO_CONFIG_GEN_H
+''')
+
+ # Source file
+ with open(os.path.join(output_dir, 'android_mono_config.gen.cpp'), 'w') as cpp:
+ with open(config_src, 'rb') as f:
+ buf = f.read()
+ decompr_size = len(buf)
+ import zlib
+ buf = zlib.compress(buf)
+ compr_size = len(buf)
+
+ bytes_seq_str = ''
+ for i, buf_idx in enumerate(range(compr_size)):
+ if i > 0:
+ bytes_seq_str += ', '
+ bytes_seq_str += byte_to_str(buf[buf_idx])
+
+ cpp.write('''/* THIS FILE IS GENERATED DO NOT EDIT */
+#include "android_mono_config.gen.h"
+
+#ifdef ANDROID_ENABLED
+
+#include "core/io/compression.h"
+#include "core/pool_vector.h"
+
+namespace {
+
+// config
+static const int config_compressed_size = %d;
+static const int config_uncompressed_size = %d;
+static const unsigned char config_compressed_data[] = { %s };
+
+} // namespace
+
+String get_godot_android_mono_config() {
+ PoolVector<uint8_t> data;
+ data.resize(config_uncompressed_size);
+ PoolVector<uint8_t>::Write w = data.write();
+ Compression::decompress(w.ptr(), config_uncompressed_size, config_compressed_data,
+ config_compressed_size, Compression::MODE_DEFLATE);
+ String s;
+ if (s.parse_utf8((const char *)w.ptr(), data.size())) {
+ ERR_FAIL_V(String());
+ }
+ return s;
+}
+
+#endif // ANDROID_ENABLED
+''' % (compr_size, decompr_size, bytes_seq_str))
diff --git a/modules/mono/build_scripts/make_cs_compressed_header.py b/modules/mono/build_scripts/make_cs_compressed_header.py
index 1f9177cef8..ed49db5bb2 100644
--- a/modules/mono/build_scripts/make_cs_compressed_header.py
+++ b/modules/mono/build_scripts/make_cs_compressed_header.py
@@ -23,30 +23,31 @@ def generate_header(src, dst, version_dst):
latest_mtime = mtime if mtime > latest_mtime else latest_mtime
with open(filepath, 'rb') as f:
buf = f.read()
- decomp_size = len(buf)
+ decompr_size = len(buf)
import zlib
buf = zlib.compress(buf)
+ compr_size = len(buf)
name = str(cs_file_count)
header.write('\n')
header.write('// ' + filepath_src_rel + '\n')
- header.write('static const int _cs_' + name + '_compressed_size = ' + str(len(buf)) + ';\n')
- header.write('static const int _cs_' + name + '_uncompressed_size = ' + str(decomp_size) + ';\n')
+ header.write('static const int _cs_' + name + '_compressed_size = ' + str(compr_size) + ';\n')
+ header.write('static const int _cs_' + name + '_uncompressed_size = ' + str(decompr_size) + ';\n')
header.write('static const unsigned char _cs_' + name + '_compressed[] = { ')
- for i, buf_idx in enumerate(range(len(buf))):
+ for i, buf_idx in enumerate(range(compr_size)):
if i > 0:
header.write(', ')
header.write(byte_to_str(buf[buf_idx]))
+ header.write(' };\n')
inserted_files += '\tr_files.insert("' + filepath_src_rel.replace('\\', '\\\\') + '", ' \
- 'CompressedFile(_cs_' + name + '_compressed_size, ' \
+ 'GodotCsCompressedFile(_cs_' + name + '_compressed_size, ' \
'_cs_' + name + '_uncompressed_size, ' \
'_cs_' + name + '_compressed));\n'
- header.write(' };\n')
- header.write('\nstruct CompressedFile\n' '{\n'
+ header.write('\nstruct GodotCsCompressedFile\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'
+ '\n\tGodotCsCompressedFile(int p_comp_size, int p_uncomp_size, const unsigned char* p_data)\n'
'\t{\n' '\t\tcompressed_size = p_comp_size;\n' '\t\tuncompressed_size = p_uncomp_size;\n'
- '\t\tdata = p_data;\n' '\t}\n' '\n\tCompressedFile() {}\n' '};\n'
- '\nvoid get_compressed_files(Map<String, CompressedFile>& r_files)\n' '{\n' + inserted_files + '}\n'
+ '\t\tdata = p_data;\n' '\t}\n' '\n\tGodotCsCompressedFile() {}\n' '};\n'
+ '\nvoid get_compressed_files(Map<String, GodotCsCompressedFile>& r_files)\n' '{\n' + inserted_files + '}\n'
)
header.write('\n#endif // TOOLS_ENABLED\n')
header.write('\n#endif // CS_COMPRESSED_H\n')
diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py
index c549640d61..3b15f722a3 100644
--- a/modules/mono/build_scripts/mono_configure.py
+++ b/modules/mono/build_scripts/mono_configure.py
@@ -41,7 +41,7 @@ def copy_file(src_dir, dst_dir, name):
dst_dir = Dir(dst_dir).abspath
if not os.path.isdir(dst_dir):
- os.mkdir(dst_dir)
+ os.makedirs(dst_dir)
copy(src_path, dst_dir)
@@ -65,6 +65,10 @@ def configure(env, env_mono):
# TODO: Implement this. We have to add the data directory to the apk, concretely the Api and Tools folders.
raise RuntimeError('This module does not currently support building for android with tools enabled')
+ if is_android and mono_static:
+ # When static linking and doing something that requires libmono-native, we get a dlopen error as libmono-native seems to depend on libmonosgen-2.0
+ raise RuntimeError('Linking Mono statically is not currently supported on Android')
+
if (os.getenv('MONO32_PREFIX') or os.getenv('MONO64_PREFIX')) and not mono_prefix:
print("WARNING: The environment variables 'MONO32_PREFIX' and 'MONO64_PREFIX' are deprecated; use the 'mono_prefix' SCons parameter instead")
@@ -173,7 +177,7 @@ def configure(env, env_mono):
if not mono_lib:
raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
- env_mono.Append(CPPFLAGS=['-D_REENTRANT'])
+ env_mono.Append(CPPDEFINES=['_REENTRANT'])
if mono_static:
mono_lib_file = os.path.join(mono_lib_path, 'lib' + mono_lib + '.a')
@@ -188,7 +192,7 @@ def configure(env, env_mono):
if is_apple:
env.Append(LIBS=['iconv', 'pthread'])
elif is_android:
- env.Append(LIBS=['m', 'dl'])
+ pass # Nothing
else:
env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
@@ -236,6 +240,14 @@ def configure(env, env_mono):
mono_root = subprocess.check_output(['pkg-config', 'mono-2', '--variable=prefix']).decode('utf8').strip()
make_template_dir(env, mono_root)
+ elif not tools_enabled and is_android:
+ # Compress Android Mono Config
+ from . import make_android_mono_config
+ config_file_path = os.path.join(mono_root, 'etc', 'mono', 'config')
+ make_android_mono_config.generate_compressed_config(config_file_path, 'mono_gd/')
+
+ # Copy the required shared libraries
+ copy_mono_shared_libs(env, mono_root, None)
if copy_mono_root:
if not mono_root:
@@ -270,9 +282,8 @@ def make_template_dir(env, mono_root):
# Copy etc/mono/
- if platform != 'android':
- template_mono_config_dir = os.path.join(template_mono_root_dir, 'etc', 'mono')
- copy_mono_etc_dir(mono_root, template_mono_config_dir, env['platform'])
+ template_mono_config_dir = os.path.join(template_mono_root_dir, 'etc', 'mono')
+ copy_mono_etc_dir(mono_root, template_mono_config_dir, env['platform'])
# Copy the required shared libraries
@@ -398,7 +409,7 @@ def configure_for_mono_version(env, mono_version):
raise RuntimeError("Mono JIT compiler version not found; specify one manually with the 'MONO_VERSION' environment variable")
print('Found Mono JIT compiler version: ' + str(mono_version))
if mono_version >= LooseVersion('5.12.0'):
- env.Append(CPPFLAGS=['-DHAS_PENDING_EXCEPTIONS'])
+ env.Append(CPPDEFINES=['HAS_PENDING_EXCEPTIONS'])
def pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext):
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 20b227bda1..cdec10eaba 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -682,19 +682,20 @@ bool CSharpLanguage::is_assembly_reloading_needed() {
GDMonoAssembly *proj_assembly = gdmono->get_project_assembly();
- String name = ProjectSettings::get_singleton()->get("application/config/name");
- if (name.empty()) {
- name = "UnnamedProject";
+ String appname = ProjectSettings::get_singleton()->get("application/config/name");
+ String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
+ if (appname_safe.empty()) {
+ appname_safe = "UnnamedProject";
}
- name += ".dll";
+ appname_safe += ".dll";
if (proj_assembly) {
String proj_asm_path = proj_assembly->get_path();
if (!FileAccess::exists(proj_assembly->get_path())) {
// Maybe it wasn't loaded from the default path, so check this as well
- proj_asm_path = GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(name);
+ proj_asm_path = GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(appname_safe);
if (!FileAccess::exists(proj_asm_path))
return false; // No assembly to load
}
@@ -702,7 +703,7 @@ bool CSharpLanguage::is_assembly_reloading_needed() {
if (FileAccess::get_modified_time(proj_asm_path) <= proj_assembly->get_modified_time())
return false; // Already up to date
} else {
- if (!FileAccess::exists(GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(name)))
+ if (!FileAccess::exists(GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(appname_safe)))
return false; // No assembly to load
}
@@ -2701,7 +2702,7 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) {
}
Variant::CallError unchecked_error;
- return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this), unchecked_error);
+ return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this) != NULL, unchecked_error);
}
PlaceHolderScriptInstance *CSharpScript::placeholder_instance_create(Object *p_this) {
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 2d618f7891..5e0ce3554a 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -914,12 +914,12 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir,
// Generate sources from compressed files
- Map<String, CompressedFile> compressed_files;
+ Map<String, GodotCsCompressedFile> compressed_files;
get_compressed_files(compressed_files);
- for (Map<String, CompressedFile>::Element *E = compressed_files.front(); E; E = E->next()) {
+ for (Map<String, GodotCsCompressedFile>::Element *E = compressed_files.front(); E; E = E->next()) {
const String &file_name = E->key();
- const CompressedFile &file_data = E->value();
+ const GodotCsCompressedFile &file_data = E->value();
String output_file = path_join(core_dir, file_name);
diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp
index 9d42528927..8dc5ced29f 100644
--- a/modules/mono/editor/godotsharp_editor.cpp
+++ b/modules/mono/editor/godotsharp_editor.cpp
@@ -63,16 +63,17 @@ bool GodotSharpEditor::_create_project_solution() {
pr.step(TTR("Generating C# project..."));
String path = OS::get_singleton()->get_resource_dir();
- String name = ProjectSettings::get_singleton()->get("application/config/name");
- if (name.empty()) {
- name = "UnnamedProject";
+ String appname = ProjectSettings::get_singleton()->get("application/config/name");
+ String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
+ if (appname_safe.empty()) {
+ appname_safe = "UnnamedProject";
}
- String guid = CSharpProject::generate_game_project(path, name);
+ String guid = CSharpProject::generate_game_project(path, appname_safe);
if (guid.length()) {
- DotNetSolution solution(name);
+ DotNetSolution solution(appname_safe);
if (!solution.set_path(path)) {
show_error_dialog(TTR("Failed to create solution."));
@@ -81,12 +82,12 @@ bool GodotSharpEditor::_create_project_solution() {
DotNetSolution::ProjectInfo proj_info;
proj_info.guid = guid;
- proj_info.relpath = name + ".csproj";
+ proj_info.relpath = appname_safe + ".csproj";
proj_info.configs.push_back("Debug");
proj_info.configs.push_back("Release");
proj_info.configs.push_back("Tools");
- solution.add_new_project(name, proj_info);
+ solution.add_new_project(appname_safe, proj_info);
Error sln_error = solution.save();
diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp
index 126178125f..590ec007ad 100644
--- a/modules/mono/editor/godotsharp_export.cpp
+++ b/modules/mono/editor/godotsharp_export.cpp
@@ -106,13 +106,14 @@ void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug
Map<String, String> dependencies;
String project_dll_name = ProjectSettings::get_singleton()->get("application/config/name");
- if (project_dll_name.empty()) {
- project_dll_name = "UnnamedProject";
+ String project_dll_name_safe = OS::get_singleton()->get_safe_dir_name(project_dll_name);
+ if (project_dll_name_safe.empty()) {
+ project_dll_name_safe = "UnnamedProject";
}
String project_dll_src_dir = GodotSharpDirs::get_res_temp_assemblies_base_dir().plus_file(build_config);
- String project_dll_src_path = project_dll_src_dir.plus_file(project_dll_name + ".dll");
- dependencies.insert(project_dll_name, project_dll_src_path);
+ String project_dll_src_path = project_dll_src_dir.plus_file(project_dll_name_safe + ".dll");
+ dependencies.insert(project_dll_name_safe, project_dll_src_path);
{
MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.ProjectExportDomain");
@@ -122,10 +123,10 @@ void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug
_GDMONO_SCOPE_DOMAIN_(export_domain);
GDMonoAssembly *scripts_assembly = NULL;
- bool load_success = GDMono::get_singleton()->load_assembly_from(project_dll_name,
+ bool load_success = GDMono::get_singleton()->load_assembly_from(project_dll_name_safe,
project_dll_src_path, &scripts_assembly, /* refonly: */ true);
- ERR_EXPLAIN("Cannot load assembly (refonly): " + project_dll_name);
+ ERR_EXPLAIN("Cannot load assembly (refonly): " + project_dll_name_safe);
ERR_FAIL_COND(!load_success);
Vector<String> search_dirs;
diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp
index 47239f1260..e67c8b9ad9 100644
--- a/modules/mono/glue/collections_glue.cpp
+++ b/modules/mono/glue/collections_glue.cpp
@@ -46,7 +46,7 @@ void godot_icall_Array_Dtor(Array *ptr) {
}
MonoObject *godot_icall_Array_At(Array *ptr, int index) {
- if (index < 0 || index > ptr->size()) {
+ if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return NULL;
}
@@ -54,7 +54,7 @@ MonoObject *godot_icall_Array_At(Array *ptr, int index) {
}
MonoObject *godot_icall_Array_At_Generic(Array *ptr, int index, uint32_t type_encoding, GDMonoClass *type_class) {
- if (index < 0 || index > ptr->size()) {
+ if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return NULL;
}
@@ -62,7 +62,7 @@ MonoObject *godot_icall_Array_At_Generic(Array *ptr, int index, uint32_t type_en
}
void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value) {
- if (index < 0 || index > ptr->size()) {
+ if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return;
}
@@ -124,7 +124,7 @@ MonoBoolean godot_icall_Array_Remove(Array *ptr, MonoObject *item) {
}
void godot_icall_Array_RemoveAt(Array *ptr, int index) {
- if (index < 0 || index > ptr->size()) {
+ if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return;
}
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index 09a1fc6fbc..6445742899 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -39,6 +39,10 @@
#include "editor/editor_settings.h"
#endif
+#ifdef __ANDROID__
+#include "utils/android_utils.h"
+#endif
+
namespace GodotSharpDirs {
String _get_expected_build_config() {
@@ -129,15 +133,16 @@ private:
mono_solutions_dir = mono_user_dir.plus_file("solutions");
build_logs_dir = mono_user_dir.plus_file("build_logs");
- String name = ProjectSettings::get_singleton()->get("application/config/name");
- if (name.empty()) {
- name = "UnnamedProject";
+ String appname = ProjectSettings::get_singleton()->get("application/config/name");
+ String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
+ if (appname_safe.empty()) {
+ appname_safe = "UnnamedProject";
}
String base_path = ProjectSettings::get_singleton()->globalize_path("res://");
- sln_filepath = base_path.plus_file(name + ".sln");
- csproj_filepath = base_path.plus_file(name + ".csproj");
+ sln_filepath = base_path.plus_file(appname_safe + ".sln");
+ csproj_filepath = base_path.plus_file(appname_safe + ".csproj");
#endif
String exe_dir = OS::get_singleton()->get_executable_path().get_base_dir();
@@ -150,7 +155,12 @@ private:
String data_mono_root_dir = data_dir_root.plus_file("Mono");
data_mono_etc_dir = data_mono_root_dir.plus_file("etc");
+
+#if __ANDROID__
+ data_mono_lib_dir = GDMonoUtils::Android::get_app_native_lib_dir();
+#else
data_mono_lib_dir = data_mono_root_dir.plus_file("lib");
+#endif
#ifdef WINDOWS_ENABLED
data_mono_bin_dir = data_mono_root_dir.plus_file("bin");
@@ -173,15 +183,21 @@ private:
#else
- String appname = OS::get_singleton()->get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/name"));
- String data_dir_root = exe_dir.plus_file("data_" + appname);
+ String appname = ProjectSettings::get_singleton()->get("application/config/name");
+ String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
+ String data_dir_root = exe_dir.plus_file("data_" + appname_safe);
if (!DirAccess::exists(data_dir_root)) {
data_dir_root = exe_dir.plus_file("data_Godot");
}
String data_mono_root_dir = data_dir_root.plus_file("Mono");
data_mono_etc_dir = data_mono_root_dir.plus_file("etc");
+
+#if __ANDROID__
+ data_mono_lib_dir = GDMonoUtils::Android::get_app_native_lib_dir();
+#else
data_mono_lib_dir = data_mono_root_dir.plus_file("lib");
+#endif
#ifdef WINDOWS_ENABLED
data_mono_bin_dir = data_mono_root_dir.plus_file("bin");
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 7699e0d0cd..c90da31f3a 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -56,6 +56,10 @@
#include "main/main.h"
#endif
+#ifdef ANDROID_ENABLED
+#include "android_mono_config.gen.h"
+#endif
+
#define OUT_OF_SYNC_ERR_MESSAGE(m_assembly_name) "The assembly '" m_assembly_name "' is out of sync. " \
"This error is expected if you just upgraded to a newer Godot version. " \
"Building the project will update the assembly to the correct version."
@@ -287,7 +291,11 @@ void GDMono::initialize() {
gdmono_debug_init();
#endif
+#ifdef ANDROID_ENABLED
+ mono_config_parse_memory(get_godot_android_mono_config().utf8().get_data());
+#else
mono_config_parse(NULL);
+#endif
mono_install_unhandled_exception_hook(&unhandled_exception_hook, NULL);
@@ -651,12 +659,13 @@ bool GDMono::_load_project_assembly() {
if (project_assembly)
return true;
- String name = ProjectSettings::get_singleton()->get("application/config/name");
- if (name.empty()) {
- name = "UnnamedProject";
+ String appname = ProjectSettings::get_singleton()->get("application/config/name");
+ String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
+ if (appname_safe.empty()) {
+ appname_safe = "UnnamedProject";
}
- bool success = load_assembly(name, &project_assembly);
+ bool success = load_assembly(appname_safe, &project_assembly);
if (success) {
mono_assembly_set_main(project_assembly->get_assembly());
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index f1f0015ac9..1b765a09ff 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -270,7 +270,18 @@ Error GDMonoAssembly::load(bool p_refonly) {
Vector<uint8_t> data = FileAccess::get_file_as_array(path);
ERR_FAIL_COND_V(data.empty(), ERR_FILE_CANT_READ);
- String image_filename = ProjectSettings::get_singleton()->globalize_path(path);
+ String image_filename;
+
+#ifdef ANDROID_ENABLED
+ if (path.begins_with("res://")) {
+ image_filename = path.substr(6, path.length());
+ } else {
+ image_filename = ProjectSettings::get_singleton()->globalize_path(path);
+ }
+#else
+ // FIXME: globalize_path does not work on exported games
+ image_filename = ProjectSettings::get_singleton()->globalize_path(path);
+#endif
MonoImageOpenStatus status = MONO_IMAGE_OK;
diff --git a/modules/mono/utils/android_utils.cpp b/modules/mono/utils/android_utils.cpp
new file mode 100644
index 0000000000..7dd67e3b8e
--- /dev/null
+++ b/modules/mono/utils/android_utils.cpp
@@ -0,0 +1,68 @@
+/*************************************************************************/
+/* android_utils.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 "android_utils.h"
+
+#ifdef __ANDROID__
+
+#include "platform/android/thread_jandroid.h"
+
+namespace GDMonoUtils {
+namespace Android {
+
+String get_app_native_lib_dir() {
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ jclass activityThreadClass = env->FindClass("android/app/ActivityThread");
+ jmethodID currentActivityThread = env->GetStaticMethodID(activityThreadClass, "currentActivityThread", "()Landroid/app/ActivityThread;");
+ jobject activityThread = env->CallStaticObjectMethod(activityThreadClass, currentActivityThread);
+ jmethodID getApplication = env->GetMethodID(activityThreadClass, "getApplication", "()Landroid/app/Application;");
+ jobject ctx = env->CallObjectMethod(activityThread, getApplication);
+
+ jmethodID getApplicationInfo = env->GetMethodID(env->GetObjectClass(ctx), "getApplicationInfo", "()Landroid/content/pm/ApplicationInfo;");
+ jobject applicationInfo = env->CallObjectMethod(ctx, getApplicationInfo);
+ jfieldID nativeLibraryDirField = env->GetFieldID(env->GetObjectClass(applicationInfo), "nativeLibraryDir", "Ljava/lang/String;");
+ jstring nativeLibraryDir = (jstring)env->GetObjectField(applicationInfo, nativeLibraryDirField);
+
+ String result;
+
+ const char *const nativeLibraryDir_utf8 = env->GetStringUTFChars(nativeLibraryDir, NULL);
+ if (nativeLibraryDir_utf8) {
+ result.parse_utf8(nativeLibraryDir_utf8);
+ env->ReleaseStringUTFChars(nativeLibraryDir, nativeLibraryDir_utf8);
+ }
+
+ return result;
+}
+
+} // namespace Android
+} // namespace GDMonoUtils
+
+#endif // __ANDROID__
diff --git a/modules/mono/utils/android_utils.h b/modules/mono/utils/android_utils.h
new file mode 100644
index 0000000000..f911c3fdfe
--- /dev/null
+++ b/modules/mono/utils/android_utils.h
@@ -0,0 +1,48 @@
+/*************************************************************************/
+/* android_utils.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 ANDROID_UTILS_H
+#define ANDROID_UTILS_H
+
+#ifdef __ANDROID__
+
+#include "core/ustring.h"
+
+namespace GDMonoUtils {
+namespace Android {
+
+String get_app_native_lib_dir();
+
+} // namespace Android
+} // namespace GDMonoUtils
+
+#endif // __ANDROID__
+
+#endif // ANDROID_UTILS_H
diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml
index c789724fc4..4826b6cd2a 100644
--- a/modules/opensimplex/doc_classes/NoiseTexture.xml
+++ b/modules/opensimplex/doc_classes/NoiseTexture.xml
@@ -12,21 +12,21 @@
<methods>
</methods>
<members>
- <member name="as_normalmap" type="bool" setter="set_as_normalmap" getter="is_normalmap">
+ <member name="as_normalmap" type="bool" setter="set_as_normalmap" getter="is_normalmap" default="false">
If [code]true[/code], the resulting texture contains a normal map created from the original noise interpreted as a bump map.
</member>
- <member name="bump_strength" type="float" setter="set_bump_strength" getter="get_bump_strength">
+ <member name="bump_strength" type="float" setter="set_bump_strength" getter="get_bump_strength" default="8.0">
</member>
- <member name="height" type="int" setter="set_height" getter="get_height">
+ <member name="height" type="int" setter="set_height" getter="get_height" default="512">
Height of the generated texture.
</member>
- <member name="noise" type="OpenSimplexNoise" setter="set_noise" getter="get_noise">
+ <member name="noise" type="OpenSimplexNoise" setter="set_noise" getter="get_noise" default="null">
The [OpenSimplexNoise] instance used to generate the noise.
</member>
- <member name="seamless" type="bool" setter="set_seamless" getter="get_seamless">
+ <member name="seamless" type="bool" setter="set_seamless" getter="get_seamless" default="false">
Whether the texture can be tiled without visible seams or not. Seamless textures take longer to generate.
</member>
- <member name="width" type="int" setter="set_width" getter="get_width">
+ <member name="width" type="int" setter="set_width" getter="get_width" default="512">
Width of the generated texture.
</member>
</members>
diff --git a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
index 86acd4eaea..f3fbbab3da 100644
--- a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
+++ b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
@@ -113,19 +113,19 @@
</method>
</methods>
<members>
- <member name="lacunarity" type="float" setter="set_lacunarity" getter="get_lacunarity">
+ <member name="lacunarity" type="float" setter="set_lacunarity" getter="get_lacunarity" default="2.0">
Difference in period between [member octaves].
</member>
- <member name="octaves" type="int" setter="set_octaves" getter="get_octaves">
+ <member name="octaves" type="int" setter="set_octaves" getter="get_octaves" default="3">
Number of OpenSimplex noise layers that are sampled to get the fractal noise.
</member>
- <member name="period" type="float" setter="set_period" getter="get_period">
+ <member name="period" type="float" setter="set_period" getter="get_period" default="64.0">
Period of the base octave. A lower period results in a higher-frequency noise (more value changes across the same distance).
</member>
- <member name="persistence" type="float" setter="set_persistence" getter="get_persistence">
+ <member name="persistence" type="float" setter="set_persistence" getter="get_persistence" default="0.5">
Contribution factor of the different octaves. A [code]persistence[/code] value of 1 means all the octaves have the same contribution, a value of 0.5 means each octave contributes half as much as the previous one.
</member>
- <member name="seed" type="int" setter="set_seed" getter="get_seed">
+ <member name="seed" type="int" setter="set_seed" getter="get_seed" default="0">
Seed used to generate random values, different seeds will generate different noise maps.
</member>
</members>
diff --git a/modules/opensimplex/icons/icon_noise_texture.svg b/modules/opensimplex/icons/icon_noise_texture.svg
new file mode 100644
index 0000000000..5908c2b2d4
--- /dev/null
+++ b/modules/opensimplex/icons/icon_noise_texture.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<path d="m2 1c-0.55228 0-1 0.44772-1 1v12c0 0.55228 0.44772 1 1 1h12c0.55228 0 1-0.44772 1-1v-12c0-0.55228-0.44772-1-1-1zm1 2h10v8h-10zm3 1v2h2v-2zm2 2v2h2v2h2v-6h-2v2zm0 2h-2v-2h-2v4h4z" fill="#e0e0e0" fill-opacity=".99608"/>
+</svg>
diff --git a/modules/opus/SCsub b/modules/opus/SCsub
index a4a431bab7..1db5b0987e 100644
--- a/modules/opus/SCsub
+++ b/modules/opus/SCsub
@@ -139,7 +139,7 @@ if env['builtin_opus']:
opus_sources_silk = []
if env["platform"] in ["android", "iphone", "javascript"]:
- env_opus.Append(CPPFLAGS=["-DFIXED_POINT"])
+ env_opus.Append(CPPDEFINES=["FIXED_POINT"])
opus_sources_silk = [
"silk/fixed/LTP_analysis_filter_FIX.c",
"silk/fixed/LTP_scale_ctrl_FIX.c",
@@ -208,7 +208,7 @@ if env['builtin_opus']:
if env['builtin_libogg']:
env_opus.Prepend(CPPPATH=["#thirdparty/libogg"])
- env_opus.Append(CPPFLAGS=["-DHAVE_CONFIG_H"])
+ env_opus.Append(CPPDEFINES=["HAVE_CONFIG_H"])
thirdparty_include_paths = [
"",
@@ -222,14 +222,14 @@ if env['builtin_opus']:
if env["platform"] == "android":
if ("android_arch" in env and env["android_arch"] == "armv7"):
- env_opus.Append(CPPFLAGS=["-DOPUS_ARM_OPT"])
+ env_opus.Append(CPPDEFINES=["OPUS_ARM_OPT"])
elif ("android_arch" in env and env["android_arch"] == "arm64v8"):
- env_opus.Append(CPPFLAGS=["-DOPUS_ARM64_OPT"])
+ env_opus.Append(CPPDEFINES=["OPUS_ARM64_OPT"])
elif env["platform"] == "iphone":
if ("arch" in env and env["arch"] == "arm"):
- env_opus.Append(CPPFLAGS=["-DOPUS_ARM_OPT"])
+ env_opus.Append(CPPDEFINES=["OPUS_ARM_OPT"])
elif ("arch" in env and env["arch"] == "arm64"):
- env_opus.Append(CPPFLAGS=["-DOPUS_ARM64_OPT"])
+ env_opus.Append(CPPDEFINES=["OPUS_ARM64_OPT"])
env_thirdparty = env_opus.Clone()
env_thirdparty.disable_warnings()
diff --git a/modules/regex/SCsub b/modules/regex/SCsub
index 65f354ffa7..acbe4a5a01 100644
--- a/modules/regex/SCsub
+++ b/modules/regex/SCsub
@@ -9,10 +9,10 @@ if env['builtin_pcre2']:
jit_blacklist = ['javascript', 'uwp']
thirdparty_dir = '#thirdparty/pcre2/src/'
- thirdparty_flags = ['-DPCRE2_STATIC', '-DHAVE_CONFIG_H']
+ thirdparty_flags = ['PCRE2_STATIC', 'HAVE_CONFIG_H']
if 'platform' in env and env['platform'] not in jit_blacklist:
- thirdparty_flags.append('-DSUPPORT_JIT')
+ thirdparty_flags.append('SUPPORT_JIT')
thirdparty_sources = [
"pcre2_auto_possess.c",
@@ -47,17 +47,17 @@ if env['builtin_pcre2']:
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_regex.Prepend(CPPPATH=[thirdparty_dir])
- env_regex.Append(CPPFLAGS=thirdparty_flags)
+ env_regex.Append(CPPDEFINES=thirdparty_flags)
def pcre2_builtin(width):
env_pcre2 = env_regex.Clone()
env_pcre2.disable_warnings()
env_pcre2["OBJSUFFIX"] = "_" + width + env_pcre2["OBJSUFFIX"]
env_pcre2.add_source_files(env.modules_sources, thirdparty_sources)
- env_pcre2.Append(CPPFLAGS=["-DPCRE2_CODE_UNIT_WIDTH=" + width])
+ env_pcre2.Append(CPPDEFINES=[("PCRE2_CODE_UNIT_WIDTH", width)])
pcre2_builtin("16")
pcre2_builtin("32")
-env_regex.Append(CPPFLAGS=["-DPCRE2_CODE_UNIT_WIDTH=0"])
+env_regex.Append(CPPDEFINES=[("PCRE2_CODE_UNIT_WIDTH", 0)])
env_regex.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/regex/doc_classes/RegExMatch.xml b/modules/regex/doc_classes/RegExMatch.xml
index 398d2ee3b6..e279607d13 100644
--- a/modules/regex/doc_classes/RegExMatch.xml
+++ b/modules/regex/doc_classes/RegExMatch.xml
@@ -48,13 +48,15 @@
</method>
</methods>
<members>
- <member name="names" type="Dictionary" setter="" getter="get_names">
+ <member name="names" type="Dictionary" setter="" getter="get_names" default="{
+
+}">
A dictionary of named groups and its corresponding group number. Only groups with that were matched are included. If multiple groups have the same name, that name would refer to the first matching one.
</member>
- <member name="strings" type="Array" setter="" getter="get_strings">
+ <member name="strings" type="Array" setter="" getter="get_strings" default="[ ]">
An [Array] of the match and its capturing groups.
</member>
- <member name="subject" type="String" setter="" getter="get_subject">
+ <member name="subject" type="String" setter="" getter="get_subject" default="&quot;&quot;">
The source string used with the search pattern to find this matching result.
</member>
</members>
diff --git a/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml b/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml
index 388c5e81ed..9403199398 100644
--- a/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml
+++ b/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml
@@ -11,12 +11,12 @@
<methods>
</methods>
<members>
- <member name="data" type="PoolByteArray" setter="set_data" getter="get_data">
+ <member name="data" type="PoolByteArray" setter="set_data" getter="get_data" default="PoolByteArray( )">
Contains the audio data in bytes.
</member>
- <member name="loop" type="bool" setter="set_loop" getter="has_loop">
+ <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="false">
</member>
- <member name="loop_offset" type="float" setter="set_loop_offset" getter="get_loop_offset">
+ <member name="loop_offset" type="float" setter="set_loop_offset" getter="get_loop_offset" default="0.0">
</member>
</members>
<constants>
diff --git a/modules/svg/SCsub b/modules/svg/SCsub
index 90bfe22abb..9324c1634b 100644
--- a/modules/svg/SCsub
+++ b/modules/svg/SCsub
@@ -16,7 +16,7 @@ env_svg.Prepend(CPPPATH=[thirdparty_dir])
# FIXME: Needed in editor/editor_themes.cpp for now, but ideally there
# shouldn't be a dependency on modules/ and its own 3rd party deps.
env.Prepend(CPPPATH=[thirdparty_dir])
-env.Append(CPPFLAGS=["-DSVG_ENABLED"])
+env.Append(CPPDEFINES=["SVG_ENABLED"])
env_thirdparty = env_svg.Clone()
env_thirdparty.disable_warnings()
diff --git a/modules/theora/SCsub b/modules/theora/SCsub
index 785eca4c41..ff65d2f8ec 100644
--- a/modules/theora/SCsub
+++ b/modules/theora/SCsub
@@ -66,7 +66,7 @@ if env['builtin_libtheora']:
thirdparty_sources += thirdparty_sources_x86_vc
if (env["x86_libtheora_opt_gcc"] or env["x86_libtheora_opt_vc"]):
- env_theora.Append(CPPFLAGS=["-DOC_X86_ASM"])
+ env_theora.Append(CPPDEFINES=["OC_X86_ASM"])
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
diff --git a/modules/upnp/SCsub b/modules/upnp/SCsub
index 6d669ab73b..3f56a69594 100644
--- a/modules/upnp/SCsub
+++ b/modules/upnp/SCsub
@@ -23,10 +23,11 @@ if env['builtin_miniupnpc']:
"portlistingparse.c",
"upnpreplyparse.c",
]
- thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+ thirdparty_sources = [thirdparty_dir + "miniupnpc/" + file for file in thirdparty_sources]
env_upnp.Prepend(CPPPATH=[thirdparty_dir])
- env_upnp.Append(CPPFLAGS=["-DMINIUPNP_STATICLIB"])
+ env_upnp.Append(CPPDEFINES=["MINIUPNP_STATICLIB"])
+ env_upnp.Append(CPPDEFINES=["MINIUPNPC_SET_SOCKET_TIMEOUT"])
env_thirdparty = env_upnp.Clone()
env_thirdparty.disable_warnings()
diff --git a/modules/upnp/doc_classes/UPNP.xml b/modules/upnp/doc_classes/UPNP.xml
index d3eb21e159..aac0932995 100644
--- a/modules/upnp/doc_classes/UPNP.xml
+++ b/modules/upnp/doc_classes/UPNP.xml
@@ -134,13 +134,13 @@
</method>
</methods>
<members>
- <member name="discover_ipv6" type="bool" setter="set_discover_ipv6" getter="is_discover_ipv6">
+ <member name="discover_ipv6" type="bool" setter="set_discover_ipv6" getter="is_discover_ipv6" default="false">
If [code]true[/code], IPv6 is used for [UPNPDevice] discovery.
</member>
- <member name="discover_local_port" type="int" setter="set_discover_local_port" getter="get_discover_local_port">
+ <member name="discover_local_port" type="int" setter="set_discover_local_port" getter="get_discover_local_port" default="0">
If [code]0[/code], the local port to use for discovery is chosen automatically by the system. If [code]1[/code], discovery will be done from the source port 1900 (same as destination port). Otherwise, the value will be used as the port.
</member>
- <member name="discover_multicast_if" type="String" setter="set_discover_multicast_if" getter="get_discover_multicast_if">
+ <member name="discover_multicast_if" type="String" setter="set_discover_multicast_if" getter="get_discover_multicast_if" default="&quot;&quot;">
Multicast interface to use for discovery. Uses the default multicast interface if empty.
</member>
</members>
diff --git a/modules/upnp/doc_classes/UPNPDevice.xml b/modules/upnp/doc_classes/UPNPDevice.xml
index 1d9a728365..4d3a0f4f1d 100644
--- a/modules/upnp/doc_classes/UPNPDevice.xml
+++ b/modules/upnp/doc_classes/UPNPDevice.xml
@@ -53,22 +53,22 @@
</method>
</methods>
<members>
- <member name="description_url" type="String" setter="set_description_url" getter="get_description_url">
+ <member name="description_url" type="String" setter="set_description_url" getter="get_description_url" default="&quot;&quot;">
URL to the device description.
</member>
- <member name="igd_control_url" type="String" setter="set_igd_control_url" getter="get_igd_control_url">
+ <member name="igd_control_url" type="String" setter="set_igd_control_url" getter="get_igd_control_url" default="&quot;&quot;">
IDG control URL.
</member>
- <member name="igd_our_addr" type="String" setter="set_igd_our_addr" getter="get_igd_our_addr">
+ <member name="igd_our_addr" type="String" setter="set_igd_our_addr" getter="get_igd_our_addr" default="&quot;&quot;">
Address of the local machine in the network connecting it to this [UPNPDevice].
</member>
- <member name="igd_service_type" type="String" setter="set_igd_service_type" getter="get_igd_service_type">
+ <member name="igd_service_type" type="String" setter="set_igd_service_type" getter="get_igd_service_type" default="&quot;&quot;">
IGD service type.
</member>
- <member name="igd_status" type="int" setter="set_igd_status" getter="get_igd_status" enum="UPNPDevice.IGDStatus">
+ <member name="igd_status" type="int" setter="set_igd_status" getter="get_igd_status" enum="UPNPDevice.IGDStatus" default="9">
IGD status. See [enum IGDStatus].
</member>
- <member name="service_type" type="String" setter="set_service_type" getter="get_service_type">
+ <member name="service_type" type="String" setter="set_service_type" getter="get_service_type" default="&quot;&quot;">
Service type.
</member>
</members>
diff --git a/modules/vhacd/SCsub b/modules/vhacd/SCsub
index 161aed2eb9..e581fb7bb2 100644
--- a/modules/vhacd/SCsub
+++ b/modules/vhacd/SCsub
@@ -10,22 +10,21 @@ env_vhacd = env_modules.Clone()
thirdparty_dir = "#thirdparty/vhacd/"
thirdparty_sources = [
-"src/vhacdManifoldMesh.cpp",
-"src/FloatMath.cpp",
-"src/vhacdMesh.cpp",
-"src/vhacdICHull.cpp",
-"src/vhacdVolume.cpp",
-"src/VHACD-ASYNC.cpp",
-"src/btAlignedAllocator.cpp",
-"src/vhacdRaycastMesh.cpp",
-"src/VHACD.cpp",
-"src/btConvexHullComputer.cpp"
+ "src/vhacdManifoldMesh.cpp",
+ "src/FloatMath.cpp",
+ "src/vhacdMesh.cpp",
+ "src/vhacdICHull.cpp",
+ "src/vhacdVolume.cpp",
+ "src/VHACD-ASYNC.cpp",
+ "src/btAlignedAllocator.cpp",
+ "src/vhacdRaycastMesh.cpp",
+ "src/VHACD.cpp",
+ "src/btConvexHullComputer.cpp"
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_vhacd.Prepend(CPPPATH=[thirdparty_dir + "/inc"])
-env_vhacd.Append(CPPFLAGS=["-DGODOT_ENET"])
# upstream uses c++11
if not env.msvc:
diff --git a/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml b/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
index b591dc9a51..6dc54dbc03 100644
--- a/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
@@ -11,7 +11,7 @@
<methods>
</methods>
<members>
- <member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type">
+ <member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type" default="0">
The type to get the constant from.
</member>
<member name="constant" type="String" setter="set_basic_type_constant" getter="get_basic_type_constant">
diff --git a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
index 7add0bc2ba..470a3a5e35 100644
--- a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
+++ b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
@@ -12,7 +12,7 @@
<methods>
</methods>
<members>
- <member name="function" type="int" setter="set_func" getter="get_func" enum="VisualScriptBuiltinFunc.BuiltinFunc">
+ <member name="function" type="int" setter="set_func" getter="get_func" enum="VisualScriptBuiltinFunc.BuiltinFunc" default="0">
The function to be executed.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
index 7d83cd0203..49ea7850ef 100644
--- a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
@@ -15,10 +15,10 @@
<methods>
</methods>
<members>
- <member name="base_type" type="String" setter="set_base_type" getter="get_base_type">
+ <member name="base_type" type="String" setter="set_base_type" getter="get_base_type" default="&quot;Object&quot;">
The constant's parent class.
</member>
- <member name="constant" type="String" setter="set_class_constant" getter="get_class_constant">
+ <member name="constant" type="String" setter="set_class_constant" getter="get_class_constant" default="&quot;&quot;">
The constant to return. See the given class for its available constants.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptComment.xml b/modules/visual_script/doc_classes/VisualScriptComment.xml
index 9652654610..2538bc8356 100644
--- a/modules/visual_script/doc_classes/VisualScriptComment.xml
+++ b/modules/visual_script/doc_classes/VisualScriptComment.xml
@@ -12,13 +12,13 @@
<methods>
</methods>
<members>
- <member name="description" type="String" setter="set_description" getter="get_description">
+ <member name="description" type="String" setter="set_description" getter="get_description" default="&quot;&quot;">
The text inside the comment node.
</member>
- <member name="size" type="Vector2" setter="set_size" getter="get_size">
+ <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2( 150, 150 )">
The comment node's size (in pixels).
</member>
- <member name="title" type="String" setter="set_title" getter="get_title">
+ <member name="title" type="String" setter="set_title" getter="get_title" default="&quot;Comment&quot;">
The comment node's title.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptConstant.xml b/modules/visual_script/doc_classes/VisualScriptConstant.xml
index b15af8e4ea..eb12fc3731 100644
--- a/modules/visual_script/doc_classes/VisualScriptConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptConstant.xml
@@ -15,7 +15,7 @@
<methods>
</methods>
<members>
- <member name="type" type="int" setter="set_constant_type" getter="get_constant_type" enum="Variant.Type">
+ <member name="type" type="int" setter="set_constant_type" getter="get_constant_type" enum="Variant.Type" default="0">
The constant's type.
</member>
<member name="value" type="Variant" setter="set_constant_value" getter="get_constant_value">
diff --git a/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml b/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml
index a0eed5b753..c8543287b4 100644
--- a/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml
+++ b/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml
@@ -11,7 +11,7 @@
<methods>
</methods>
<members>
- <member name="type" type="int" setter="set_deconstruct_type" getter="get_deconstruct_type" enum="Variant.Type">
+ <member name="type" type="int" setter="set_deconstruct_type" getter="get_deconstruct_type" enum="Variant.Type" default="0">
The type to deconstruct.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
index 623aa1ba86..1a567905a9 100644
--- a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
+++ b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
@@ -15,7 +15,7 @@
<methods>
</methods>
<members>
- <member name="signal" type="String" setter="set_signal" getter="get_signal">
+ <member name="signal" type="String" setter="set_signal" getter="get_signal" default="&quot;&quot;">
The signal to emit.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml b/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml
index 525389366a..05bd87ec22 100644
--- a/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml
+++ b/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml
@@ -11,7 +11,7 @@
<methods>
</methods>
<members>
- <member name="constant" type="String" setter="set_singleton" getter="get_singleton">
+ <member name="constant" type="String" setter="set_singleton" getter="get_singleton" default="&quot;&quot;">
The singleton's name.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
index e4d0bb7672..f7f86e8c80 100644
--- a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
+++ b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
@@ -11,23 +11,23 @@
<members>
<member name="base_script" type="String" setter="set_base_script" getter="get_base_script">
</member>
- <member name="base_type" type="String" setter="set_base_type" getter="get_base_type">
+ <member name="base_type" type="String" setter="set_base_type" getter="get_base_type" default="&quot;Object&quot;">
</member>
<member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type">
</member>
- <member name="call_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptFunctionCall.CallMode">
+ <member name="call_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptFunctionCall.CallMode" default="0">
</member>
- <member name="function" type="String" setter="set_function" getter="get_function">
+ <member name="function" type="String" setter="set_function" getter="get_function" default="&quot;&quot;">
</member>
<member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path">
</member>
- <member name="rpc_call_mode" type="int" setter="set_rpc_call_mode" getter="get_rpc_call_mode" enum="VisualScriptFunctionCall.RPCCallMode">
+ <member name="rpc_call_mode" type="int" setter="set_rpc_call_mode" getter="get_rpc_call_mode" enum="VisualScriptFunctionCall.RPCCallMode" default="0">
</member>
<member name="singleton" type="String" setter="set_singleton" getter="get_singleton">
</member>
<member name="use_default_args" type="int" setter="set_use_default_args" getter="get_use_default_args">
</member>
- <member name="validate" type="bool" setter="set_validate" getter="get_validate">
+ <member name="validate" type="bool" setter="set_validate" getter="get_validate" default="true">
</member>
</members>
<constants>
diff --git a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml b/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml
index 4099a351e6..6c70dc7dc4 100644
--- a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml
@@ -9,7 +9,7 @@
<methods>
</methods>
<members>
- <member name="constant" type="int" setter="set_global_constant" getter="get_global_constant">
+ <member name="constant" type="int" setter="set_global_constant" getter="get_global_constant" default="0">
</member>
</members>
<constants>
diff --git a/modules/visual_script/doc_classes/VisualScriptInputAction.xml b/modules/visual_script/doc_classes/VisualScriptInputAction.xml
index 4bd1430cf6..8c942813b2 100644
--- a/modules/visual_script/doc_classes/VisualScriptInputAction.xml
+++ b/modules/visual_script/doc_classes/VisualScriptInputAction.xml
@@ -9,9 +9,9 @@
<methods>
</methods>
<members>
- <member name="action" type="String" setter="set_action_name" getter="get_action_name">
+ <member name="action" type="String" setter="set_action_name" getter="get_action_name" default="&quot;&quot;">
</member>
- <member name="mode" type="int" setter="set_action_mode" getter="get_action_mode" enum="VisualScriptInputAction.Mode">
+ <member name="mode" type="int" setter="set_action_mode" getter="get_action_mode" enum="VisualScriptInputAction.Mode" default="0">
</member>
</members>
<constants>
diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
index 5d061ea79f..8c21c3f0bc 100644
--- a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
+++ b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
@@ -15,10 +15,10 @@
<methods>
</methods>
<members>
- <member name="type" type="int" setter="set_var_type" getter="get_var_type" enum="Variant.Type">
+ <member name="type" type="int" setter="set_var_type" getter="get_var_type" enum="Variant.Type" default="0">
The local variable's type.
</member>
- <member name="var_name" type="String" setter="set_var_name" getter="get_var_name">
+ <member name="var_name" type="String" setter="set_var_name" getter="get_var_name" default="&quot;new_local&quot;">
The local variable's name.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
index 049195d890..a981432cdb 100644
--- a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
@@ -17,10 +17,10 @@
<methods>
</methods>
<members>
- <member name="type" type="int" setter="set_var_type" getter="get_var_type" enum="Variant.Type">
+ <member name="type" type="int" setter="set_var_type" getter="get_var_type" enum="Variant.Type" default="0">
The local variable's type.
</member>
- <member name="var_name" type="String" setter="set_var_name" getter="get_var_name">
+ <member name="var_name" type="String" setter="set_var_name" getter="get_var_name" default="&quot;new_local&quot;">
The local variable's name.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptMathConstant.xml b/modules/visual_script/doc_classes/VisualScriptMathConstant.xml
index fb4e423f0e..3be392aef5 100644
--- a/modules/visual_script/doc_classes/VisualScriptMathConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptMathConstant.xml
@@ -15,7 +15,7 @@
<methods>
</methods>
<members>
- <member name="constant" type="int" setter="set_math_constant" getter="get_math_constant" enum="VisualScriptMathConstant.MathConstant">
+ <member name="constant" type="int" setter="set_math_constant" getter="get_math_constant" enum="VisualScriptMathConstant.MathConstant" default="0">
The math constant.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptOperator.xml b/modules/visual_script/doc_classes/VisualScriptOperator.xml
index a0827972e0..80449ac521 100644
--- a/modules/visual_script/doc_classes/VisualScriptOperator.xml
+++ b/modules/visual_script/doc_classes/VisualScriptOperator.xml
@@ -14,9 +14,9 @@
<methods>
</methods>
<members>
- <member name="operator" type="int" setter="set_operator" getter="get_operator" enum="Variant.Operator">
+ <member name="operator" type="int" setter="set_operator" getter="get_operator" enum="Variant.Operator" default="6">
</member>
- <member name="type" type="int" setter="set_typed" getter="get_typed" enum="Variant.Type">
+ <member name="type" type="int" setter="set_typed" getter="get_typed" enum="Variant.Type" default="0">
</member>
</members>
<constants>
diff --git a/modules/visual_script/doc_classes/VisualScriptPreload.xml b/modules/visual_script/doc_classes/VisualScriptPreload.xml
index b3b39691c9..05ed0ad1e5 100644
--- a/modules/visual_script/doc_classes/VisualScriptPreload.xml
+++ b/modules/visual_script/doc_classes/VisualScriptPreload.xml
@@ -15,7 +15,7 @@
<methods>
</methods>
<members>
- <member name="resource" type="Resource" setter="set_preload" getter="get_preload">
+ <member name="resource" type="Resource" setter="set_preload" getter="get_preload" default="null">
The [Resource] to load.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
index 697a31ca46..af1e8e68e8 100644
--- a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
@@ -11,7 +11,7 @@
<members>
<member name="base_script" type="String" setter="set_base_script" getter="get_base_script">
</member>
- <member name="base_type" type="String" setter="set_base_type" getter="get_base_type">
+ <member name="base_type" type="String" setter="set_base_type" getter="get_base_type" default="&quot;Object&quot;">
</member>
<member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type">
</member>
@@ -19,9 +19,9 @@
</member>
<member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path">
</member>
- <member name="property" type="String" setter="set_property" getter="get_property">
+ <member name="property" type="String" setter="set_property" getter="get_property" default="&quot;&quot;">
</member>
- <member name="set_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptPropertyGet.CallMode">
+ <member name="set_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptPropertyGet.CallMode" default="0">
</member>
</members>
<constants>
diff --git a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
index c41e3781d4..380c196caf 100644
--- a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
@@ -9,11 +9,11 @@
<methods>
</methods>
<members>
- <member name="assign_op" type="int" setter="set_assign_op" getter="get_assign_op" enum="VisualScriptPropertySet.AssignOp">
+ <member name="assign_op" type="int" setter="set_assign_op" getter="get_assign_op" enum="VisualScriptPropertySet.AssignOp" default="0">
</member>
<member name="base_script" type="String" setter="set_base_script" getter="get_base_script">
</member>
- <member name="base_type" type="String" setter="set_base_type" getter="get_base_type">
+ <member name="base_type" type="String" setter="set_base_type" getter="get_base_type" default="&quot;Object&quot;">
</member>
<member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type">
</member>
@@ -21,9 +21,9 @@
</member>
<member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path">
</member>
- <member name="property" type="String" setter="set_property" getter="get_property">
+ <member name="property" type="String" setter="set_property" getter="get_property" default="&quot;&quot;">
</member>
- <member name="set_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptPropertySet.CallMode">
+ <member name="set_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptPropertySet.CallMode" default="0">
</member>
</members>
<constants>
diff --git a/modules/visual_script/doc_classes/VisualScriptResourcePath.xml b/modules/visual_script/doc_classes/VisualScriptResourcePath.xml
index 40862b810b..da37bbbb2c 100644
--- a/modules/visual_script/doc_classes/VisualScriptResourcePath.xml
+++ b/modules/visual_script/doc_classes/VisualScriptResourcePath.xml
@@ -9,7 +9,7 @@
<methods>
</methods>
<members>
- <member name="path" type="String" setter="set_resource_path" getter="get_resource_path">
+ <member name="path" type="String" setter="set_resource_path" getter="get_resource_path" default="&quot;&quot;">
</member>
</members>
<constants>
diff --git a/modules/visual_script/doc_classes/VisualScriptReturn.xml b/modules/visual_script/doc_classes/VisualScriptReturn.xml
index 40c8963efe..9a81c671d4 100644
--- a/modules/visual_script/doc_classes/VisualScriptReturn.xml
+++ b/modules/visual_script/doc_classes/VisualScriptReturn.xml
@@ -16,10 +16,10 @@
<methods>
</methods>
<members>
- <member name="return_enabled" type="bool" setter="set_enable_return_value" getter="is_return_value_enabled">
+ <member name="return_enabled" type="bool" setter="set_enable_return_value" getter="is_return_value_enabled" default="false">
If [code]true[/code], the [code]return[/code] input port is available.
</member>
- <member name="return_type" type="int" setter="set_return_type" getter="get_return_type" enum="Variant.Type">
+ <member name="return_type" type="int" setter="set_return_type" getter="get_return_type" enum="Variant.Type" default="0">
The return value's data type.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptSceneNode.xml b/modules/visual_script/doc_classes/VisualScriptSceneNode.xml
index 81ef4ceedc..99f4acbd27 100644
--- a/modules/visual_script/doc_classes/VisualScriptSceneNode.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSceneNode.xml
@@ -15,7 +15,7 @@
<methods>
</methods>
<members>
- <member name="node_path" type="NodePath" setter="set_node_path" getter="get_node_path">
+ <member name="node_path" type="NodePath" setter="set_node_path" getter="get_node_path" default="NodePath(&quot;.&quot;)">
The node's path in the scene tree.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptSelect.xml b/modules/visual_script/doc_classes/VisualScriptSelect.xml
index 3b1e7f7f02..e6a6cd5a48 100644
--- a/modules/visual_script/doc_classes/VisualScriptSelect.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSelect.xml
@@ -17,7 +17,7 @@
<methods>
</methods>
<members>
- <member name="type" type="int" setter="set_typed" getter="get_typed" enum="Variant.Type">
+ <member name="type" type="int" setter="set_typed" getter="get_typed" enum="Variant.Type" default="0">
The input variables' type.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptSequence.xml b/modules/visual_script/doc_classes/VisualScriptSequence.xml
index 26af15b404..2ceceb199f 100644
--- a/modules/visual_script/doc_classes/VisualScriptSequence.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSequence.xml
@@ -17,7 +17,7 @@
<methods>
</methods>
<members>
- <member name="steps" type="int" setter="set_steps" getter="get_steps">
+ <member name="steps" type="int" setter="set_steps" getter="get_steps" default="1">
The number of steps in the sequence.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
index a9e920bca6..999a190a9a 100644
--- a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
+++ b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
@@ -9,9 +9,9 @@
<methods>
</methods>
<members>
- <member name="base_script" type="String" setter="set_base_script" getter="get_base_script">
+ <member name="base_script" type="String" setter="set_base_script" getter="get_base_script" default="&quot;&quot;">
</member>
- <member name="base_type" type="String" setter="set_base_type" getter="get_base_type">
+ <member name="base_type" type="String" setter="set_base_type" getter="get_base_type" default="&quot;Object&quot;">
</member>
</members>
<constants>
diff --git a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
index e1c7c4e4d4..40e461294b 100644
--- a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
@@ -15,7 +15,7 @@
<methods>
</methods>
<members>
- <member name="var_name" type="String" setter="set_variable" getter="get_variable">
+ <member name="var_name" type="String" setter="set_variable" getter="get_variable" default="&quot;&quot;">
The variable's name.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
index 7339482908..6c53ad61b4 100644
--- a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
@@ -16,7 +16,7 @@
<methods>
</methods>
<members>
- <member name="var_name" type="String" setter="set_variable" getter="get_variable">
+ <member name="var_name" type="String" setter="set_variable" getter="get_variable" default="&quot;&quot;">
The variable's name.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptYield.xml b/modules/visual_script/doc_classes/VisualScriptYield.xml
index 9f61a5f88c..c506e6db01 100644
--- a/modules/visual_script/doc_classes/VisualScriptYield.xml
+++ b/modules/visual_script/doc_classes/VisualScriptYield.xml
@@ -9,7 +9,7 @@
<methods>
</methods>
<members>
- <member name="mode" type="int" setter="set_yield_mode" getter="get_yield_mode" enum="VisualScriptYield.YieldMode">
+ <member name="mode" type="int" setter="set_yield_mode" getter="get_yield_mode" enum="VisualScriptYield.YieldMode" default="1">
</member>
<member name="wait_time" type="float" setter="set_wait_time" getter="get_wait_time">
</member>
diff --git a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
index 6791375182..b9d7aedaab 100644
--- a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
+++ b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
@@ -9,13 +9,13 @@
<methods>
</methods>
<members>
- <member name="base_type" type="String" setter="set_base_type" getter="get_base_type">
+ <member name="base_type" type="String" setter="set_base_type" getter="get_base_type" default="&quot;Object&quot;">
</member>
- <member name="call_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptYieldSignal.CallMode">
+ <member name="call_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptYieldSignal.CallMode" default="0">
</member>
<member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path">
</member>
- <member name="signal" type="String" setter="set_signal" getter="get_signal">
+ <member name="signal" type="String" setter="set_signal" getter="get_signal" default="&quot;&quot;">
</member>
</members>
<constants>
diff --git a/modules/visual_script/icons/icon_visual_script.svg b/modules/visual_script/icons/icon_visual_script.svg
new file mode 100644
index 0000000000..f6475d590e
--- /dev/null
+++ b/modules/visual_script/icons/icon_visual_script.svg
@@ -0,0 +1,6 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<g transform="translate(0 -1036.4)">
+<ellipse cx="3" cy="1039.4" r="2" fill="#6e6e6e"/>
+<path transform="translate(0 1036.4)" d="m7 1l-0.56445 2.2578a5 5 0 0 0 -0.68945 0.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -0.28516 0.68555l-2.2539 0.5625v2h5.2715a2 2 0 0 1 -0.27148 -1 2 2 0 0 1 2 -2 2 2 0 0 1 2 2 2 2 0 0 1 -0.26953 1h5.2695v-2l-2.2578-0.56445a5 5 0 0 0 -0.2793 -0.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -0.68555 -0.28516l-0.5625-2.2539h-2zm-4 9v6h2a3 3 0 0 0 3 -3v-3h-2v3a1 1 0 0 1 -1 1v-4h-2zm8 0a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324 -1 2 2 0 0 0 0 -2 2 2 0 0 0 -1.7324 -1h2v-2h-2z" fill="#e0e0e0"/>
+</g>
+</svg>
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 3ac170a935..4579644d49 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -1099,6 +1099,9 @@ void VisualScriptEditor::_expression_text_changed(const String &p_text, int p_id
void VisualScriptEditor::_available_node_doubleclicked() {
+ if (edited_func == String())
+ return;
+
TreeItem *item = nodes->get_selected();
if (!item)
@@ -1107,7 +1110,6 @@ void VisualScriptEditor::_available_node_doubleclicked() {
String which = item->get_metadata(0);
if (which == String())
return;
-
Vector2 ofs = graph->get_scroll_ofs() + graph->get_size() * 0.5;
if (graph->is_using_snap()) {
diff --git a/modules/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub
index c76585013c..14fa6c1268 100644
--- a/modules/webm/libvpx/SCsub
+++ b/modules/webm/libvpx/SCsub
@@ -323,7 +323,7 @@ if webm_cpu_x86:
elif cpu_bits == '64':
env_libvpx["ASCPU"] = 'X86_64'
- env_libvpx.Append(CPPFLAGS=['-DWEBM_X86ASM'])
+ env_libvpx.Append(CPPDEFINES=['WEBM_X86ASM'])
webm_simd_optimizations = True
@@ -337,7 +337,7 @@ if webm_cpu_arm:
env_libvpx["ASFLAGS"] = ''
env_libvpx["ASCOM"] = '$AS $ASFLAGS -o $TARGET $SOURCES'
- env_libvpx.Append(CPPFLAGS=['-DWEBM_ARMASM'])
+ env_libvpx.Append(CPPDEFINES=['WEBM_ARMASM'])
webm_simd_optimizations = True
diff --git a/modules/webrtc/doc_classes/WebRTCDataChannel.xml b/modules/webrtc/doc_classes/WebRTCDataChannel.xml
index 6d600f6239..98715ee99b 100644
--- a/modules/webrtc/doc_classes/WebRTCDataChannel.xml
+++ b/modules/webrtc/doc_classes/WebRTCDataChannel.xml
@@ -89,7 +89,7 @@
</method>
</methods>
<members>
- <member name="write_mode" type="int" setter="set_write_mode" getter="get_write_mode" enum="WebRTCDataChannel.WriteMode">
+ <member name="write_mode" type="int" setter="set_write_mode" getter="get_write_mode" enum="WebRTCDataChannel.WriteMode" default="1">
The transfer mode to use when sending outgoing packet. Either text or binary.
</member>
</members>
diff --git a/modules/webrtc/webrtc_data_channel_gdnative.cpp b/modules/webrtc/webrtc_data_channel_gdnative.cpp
index 4f33491af2..6362634626 100644
--- a/modules/webrtc/webrtc_data_channel_gdnative.cpp
+++ b/modules/webrtc/webrtc_data_channel_gdnative.cpp
@@ -35,6 +35,7 @@
#include "modules/gdnative/nativescript/nativescript.h"
void WebRTCDataChannelGDNative::_bind_methods() {
+ ADD_PROPERTY_DEFAULT("write_mode", WRITE_MODE_BINARY);
}
WebRTCDataChannelGDNative::WebRTCDataChannelGDNative() {
diff --git a/modules/websocket/SCsub b/modules/websocket/SCsub
index d9e60eb6f1..033169411f 100644
--- a/modules/websocket/SCsub
+++ b/modules/websocket/SCsub
@@ -5,89 +5,26 @@ Import('env_modules')
# Thirdparty source files
-env_lws = env_modules.Clone()
-
-if env['builtin_libwebsockets'] and not env["platform"] == "javascript": # already builtin for javascript
- thirdparty_dir = "#thirdparty/libwebsockets/"
- helper_dir = "win32helpers/"
- thirdparty_sources = [
-
- "core/alloc.c",
- "core/context.c",
- "core/libwebsockets.c",
- "core/output.c",
- "core/pollfd.c",
- "core/service.c",
-
- "event-libs/poll/poll.c",
-
- "misc/base64-decode.c",
- "misc/lejp.c",
- "misc/sha-1.c",
-
- "roles/h1/ops-h1.c",
- "roles/http/header.c",
- "roles/http/client/client.c",
- "roles/http/client/client-handshake.c",
- "roles/http/server/fops-zip.c",
- "roles/http/server/lejp-conf.c",
- "roles/http/server/parsers.c",
- "roles/http/server/server.c",
- "roles/listen/ops-listen.c",
- "roles/pipe/ops-pipe.c",
- "roles/raw/ops-raw.c",
-
- "roles/ws/client-ws.c",
- "roles/ws/client-parser-ws.c",
- "roles/ws/ops-ws.c",
- "roles/ws/server-ws.c",
-
- "tls/tls.c",
- "tls/tls-client.c",
- "tls/tls-server.c",
-
- "tls/mbedtls/wrapper/library/ssl_cert.c",
- "tls/mbedtls/wrapper/library/ssl_pkey.c",
- "tls/mbedtls/wrapper/library/ssl_stack.c",
- "tls/mbedtls/wrapper/library/ssl_methods.c",
- "tls/mbedtls/wrapper/library/ssl_lib.c",
- "tls/mbedtls/wrapper/library/ssl_x509.c",
- "tls/mbedtls/wrapper/platform/ssl_port.c",
- "tls/mbedtls/wrapper/platform/ssl_pm.c",
- "tls/mbedtls/lws-genhash.c",
- "tls/mbedtls/mbedtls-client.c",
- "tls/mbedtls/lws-genrsa.c",
- "tls/mbedtls/ssl.c",
- "tls/mbedtls/mbedtls-server.c"
+env_ws = env_modules.Clone()
+
+if env['builtin_wslay'] and not env["platform"] == "javascript": # already builtin for javascript
+ wslay_dir = "#thirdparty/wslay/"
+ wslay_sources = [
+ "wslay_net.c",
+ "wslay_event.c",
+ "wslay_queue.c",
+ "wslay_stack.c",
+ "wslay_frame.c",
]
-
- if env["platform"] == "android": # Builtin getifaddrs
- thirdparty_sources += ["misc/getifaddrs.c"]
-
- if env["platform"] == "windows" or env["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]
-
- env_lws.Prepend(CPPPATH=[thirdparty_dir])
-
- if env['builtin_mbedtls']:
- mbedtls_includes = "#thirdparty/mbedtls/include"
- env_lws.Prepend(CPPPATH=[mbedtls_includes])
-
- wrapper_includes = ["#thirdparty/libwebsockets/tls/mbedtls/wrapper/include/" + inc for inc in ["internal", "openssl", "platform", ""]]
- env_lws.Prepend(CPPPATH=wrapper_includes)
-
+ wslay_sources = [wslay_dir + s for s in wslay_sources]
+ env_ws.Prepend(CPPPATH=[wslay_dir + "includes/"])
+ env_ws.Append(CPPDEFINES=["HAVE_CONFIG_H"])
if env["platform"] == "windows" or env["platform"] == "uwp":
- env_lws.Prepend(CPPPATH=[thirdparty_dir + helper_dir])
-
- if env["platform"] == "uwp":
- env_lws.Append(CPPFLAGS=["/DLWS_MINGW_SUPPORT"])
-
- env_thirdparty = env_lws.Clone()
- env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
-
-env_lws.add_source_files(env.modules_sources, "*.cpp")
+ env_ws.Append(CPPDEFINES=["HAVE_WINSOCK2_H"])
+ else:
+ env_ws.Append(CPPDEFINES=["HAVE_NETINET_IN_H"])
+ env_wslay = env_ws.Clone()
+ env_wslay.disable_warnings()
+ env_wslay.add_source_files(env.modules_sources, wslay_sources)
+
+env_ws.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/websocket/doc_classes/WebSocketClient.xml b/modules/websocket/doc_classes/WebSocketClient.xml
index 0d425ad1dd..c3baf9de83 100644
--- a/modules/websocket/doc_classes/WebSocketClient.xml
+++ b/modules/websocket/doc_classes/WebSocketClient.xml
@@ -22,7 +22,7 @@
<argument index="2" name="gd_mp_api" type="bool" default="false">
</argument>
<description>
- Connects to the given URL requesting one of the given [code]protocols[/code] as sub-protocol.
+ Connects to the given URL requesting one of the given [code]protocols[/code] as sub-protocol. If the list empty (default), no sub-protocol will be requested.
If [code]true[/code] is passed as [code]gd_mp_api[/code], the client will behave like a network peer for the [MultiplayerAPI], connections to non-Godot servers will not work, and [signal data_received] will not be emitted.
If [code]false[/code] is passed instead (default), you must call [PacketPeer] functions ([code]put_packet[/code], [code]get_packet[/code], etc.) on the [WebSocketPeer] returned via [code]get_peer(1)[/code] and not on this object directly (e.g. [code]get_peer(1).put_packet(data)[/code]).
</description>
diff --git a/modules/websocket/doc_classes/WebSocketServer.xml b/modules/websocket/doc_classes/WebSocketServer.xml
index 1af5e403e6..63318e5874 100644
--- a/modules/websocket/doc_classes/WebSocketServer.xml
+++ b/modules/websocket/doc_classes/WebSocketServer.xml
@@ -69,7 +69,7 @@
</argument>
<description>
Starts listening on the given port.
- You can specify the desired subprotocols via the "protocols" array. If the list empty (default), "binary" will be used.
+ You can specify the desired subprotocols via the "protocols" array. If the list empty (default), no sub-protocol will be requested.
If [code]true[/code] is passed as [code]gd_mp_api[/code], the server will behave like a network peer for the [MultiplayerAPI], connections from non-Godot clients will not work, and [signal data_received] will not be emitted.
If [code]false[/code] is passed instead (default), you must call [PacketPeer] functions ([code]put_packet[/code], [code]get_packet[/code], etc.), on the [WebSocketPeer] returned via [code]get_peer(id)[/code] to communicate with the peer with given [code]id[/code] (e.g. [code]get_peer(id).get_available_packet_count[/code]).
</description>
diff --git a/modules/websocket/lws_client.cpp b/modules/websocket/lws_client.cpp
deleted file mode 100644
index f139a4ef66..0000000000
--- a/modules/websocket/lws_client.cpp
+++ /dev/null
@@ -1,248 +0,0 @@
-/*************************************************************************/
-/* lws_client.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 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"
-#include "core/project_settings.h"
-#if defined(LWS_OPENSSL_SUPPORT)
-#include "core/io/stream_peer_ssl.h"
-#include "tls/mbedtls/wrapper/include/openssl/ssl.h"
-#endif
-
-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
- _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;
-#if defined(LWS_OPENSSL_SUPPORT)
- info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
-#endif
- 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);
- }
-
- i.context = context;
- if (p_protocols.size() > 0)
- i.protocol = _lws_ref->lws_names;
- else
- i.protocol = NULL;
-
- if (p_ssl) {
- i.ssl_connection = LCCSCF_USE_SSL;
- if (!verify_ssl)
- i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
- } else {
- i.ssl_connection = 0;
- }
-
- // These CharStrings needs to survive till we call lws_client_connect_via_info
- CharString addr_ch = ((String)addr).ascii();
- CharString host_ch = p_host.utf8();
- CharString path_ch = p_path.utf8();
- i.address = addr_ch.get_data();
- i.host = host_ch.get_data();
- i.path = path_ch.get_data();
- i.port = p_port;
-
- lws_client_connect_via_info(&i);
-
- return OK;
-};
-
-int LWSClient::get_max_packet_size() const {
- return (1 << _out_buf_size) - PROTO_SIZE;
-}
-
-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) {
-#if defined(LWS_OPENSSL_SUPPORT)
- case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: {
- PoolByteArray arr = StreamPeerSSL::get_project_cert_array();
- if (arr.size() > 0)
- SSL_CTX_add_client_CA((SSL_CTX *)user, d2i_X509(NULL, &arr.read()[0], arr.size()));
- else if (verify_ssl)
- WARN_PRINTS("No CA cert specified in project settings, SSL will not work");
- } break;
-#endif
- case LWS_CALLBACK_CLIENT_ESTABLISHED:
- peer->set_wsi(wsi, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size);
- peer_data->peer_id = 0;
- peer_data->force_close = false;
- peer_data->clean_close = false;
- _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_WS_PEER_INITIATED_CLOSE: {
- int code;
- String reason2 = peer->get_close_reason(in, len, code);
- peer_data->clean_close = true;
- _on_close_request(code, reason2);
- return 0;
- }
-
- case LWS_CALLBACK_CLIENT_CLOSED:
- peer->close();
- destroy_context();
- _on_disconnect(peer_data->clean_close);
- 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) {
- peer->send_close_status(wsi);
- 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(int p_code, String p_reason) {
-
- if (context == NULL)
- return;
-
- _peer->close(p_code, p_reason);
-};
-
-IP_Address LWSClient::get_connected_host() const {
-
- return IP_Address();
-};
-
-uint16_t LWSClient::get_connected_port() const {
-
- return 1025;
-};
-
-Error LWSClient::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) {
- ERR_EXPLAIN("Buffers sizes can only be set before listening or connecting");
- ERR_FAIL_COND_V(context != NULL, FAILED);
-
- _in_buf_size = nearest_shift(p_in_buffer - 1) + 10;
- _in_pkt_size = nearest_shift(p_in_packets - 1);
- _out_buf_size = nearest_shift(p_out_buffer - 1) + 10;
- _out_pkt_size = nearest_shift(p_out_packets - 1);
- return OK;
-}
-
-LWSClient::LWSClient() {
- _in_buf_size = nearest_shift((int)GLOBAL_GET(WSC_IN_BUF) - 1) + 10;
- _in_pkt_size = nearest_shift((int)GLOBAL_GET(WSC_IN_PKT) - 1);
- _out_buf_size = nearest_shift((int)GLOBAL_GET(WSC_OUT_BUF) - 1) + 10;
- _out_pkt_size = nearest_shift((int)GLOBAL_GET(WSC_OUT_PKT) - 1);
-
- context = NULL;
- _lws_ref = NULL;
- _peer = Ref<LWSPeer>(memnew(LWSPeer));
-};
-
-LWSClient::~LWSClient() {
-
- invalidate_lws_ref(); // We do not want any more callback
- disconnect_from_host();
- destroy_context();
- _peer = Ref<LWSPeer>();
-};
-
-#endif // JAVASCRIPT_ENABLED
diff --git a/modules/websocket/lws_helper.cpp b/modules/websocket/lws_helper.cpp
deleted file mode 100644
index a652779960..0000000000
--- a/modules/websocket/lws_helper.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/*************************************************************************/
-/* lws_helper.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 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. */
-/*************************************************************************/
-
-#if !defined(JAVASCRIPT_ENABLED)
-
-#include "lws_helper.h"
-
-_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;
-}
-
-void _lws_free_ref(_LWSRef *ref) {
- // Free strings and structs
- memfree(ref->lws_structs);
- memfree(ref->lws_names);
- // Free ref
- memfree(ref);
-}
-
-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;
-}
-
-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.
- */
-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.
- // We 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));
- memset(ref->lws_structs, 0, 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;
-
- // Comma separated protocols string to be used in client Sec-WebSocket-Protocol header
- if (str_len > 0)
- copymem(names_ptr, strings.get_data(), str_len);
- names_ptr[str_len] = '\0'; // NULL terminator
-
- // NULL terminated protocol strings to be used in protocol structs
- if (str_len > 0)
- 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 the default for any http request (before upgrade).
- // It is also used as the websocket protocol when no subprotocol is specified.
- structs_ptr[0].name = "default";
- structs_ptr[0].callback = p_callback;
- structs_ptr[0].per_session_data_size = data_size;
- structs_ptr[0].rx_buffer_size = LWS_BUF_SIZE;
- structs_ptr[0].tx_packet_size = LWS_PACKET_SIZE;
- // 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 = LWS_BUF_SIZE;
- structs_ptr[i + 1].tx_packet_size = LWS_PACKET_SIZE;
- 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;
-}
-
-#endif
diff --git a/modules/websocket/lws_helper.h b/modules/websocket/lws_helper.h
deleted file mode 100644
index 265dc4e6ad..0000000000
--- a/modules/websocket/lws_helper.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*************************************************************************/
-/* lws_helper.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 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
-
-#define LWS_BUF_SIZE 65536
-#define LWS_PACKET_SIZE LWS_BUF_SIZE
-
-#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;
-};
-
-_LWSRef *_lws_create_ref(void *obj);
-void _lws_free_ref(_LWSRef *ref);
-bool _lws_destroy(struct lws_context *context, _LWSRef *ref);
-bool _lws_poll(struct lws_context *context, _LWSRef *ref);
-void _lws_make_protocols(void *p_obj, lws_callback_function *p_callback, PoolVector<String> p_names, _LWSRef **r_lws_ref);
-
-/* clang-format off */
-#define LWS_HELPER(CNAME) \
-protected: \
- struct _LWSRef *_lws_ref; \
- struct lws_context *context; \
- bool _keep_servicing; \
- \
- 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; \
- helper->_keep_servicing = true; \
- 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); \
- do { \
- _keep_servicing = false; \
- if (::_lws_poll(context, _lws_ref)) { \
- context = NULL; \
- _lws_ref = NULL; \
- break; \
- } \
- } while (_keep_servicing); \
- } \
- \
-protected:
-
-/* clang-format on */
-
-#endif // LWS_HELPER_H
diff --git a/modules/websocket/lws_peer.cpp b/modules/websocket/lws_peer.cpp
deleted file mode 100644
index a7c85450fa..0000000000
--- a/modules/websocket/lws_peer.cpp
+++ /dev/null
@@ -1,270 +0,0 @@
-/*************************************************************************/
-/* lws_peer.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 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"
-
-// Needed for socket_helpers on Android at least. UNIXes has it, just include if not windows
-#if !defined(WINDOWS_ENABLED)
-#include <netinet/in.h>
-#include <sys/socket.h>
-#endif
-
-#include "drivers/unix/net_socket_posix.h"
-
-void LWSPeer::set_wsi(struct lws *p_wsi, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size, unsigned int p_out_pkt_size) {
- ERR_FAIL_COND(wsi != NULL);
-
- _in_buffer.resize(p_in_pkt_size, p_in_buf_size);
- _out_buffer.resize(p_out_pkt_size, p_out_buf_size);
- _packet_buffer.resize((1 << MAX(p_in_buf_size, p_out_buf_size)) + LWS_PRE);
- wsi = p_wsi;
-};
-
-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);
-
- if (lws_is_first_fragment(wsi))
- _in_size = 0;
- else if (_in_size == -1) // Trash this frame
- return ERR_FILE_CORRUPT;
-
- Error err = _in_buffer.write_packet((const uint8_t *)in, len, NULL);
-
- if (err != OK) {
- _in_buffer.discard_payload(_in_size);
- _in_size = -1;
- ERR_FAIL_V(err);
- }
-
- _in_size += len;
-
- if (lws_is_final_fragment(wsi)) {
- uint8_t is_string = lws_frame_is_binary(wsi) ? 0 : 1;
- err = _in_buffer.write_packet(NULL, _in_size, &is_string);
- if (err != OK) {
- _in_buffer.discard_payload(_in_size);
- _in_size = -1;
- ERR_FAIL_V(err);
- }
- }
-
- return OK;
-}
-
-Error LWSPeer::write_wsi() {
-
- ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
-
- PoolVector<uint8_t> tmp;
- int count = _out_buffer.packets_left();
-
- if (count == 0)
- return OK;
-
- int read = 0;
- uint8_t is_string = 0;
- PoolVector<uint8_t>::Write rw = _packet_buffer.write();
- _out_buffer.read_packet(&(rw[LWS_PRE]), _packet_buffer.size() - LWS_PRE, &is_string, read);
-
- enum lws_write_protocol mode = is_string ? LWS_WRITE_TEXT : LWS_WRITE_BINARY;
- lws_write(wsi, &(rw[LWS_PRE]), read, mode);
-
- if (count > 1)
- 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);
-
- uint8_t is_string = write_mode == WRITE_MODE_TEXT;
- _out_buffer.write_packet(p_buffer, p_buffer_size, &is_string);
- lws_callback_on_writable(wsi); // notify that we want to write
- return OK;
-};
-
-Error LWSPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
-
- r_buffer_size = 0;
-
- ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
-
- if (_in_buffer.packets_left() == 0)
- return ERR_UNAVAILABLE;
-
- int read = 0;
- PoolVector<uint8_t>::Write rw = _packet_buffer.write();
- _in_buffer.read_packet(rw.ptr(), _packet_buffer.size(), &_is_string, read);
-
- *r_buffer = rw.ptr();
- r_buffer_size = read;
-
- return OK;
-};
-
-int LWSPeer::get_available_packet_count() const {
-
- if (!is_connected_to_host())
- return 0;
-
- return _in_buffer.packets_left();
-};
-
-bool LWSPeer::was_string_packet() const {
-
- return _is_string;
-};
-
-bool LWSPeer::is_connected_to_host() const {
-
- return wsi != NULL;
-};
-
-String LWSPeer::get_close_reason(void *in, size_t len, int &r_code) {
- String s;
- r_code = 0;
- if (len < 2) // From docs this should not happen
- return s;
-
- const uint8_t *b = (const uint8_t *)in;
- r_code = b[0] << 8 | b[1];
-
- if (len > 2) {
- const char *utf8 = (const char *)&b[2];
- s.parse_utf8(utf8, len - 2);
- }
- return s;
-}
-
-void LWSPeer::send_close_status(struct lws *p_wsi) {
- if (close_code == -1)
- return;
-
- int len = close_reason.size();
- ERR_FAIL_COND(len > 123); // Maximum allowed reason size in bytes
-
- lws_close_status code = (lws_close_status)close_code;
- unsigned char *reason = len > 0 ? (unsigned char *)close_reason.utf8().ptrw() : NULL;
-
- lws_close_reason(p_wsi, code, reason, len);
-
- close_code = -1;
- close_reason = "";
-}
-
-void LWSPeer::close(int p_code, String p_reason) {
- if (wsi != NULL) {
- close_code = p_code;
- close_reason = p_reason;
- PeerData *data = ((PeerData *)lws_wsi_user(wsi));
- data->force_close = true;
- data->clean_close = true;
- lws_callback_on_writable(wsi); // Notify that we want to disconnect
- } else {
- close_code = -1;
- close_reason = "";
- }
- wsi = NULL;
- _in_buffer.clear();
- _out_buffer.clear();
- _in_size = 0;
- _is_string = 0;
- _packet_buffer.resize(0);
-};
-
-IP_Address LWSPeer::get_connected_host() const {
-
- ERR_FAIL_COND_V(!is_connected_to_host(), IP_Address());
-
- IP_Address ip;
- uint16_t port = 0;
-
- struct sockaddr_storage addr;
- socklen_t len = sizeof(addr);
-
- int fd = lws_get_socket_fd(wsi);
- ERR_FAIL_COND_V(fd == -1, IP_Address());
-
- int ret = getpeername(fd, (struct sockaddr *)&addr, &len);
- ERR_FAIL_COND_V(ret != 0, IP_Address());
-
- NetSocketPosix::_set_ip_port(&addr, ip, port);
-
- return ip;
-};
-
-uint16_t LWSPeer::get_connected_port() const {
-
- ERR_FAIL_COND_V(!is_connected_to_host(), 0);
-
- IP_Address ip;
- uint16_t port = 0;
-
- struct sockaddr_storage addr;
- socklen_t len = sizeof(addr);
-
- int fd = lws_get_socket_fd(wsi);
- ERR_FAIL_COND_V(fd == -1, 0);
-
- int ret = getpeername(fd, (struct sockaddr *)&addr, &len);
- ERR_FAIL_COND_V(ret != 0, 0);
-
- NetSocketPosix::_set_ip_port(&addr, ip, port);
-
- return port;
-};
-
-LWSPeer::LWSPeer() {
- wsi = NULL;
- write_mode = WRITE_MODE_BINARY;
- close();
-};
-
-LWSPeer::~LWSPeer() {
-
- close();
-};
-
-#endif // JAVASCRIPT_ENABLED
diff --git a/modules/websocket/lws_server.cpp b/modules/websocket/lws_server.cpp
deleted file mode 100644
index 482c02dc60..0000000000
--- a/modules/websocket/lws_server.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-/*************************************************************************/
-/* lws_server.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 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"
-#include "core/project_settings.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);
-
- // 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::get_max_packet_size() const {
- return (1 << _out_buf_size) - PROTO_SIZE;
-}
-
-int LWSServer::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
-
- LWSPeer::PeerData *peer_data = (LWSPeer::PeerData *)user;
-
- 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, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size);
- _peer_map[id] = peer;
-
- peer_data->peer_id = id;
- peer_data->force_close = false;
- peer_data->clean_close = false;
- _on_connect(id, lws_get_protocol(wsi)->name);
- break;
- }
-
- case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: {
- if (peer_data == NULL)
- return 0;
-
- int32_t id = peer_data->peer_id;
- if (_peer_map.has(id)) {
- int code;
- Ref<LWSPeer> peer = _peer_map[id];
- String reason2 = peer->get_close_reason(in, len, code);
- peer_data->clean_close = true;
- _on_close_request(id, code, reason2);
- }
- return 0;
- }
-
- case LWS_CALLBACK_CLOSED: {
- if (peer_data == NULL)
- return 0;
- int32_t id = peer_data->peer_id;
- bool clean = peer_data->clean_close;
- if (_peer_map.has(id)) {
- _peer_map[id]->close();
- _peer_map.erase(id);
- }
- _on_disconnect(id, clean);
- 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: {
- int id = peer_data->peer_id;
- if (peer_data->force_close) {
- if (_peer_map.has(id)) {
- Ref<LWSPeer> peer = _peer_map[id];
- peer->send_close_status(wsi);
- }
- return -1;
- }
-
- 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];
-}
-
-IP_Address LWSServer::get_peer_address(int p_peer_id) const {
- ERR_FAIL_COND_V(!has_peer(p_peer_id), IP_Address());
-
- return _peer_map[p_peer_id]->get_connected_host();
-}
-
-int LWSServer::get_peer_port(int p_peer_id) const {
- ERR_FAIL_COND_V(!has_peer(p_peer_id), 0);
-
- return _peer_map[p_peer_id]->get_connected_port();
-}
-
-void LWSServer::disconnect_peer(int p_peer_id, int p_code, String p_reason) {
- ERR_FAIL_COND(!has_peer(p_peer_id));
-
- get_peer(p_peer_id)->close(p_code, p_reason);
-}
-
-Error LWSServer::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) {
- ERR_EXPLAIN("Buffers sizes can only be set before listening or connecting");
- ERR_FAIL_COND_V(context != NULL, FAILED);
-
- _in_buf_size = nearest_shift(p_in_buffer - 1) + 10;
- _in_pkt_size = nearest_shift(p_in_packets - 1);
- _out_buf_size = nearest_shift(p_out_buffer - 1) + 10;
- _out_pkt_size = nearest_shift(p_out_packets - 1);
- return OK;
-}
-
-LWSServer::LWSServer() {
- _in_buf_size = nearest_shift((int)GLOBAL_GET(WSS_IN_BUF) - 1) + 10;
- _in_pkt_size = nearest_shift((int)GLOBAL_GET(WSS_IN_PKT) - 1);
- _out_buf_size = nearest_shift((int)GLOBAL_GET(WSS_OUT_BUF) - 1) + 10;
- _out_pkt_size = nearest_shift((int)GLOBAL_GET(WSS_OUT_PKT) - 1);
- context = NULL;
- _lws_ref = NULL;
-}
-
-LWSServer::~LWSServer() {
- invalidate_lws_ref(); // we do not want any more callbacks
- stop();
-}
-
-#endif // JAVASCRIPT_ENABLED
diff --git a/modules/websocket/register_types.cpp b/modules/websocket/register_types.cpp
index 39bf3de982..1c808f0d5c 100644
--- a/modules/websocket/register_types.cpp
+++ b/modules/websocket/register_types.cpp
@@ -37,9 +37,8 @@
#include "emws_peer.h"
#include "emws_server.h"
#else
-#include "lws_client.h"
-#include "lws_peer.h"
-#include "lws_server.h"
+#include "wsl_client.h"
+#include "wsl_server.h"
#endif
void register_websocket_types() {
@@ -64,9 +63,9 @@ void register_websocket_types() {
EMWSClient::make_default();
EMWSServer::make_default();
#else
- LWSPeer::make_default();
- LWSClient::make_default();
- LWSServer::make_default();
+ WSLPeer::make_default();
+ WSLClient::make_default();
+ WSLServer::make_default();
#endif
ClassDB::register_virtual_class<WebSocketMultiplayerPeer>();
diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp
new file mode 100644
index 0000000000..b2d865a58f
--- /dev/null
+++ b/modules/websocket/wsl_client.cpp
@@ -0,0 +1,362 @@
+/*************************************************************************/
+/* wsl_client.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 "wsl_client.h"
+#include "core/io/ip.h"
+#include "core/project_settings.h"
+
+void WSLClient::_do_handshake() {
+ if (_requested < _request.size() - 1) {
+ int sent = 0;
+ Error err = _connection->put_partial_data(((const uint8_t *)_request.get_data() + _requested), _request.size() - _requested - 1, sent);
+ // Sending handshake failed
+ if (err != OK) {
+ disconnect_from_host();
+ _on_error();
+ return;
+ }
+ _requested += sent;
+
+ } else {
+ int read = 0;
+ while (true) {
+ if (_resp_pos >= WSL_MAX_HEADER_SIZE) {
+ // Header is too big
+ disconnect_from_host();
+ _on_error();
+ ERR_EXPLAIN("Response headers too big");
+ ERR_FAIL();
+ }
+ Error err = _connection->get_partial_data(&_resp_buf[_resp_pos], 1, read);
+ if (err == ERR_FILE_EOF) {
+ // We got a disconnect.
+ disconnect_from_host();
+ _on_error();
+ return;
+ } else if (err != OK) {
+ // Got some error.
+ disconnect_from_host();
+ _on_error();
+ return;
+ } else if (read != 1) {
+ // Busy, wait next poll.
+ break;
+ }
+ // Check "\r\n\r\n" header terminator
+ char *r = (char *)_resp_buf;
+ int l = _resp_pos;
+ if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') {
+ r[l - 3] = '\0';
+ String protocol;
+ // Response is over, verify headers and create peer.
+ if (!_verify_headers(protocol)) {
+ disconnect_from_host();
+ _on_error();
+ ERR_EXPLAIN("Invalid response headers");
+ ERR_FAIL();
+ }
+ // Create peer.
+ WSLPeer::PeerData *data = memnew(struct WSLPeer::PeerData);
+ data->obj = this;
+ data->conn = _connection;
+ data->is_server = false;
+ data->id = 1;
+ _peer->make_context(data, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size);
+ _on_connect(protocol);
+ }
+ _resp_pos += 1;
+ }
+ }
+}
+
+bool WSLClient::_verify_headers(String &r_protocol) {
+ String s = (char *)_resp_buf;
+ Vector<String> psa = s.split("\r\n");
+ int len = psa.size();
+ if (len < 4) {
+ ERR_EXPLAIN("Not enough response headers.");
+ ERR_FAIL_V(false);
+ }
+
+ Vector<String> req = psa[0].split(" ", false);
+ if (req.size() < 2) {
+ ERR_EXPLAIN("Invalid protocol or status code.");
+ ERR_FAIL_V(false);
+ }
+ // Wrong protocol
+ if (req[0] != "HTTP/1.1" || req[1] != "101") {
+ ERR_EXPLAIN("Invalid protocol or status code.");
+ ERR_FAIL_V(false);
+ }
+
+ Map<String, String> headers;
+ for (int i = 1; i < len; i++) {
+ Vector<String> header = psa[i].split(":", false, 1);
+ if (header.size() != 2) {
+ ERR_EXPLAIN("Invalid header -> " + psa[i]);
+ ERR_FAIL_V(false);
+ }
+ String name = header[0].to_lower();
+ String value = header[1].strip_edges();
+ if (headers.has(name))
+ headers[name] += "," + value;
+ else
+ headers[name] = value;
+ }
+
+#define _WLS_EXPLAIN(NAME, VALUE) \
+ ERR_EXPLAIN("Missing or invalid header '" + String(NAME) + "'. Expected value '" + VALUE + "'");
+#define _WLS_CHECK(NAME, VALUE) \
+ _WLS_EXPLAIN(NAME, VALUE); \
+ ERR_FAIL_COND_V(!headers.has(NAME) || headers[NAME].to_lower() != VALUE, false);
+#define _WLS_CHECK_NC(NAME, VALUE) \
+ _WLS_EXPLAIN(NAME, VALUE); \
+ ERR_FAIL_COND_V(!headers.has(NAME) || headers[NAME] != VALUE, false);
+ _WLS_CHECK("connection", "upgrade");
+ _WLS_CHECK("upgrade", "websocket");
+ _WLS_CHECK_NC("sec-websocket-accept", WSLPeer::compute_key_response(_key));
+ if (_protocols.size() == 0) {
+ // We didn't request a custom protocol
+ ERR_FAIL_COND_V(headers.has("sec-websocket-protocol"), false);
+ } else {
+ ERR_FAIL_COND_V(!headers.has("sec-websocket-protocol"), false);
+ r_protocol = headers["sec-websocket-protocol"];
+ bool valid = false;
+ for (int i = 0; i < _protocols.size(); i++) {
+ if (_protocols[i] != r_protocol)
+ continue;
+ valid = true;
+ break;
+ }
+ if (!valid)
+ return false;
+ }
+#undef _WLS_CHECK_NC
+#undef _WLS_CHECK
+#undef _WLS_EXPLAIN
+
+ return true;
+}
+
+Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocols) {
+
+ ERR_FAIL_COND_V(_connection.is_valid(), ERR_ALREADY_IN_USE);
+
+ _peer = Ref<WSLPeer>(memnew(WSLPeer));
+ 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);
+
+ String port = "";
+ if ((p_port != 80 && !p_ssl) || (p_port != 443 && p_ssl)) {
+ port = ":" + itos(p_port);
+ }
+
+ Error err = _tcp->connect_to_host(addr, p_port);
+ if (err != OK) {
+ _on_error();
+ _tcp->disconnect_from_host();
+ return err;
+ }
+ _connection = _tcp;
+ _use_ssl = p_ssl;
+ _host = p_host;
+ _protocols = p_protocols;
+
+ _key = WSLPeer::generate_key();
+ // TODO custom extra headers (allow overriding this too?)
+ String request = "GET " + p_path + " HTTP/1.1\r\n";
+ request += "Host: " + p_host + port + "\r\n";
+ request += "Upgrade: websocket\r\n";
+ request += "Connection: Upgrade\r\n";
+ request += "Sec-WebSocket-Key: " + _key + "\r\n";
+ request += "Sec-WebSocket-Version: 13\r\n";
+ if (p_protocols.size() > 0) {
+ request += "Sec-WebSocket-Protocol: ";
+ for (int i = 0; i < p_protocols.size(); i++) {
+ if (i != 0)
+ request += ",";
+ request += p_protocols[i];
+ }
+ request += "\r\n";
+ }
+ request += "\r\n";
+ _request = request.utf8();
+
+ return OK;
+}
+
+int WSLClient::get_max_packet_size() const {
+ return (1 << _out_buf_size) - PROTO_SIZE;
+}
+
+void WSLClient::poll() {
+ if (_peer->is_connected_to_host()) {
+ _peer->poll();
+ if (!_peer->is_connected_to_host()) {
+ _on_disconnect(_peer->close_code != -1);
+ disconnect_from_host();
+ }
+ return;
+ }
+
+ if (_connection.is_null())
+ return; // Not connected.
+
+ switch (_tcp->get_status()) {
+ case StreamPeerTCP::STATUS_NONE:
+ // Clean close
+ _on_error();
+ disconnect_from_host();
+ break;
+ case StreamPeerTCP::STATUS_CONNECTED: {
+ Ref<StreamPeerSSL> ssl;
+ if (_use_ssl) {
+ if (_connection == _tcp) {
+ // Start SSL handshake
+ ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create());
+ ERR_EXPLAIN("SSL is not available in this build");
+ ERR_FAIL_COND(ssl.is_null());
+ ssl->set_blocking_handshake_enabled(false);
+ if (ssl->connect_to_stream(_tcp, verify_ssl, _host) != OK) {
+ _on_error();
+ disconnect_from_host();
+ return;
+ }
+ _connection = ssl;
+ } else {
+ ssl = static_cast<Ref<StreamPeerSSL> >(_connection);
+ ERR_FAIL_COND(ssl.is_null()); // Bug?
+ ssl->poll();
+ }
+ if (ssl->get_status() == StreamPeerSSL::STATUS_HANDSHAKING)
+ return; // Need more polling.
+ else if (ssl->get_status() != StreamPeerSSL::STATUS_CONNECTED) {
+ _on_error();
+ disconnect_from_host();
+ return; // Error.
+ }
+ }
+ // Do websocket handshake.
+ _do_handshake();
+ } break;
+ case StreamPeerTCP::STATUS_ERROR:
+ _on_error();
+ disconnect_from_host();
+ break;
+ case StreamPeerTCP::STATUS_CONNECTING:
+ break; // Wait for connection
+ }
+}
+
+Ref<WebSocketPeer> WSLClient::get_peer(int p_peer_id) const {
+
+ ERR_FAIL_COND_V(p_peer_id != 1, NULL);
+
+ return _peer;
+}
+
+NetworkedMultiplayerPeer::ConnectionStatus WSLClient::get_connection_status() const {
+
+ if (_peer->is_connected_to_host())
+ return CONNECTION_CONNECTED;
+
+ if (_tcp->is_connected_to_host())
+ return CONNECTION_CONNECTING;
+
+ return CONNECTION_DISCONNECTED;
+}
+
+void WSLClient::disconnect_from_host(int p_code, String p_reason) {
+
+ _peer->close(p_code, p_reason);
+ _connection = Ref<StreamPeer>(NULL);
+ _tcp = Ref<StreamPeerTCP>(memnew(StreamPeerTCP));
+
+ _key = "";
+ _host = "";
+ _protocols.resize(0);
+ _use_ssl = false;
+
+ _request = "";
+ _requested = 0;
+
+ memset(_resp_buf, 0, sizeof(_resp_buf));
+ _resp_pos = 0;
+}
+
+IP_Address WSLClient::get_connected_host() const {
+
+ return IP_Address();
+}
+
+uint16_t WSLClient::get_connected_port() const {
+
+ return 1025;
+}
+
+Error WSLClient::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) {
+ ERR_EXPLAIN("Buffers sizes can only be set before listening or connecting");
+ ERR_FAIL_COND_V(_connection.is_valid(), FAILED);
+
+ _in_buf_size = nearest_shift(p_in_buffer - 1) + 10;
+ _in_pkt_size = nearest_shift(p_in_packets - 1);
+ _out_buf_size = nearest_shift(p_out_buffer - 1) + 10;
+ _out_pkt_size = nearest_shift(p_out_packets - 1);
+ return OK;
+}
+
+WSLClient::WSLClient() {
+ _in_buf_size = nearest_shift((int)GLOBAL_GET(WSC_IN_BUF) - 1) + 10;
+ _in_pkt_size = nearest_shift((int)GLOBAL_GET(WSC_IN_PKT) - 1);
+ _out_buf_size = nearest_shift((int)GLOBAL_GET(WSC_OUT_BUF) - 1) + 10;
+ _out_pkt_size = nearest_shift((int)GLOBAL_GET(WSC_OUT_PKT) - 1);
+
+ _peer.instance();
+ _tcp.instance();
+ disconnect_from_host();
+}
+
+WSLClient::~WSLClient() {
+
+ _peer->close_now();
+ _peer->invalidate();
+ disconnect_from_host();
+}
+
+#endif // JAVASCRIPT_ENABLED
diff --git a/modules/websocket/lws_client.h b/modules/websocket/wsl_client.h
index df4aabec7f..57dfd635b7 100644
--- a/modules/websocket/lws_client.h
+++ b/modules/websocket/wsl_client.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* lws_client.h */
+/* wsl_client.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,21 +28,21 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef LWSCLIENT_H
-#define LWSCLIENT_H
+#ifndef WSLCLIENT_H
+#define WSLCLIENT_H
#ifndef JAVASCRIPT_ENABLED
#include "core/error_list.h"
-#include "lws_helper.h"
-#include "lws_peer.h"
+#include "core/io/stream_peer_ssl.h"
+#include "core/io/stream_peer_tcp.h"
#include "websocket_client.h"
+#include "wsl_peer.h"
+#include "wslay/wslay.h"
-class LWSClient : public WebSocketClient {
+class WSLClient : public WebSocketClient {
- GDCIIMPL(LWSClient, WebSocketClient);
-
- LWS_HELPER(LWSClient);
+ GDCIIMPL(WSLClient, WebSocketClient);
private:
int _in_buf_size;
@@ -50,6 +50,26 @@ private:
int _out_buf_size;
int _out_pkt_size;
+ Ref<WSLPeer> _peer;
+ Ref<StreamPeerTCP> _tcp;
+ Ref<StreamPeer> _connection;
+
+ CharString _request;
+ int _requested;
+
+ uint8_t _resp_buf[WSL_MAX_HEADER_SIZE];
+ int _resp_pos;
+
+ String _response;
+
+ String _key;
+ String _host;
+ PoolVector<String> _protocols;
+ bool _use_ssl;
+
+ void _do_handshake();
+ bool _verify_headers(String &r_protocol);
+
public:
Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets);
Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocol = PoolVector<String>());
@@ -61,10 +81,10 @@ public:
virtual ConnectionStatus get_connection_status() const;
virtual void poll();
- LWSClient();
- ~LWSClient();
+ WSLClient();
+ ~WSLClient();
};
#endif // JAVASCRIPT_ENABLED
-#endif // LWSCLIENT_H
+#endif // WSLCLIENT_H
diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp
new file mode 100644
index 0000000000..b11bd2b70f
--- /dev/null
+++ b/modules/websocket/wsl_peer.cpp
@@ -0,0 +1,339 @@
+/*************************************************************************/
+/* lws_peer.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 "wsl_peer.h"
+
+#include "wsl_client.h"
+#include "wsl_server.h"
+
+#include "core/math/crypto_core.h"
+#include "core/math/random_number_generator.h"
+#include "core/os/os.h"
+
+String WSLPeer::generate_key() {
+ // Random key
+ RandomNumberGenerator rng;
+ rng.set_seed(OS::get_singleton()->get_unix_time());
+ PoolVector<uint8_t> bkey;
+ int len = 16; // 16 bytes, as per RFC
+ bkey.resize(len);
+ PoolVector<uint8_t>::Write w = bkey.write();
+ for (int i = 0; i < len; i++) {
+ w[i] = (uint8_t)rng.randi_range(0, 255);
+ }
+ return CryptoCore::b64_encode_str(&w[0], len);
+}
+
+String WSLPeer::compute_key_response(String p_key) {
+ String key = p_key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // Magic UUID as per RFC
+ Vector<uint8_t> sha = key.sha1_buffer();
+ return CryptoCore::b64_encode_str(sha.ptr(), sha.size());
+}
+
+void WSLPeer::_wsl_destroy(struct PeerData **p_data) {
+ if (!p_data || !(*p_data))
+ return;
+ struct PeerData *data = *p_data;
+ if (data->polling) {
+ data->destroy = true;
+ return;
+ }
+ wslay_event_context_free(data->ctx);
+ memdelete(data);
+ *p_data = NULL;
+}
+
+bool WSLPeer::_wsl_poll(struct PeerData *p_data) {
+ p_data->polling = true;
+ int err = 0;
+ if ((err = wslay_event_recv(p_data->ctx)) != 0 || (err = wslay_event_send(p_data->ctx)) != 0) {
+ print_verbose("Websocket (wslay) poll error: " + itos(err));
+ p_data->destroy = true;
+ }
+ p_data->polling = false;
+
+ if (p_data->destroy || (wslay_event_get_close_sent(p_data->ctx) && wslay_event_get_close_received(p_data->ctx))) {
+ bool valid = p_data->valid;
+ _wsl_destroy(&p_data);
+ return valid;
+ }
+ return false;
+}
+
+ssize_t wsl_recv_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len, int flags, void *user_data) {
+ struct WSLPeer::PeerData *peer_data = (struct WSLPeer::PeerData *)user_data;
+ if (!peer_data->valid) {
+ wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
+ return -1;
+ }
+ Ref<StreamPeer> conn = peer_data->conn;
+ int read = 0;
+ Error err = conn->get_partial_data(data, len, read);
+ if (err != OK) {
+ print_verbose("Websocket get data error: " + itos(err) + ", read (should be 0!): " + itos(read));
+ wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
+ return -1;
+ }
+ if (read == 0) {
+ wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
+ return -1;
+ }
+ return read;
+}
+
+ssize_t wsl_send_callback(wslay_event_context_ptr ctx, const uint8_t *data, size_t len, int flags, void *user_data) {
+ struct WSLPeer::PeerData *peer_data = (struct WSLPeer::PeerData *)user_data;
+ if (!peer_data->valid) {
+ wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
+ return -1;
+ }
+ Ref<StreamPeer> conn = peer_data->conn;
+ int sent = 0;
+ Error err = conn->put_partial_data(data, len, sent);
+ if (err != OK) {
+ wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
+ return -1;
+ }
+ if (sent == 0) {
+ wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
+ return -1;
+ }
+ return sent;
+}
+
+int wsl_genmask_callback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len, void *user_data) {
+ RandomNumberGenerator rng;
+ // TODO maybe use crypto in the future?
+ rng.set_seed(OS::get_singleton()->get_unix_time());
+ for (unsigned int i = 0; i < len; i++) {
+ buf[i] = (uint8_t)rng.randi_range(0, 255);
+ }
+ return 0;
+}
+
+void wsl_msg_recv_callback(wslay_event_context_ptr ctx, const struct wslay_event_on_msg_recv_arg *arg, void *user_data) {
+ struct WSLPeer::PeerData *peer_data = (struct WSLPeer::PeerData *)user_data;
+ if (!peer_data->valid) {
+ return;
+ }
+ WSLPeer *peer = (WSLPeer *)peer_data->peer;
+
+ if (peer->parse_message(arg) != OK)
+ return;
+
+ if (peer_data->is_server) {
+ WSLServer *helper = (WSLServer *)peer_data->obj;
+ helper->_on_peer_packet(peer_data->id);
+ } else {
+ WSLClient *helper = (WSLClient *)peer_data->obj;
+ helper->_on_peer_packet();
+ }
+}
+
+wslay_event_callbacks wsl_callbacks = {
+ wsl_recv_callback,
+ wsl_send_callback,
+ wsl_genmask_callback,
+ NULL, /* on_frame_recv_start_callback */
+ NULL, /* on_frame_recv_callback */
+ NULL, /* on_frame_recv_end_callback */
+ wsl_msg_recv_callback
+};
+
+Error WSLPeer::parse_message(const wslay_event_on_msg_recv_arg *arg) {
+ uint8_t is_string = 0;
+ if (arg->opcode == WSLAY_TEXT_FRAME) {
+ is_string = 1;
+ } else if (arg->opcode == WSLAY_CONNECTION_CLOSE) {
+ close_code = arg->status_code;
+ size_t len = arg->msg_length;
+ close_reason = "";
+ if (len > 2 /* first 2 bytes = close code */) {
+ close_reason.parse_utf8((char *)arg->msg + 2, len - 2);
+ }
+ if (!wslay_event_get_close_sent(_data->ctx)) {
+ if (_data->is_server) {
+ WSLServer *helper = (WSLServer *)_data->obj;
+ helper->_on_close_request(_data->id, close_code, close_reason);
+ } else {
+ WSLClient *helper = (WSLClient *)_data->obj;
+ helper->_on_close_request(close_code, close_reason);
+ }
+ }
+ return ERR_FILE_EOF;
+ } else if (arg->opcode != WSLAY_BINARY_FRAME) {
+ // Ping or pong
+ return ERR_SKIP;
+ }
+ _in_buffer.write_packet(arg->msg, arg->msg_length, &is_string);
+ return OK;
+}
+
+void WSLPeer::make_context(PeerData *p_data, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size, unsigned int p_out_pkt_size) {
+ ERR_FAIL_COND(_data != NULL);
+ ERR_FAIL_COND(p_data == NULL);
+
+ _in_buffer.resize(p_in_pkt_size, p_in_buf_size);
+ _packet_buffer.resize((1 << MAX(p_in_buf_size, p_out_buf_size)));
+
+ _data = p_data;
+ _data->peer = this;
+ _data->valid = true;
+ _connection = Ref<StreamPeer>(_data->conn);
+
+ if (_data->is_server)
+ wslay_event_context_server_init(&(_data->ctx), &wsl_callbacks, _data);
+ else
+ wslay_event_context_client_init(&(_data->ctx), &wsl_callbacks, _data);
+ wslay_event_config_set_max_recv_msg_length(_data->ctx, (1 << p_in_buf_size));
+}
+
+void WSLPeer::set_write_mode(WriteMode p_mode) {
+ write_mode = p_mode;
+}
+
+WSLPeer::WriteMode WSLPeer::get_write_mode() const {
+ return write_mode;
+}
+
+void WSLPeer::poll() {
+ if (!_data)
+ return;
+
+ if (_wsl_poll(_data)) {
+ _data = NULL;
+ }
+}
+
+Error WSLPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
+
+ ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
+
+ struct wslay_event_msg msg; // Should I use fragmented?
+ msg.opcode = write_mode == WRITE_MODE_TEXT ? WSLAY_TEXT_FRAME : WSLAY_BINARY_FRAME;
+ msg.msg = p_buffer;
+ msg.msg_length = p_buffer_size;
+
+ wslay_event_queue_msg(_data->ctx, &msg);
+ return OK;
+}
+
+Error WSLPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
+
+ r_buffer_size = 0;
+
+ ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
+
+ if (_in_buffer.packets_left() == 0)
+ return ERR_UNAVAILABLE;
+
+ int read = 0;
+ PoolVector<uint8_t>::Write rw = _packet_buffer.write();
+ _in_buffer.read_packet(rw.ptr(), _packet_buffer.size(), &_is_string, read);
+
+ *r_buffer = rw.ptr();
+ r_buffer_size = read;
+
+ return OK;
+}
+
+int WSLPeer::get_available_packet_count() const {
+
+ if (!is_connected_to_host())
+ return 0;
+
+ return _in_buffer.packets_left();
+}
+
+bool WSLPeer::was_string_packet() const {
+
+ return _is_string;
+}
+
+bool WSLPeer::is_connected_to_host() const {
+
+ return _data != NULL;
+}
+
+void WSLPeer::close_now() {
+ close(1000, "");
+ _wsl_destroy(&_data);
+}
+
+void WSLPeer::close(int p_code, String p_reason) {
+ if (_data && !wslay_event_get_close_sent(_data->ctx)) {
+ CharString cs = p_reason.utf8();
+ wslay_event_queue_close(_data->ctx, p_code, (uint8_t *)cs.ptr(), cs.size());
+ wslay_event_send(_data->ctx);
+ }
+
+ _in_buffer.clear();
+ _packet_buffer.resize(0);
+}
+
+IP_Address WSLPeer::get_connected_host() const {
+
+ ERR_FAIL_COND_V(!is_connected_to_host(), IP_Address());
+
+ IP_Address ip;
+ return ip;
+}
+
+uint16_t WSLPeer::get_connected_port() const {
+
+ ERR_FAIL_COND_V(!is_connected_to_host(), 0);
+
+ uint16_t port = 0;
+ return port;
+}
+
+void WSLPeer::invalidate() {
+ if (_data)
+ _data->valid = false;
+}
+
+WSLPeer::WSLPeer() {
+ _data = NULL;
+ _is_string = 0;
+ close_code = -1;
+ write_mode = WRITE_MODE_BINARY;
+}
+
+WSLPeer::~WSLPeer() {
+
+ close();
+ invalidate();
+ _wsl_destroy(&_data);
+ _data = NULL;
+}
+
+#endif // JAVASCRIPT_ENABLED
diff --git a/modules/websocket/lws_peer.h b/modules/websocket/wsl_peer.h
index 6771c13094..d51b304fe1 100644
--- a/modules/websocket/lws_peer.h
+++ b/modules/websocket/wsl_peer.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* lws_peer.h */
+/* wsl_peer.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,50 +28,76 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef LWSPEER_H
-#define LWSPEER_H
+#ifndef WSLPEER_H
+#define WSLPEER_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 "packet_buffer.h"
#include "websocket_peer.h"
+#include "wslay/wslay.h"
-class LWSPeer : public WebSocketPeer {
+#define WSL_MAX_HEADER_SIZE 4096
- GDCIIMPL(LWSPeer, WebSocketPeer);
+class WSLPeer : public WebSocketPeer {
+
+ GDCIIMPL(WSLPeer, WebSocketPeer);
+
+public:
+ struct PeerData {
+ bool polling;
+ bool destroy;
+ bool valid;
+ bool is_server;
+ void *obj;
+ void *peer;
+ Ref<StreamPeer> conn;
+ int id;
+ wslay_event_context_ptr ctx;
+
+ PeerData() {
+ polling = false;
+ destroy = false;
+ valid = false;
+ is_server = false;
+ id = 1;
+ ctx = NULL;
+ obj = NULL;
+ peer = NULL;
+ }
+ };
+
+ static String compute_key_response(String p_key);
+ static String generate_key();
private:
- int _in_size;
+ static bool _wsl_poll(struct PeerData *p_data);
+ static void _wsl_destroy(struct PeerData **p_data);
+
+ Ref<StreamPeer> _connection;
+ struct PeerData *_data;
uint8_t _is_string;
// Our packet info is just a boolean (is_string), using uint8_t for it.
PacketBuffer<uint8_t> _in_buffer;
- PacketBuffer<uint8_t> _out_buffer;
PoolVector<uint8_t> _packet_buffer;
- struct lws *wsi;
WriteMode write_mode;
+public:
int close_code;
String close_reason;
-
-public:
- struct PeerData {
- uint32_t peer_id;
- bool force_close;
- bool clean_close;
- };
+ void poll(); // Used by client and server.
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_now();
virtual void close(int p_code = 1000, String p_reason = "");
virtual bool is_connected_to_host() const;
virtual IP_Address get_connected_host() const;
@@ -81,14 +107,12 @@ public:
virtual void set_write_mode(WriteMode p_mode);
virtual bool was_string_packet() const;
- void set_wsi(struct lws *wsi, unsigned int _in_buf_size, unsigned int _in_pkt_size, unsigned int _out_buf_size, unsigned int _out_pkt_size);
- Error read_wsi(void *in, size_t len);
- Error write_wsi();
- void send_close_status(struct lws *wsi);
- String get_close_reason(void *in, size_t len, int &r_code);
+ void make_context(PeerData *p_data, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size, unsigned int p_out_pkt_size);
+ Error parse_message(const wslay_event_on_msg_recv_arg *arg);
+ void invalidate();
- LWSPeer();
- ~LWSPeer();
+ WSLPeer();
+ ~WSLPeer();
};
#endif // JAVASCRIPT_ENABLED
diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp
new file mode 100644
index 0000000000..1e140a716f
--- /dev/null
+++ b/modules/websocket/wsl_server.cpp
@@ -0,0 +1,281 @@
+/*************************************************************************/
+/* lws_server.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 "wsl_server.h"
+#include "core/os/os.h"
+#include "core/project_settings.h"
+
+WSLServer::PendingPeer::PendingPeer() {
+ time = 0;
+ has_request = false;
+ response_sent = 0;
+ req_pos = 0;
+ memset(req_buf, 0, sizeof(req_buf));
+}
+
+bool WSLServer::PendingPeer::_parse_request(String &r_key) {
+ Vector<String> psa = String((char *)req_buf).split("\r\n");
+ int len = psa.size();
+ if (len < 4) {
+ ERR_EXPLAIN("Not enough response headers.");
+ ERR_FAIL_V(false);
+ }
+
+ Vector<String> req = psa[0].split(" ", false);
+ if (req.size() < 2) {
+ ERR_EXPLAIN("Invalid protocol or status code.");
+ ERR_FAIL_V(false);
+ }
+ // Wrong protocol
+ if (req[0] != "GET" || req[2] != "HTTP/1.1") {
+ ERR_EXPLAIN("Invalid method or HTTP version.");
+ ERR_FAIL_V(false);
+ }
+
+ Map<String, String> headers;
+ for (int i = 1; i < len; i++) {
+ Vector<String> header = psa[i].split(":", false, 1);
+ if (header.size() != 2) {
+ ERR_EXPLAIN("Invalid header -> " + psa[i]);
+ ERR_FAIL_V(false);
+ }
+ String name = header[0].to_lower();
+ String value = header[1].strip_edges();
+ if (headers.has(name))
+ headers[name] += "," + value;
+ else
+ headers[name] = value;
+ }
+#define _WLS_CHECK(NAME, VALUE) \
+ ERR_EXPLAIN("Missing or invalid header '" + String(NAME) + "'. Expected value '" + VALUE + "'"); \
+ ERR_FAIL_COND_V(!headers.has(NAME) || headers[NAME].to_lower() != VALUE, false);
+#define _WLS_CHECK_EX(NAME) \
+ ERR_EXPLAIN("Missing header '" + String(NAME) + "'."); \
+ ERR_FAIL_COND_V(!headers.has(NAME), false);
+ _WLS_CHECK("upgrade", "websocket");
+ _WLS_CHECK("sec-websocket-version", "13");
+ _WLS_CHECK_EX("sec-websocket-key");
+ _WLS_CHECK_EX("connection");
+#undef _WLS_CHECK_EX
+#undef _WLS_CHECK
+ r_key = headers["sec-websocket-key"];
+ return true;
+}
+
+Error WSLServer::PendingPeer::do_handshake() {
+ if (OS::get_singleton()->get_ticks_msec() - time > WSL_SERVER_TIMEOUT)
+ return ERR_TIMEOUT;
+ if (!has_request) {
+ int read = 0;
+ while (true) {
+ if (req_pos >= WSL_MAX_HEADER_SIZE) {
+ // Header is too big
+ ERR_EXPLAIN("Response headers too big");
+ ERR_FAIL_V(ERR_OUT_OF_MEMORY);
+ }
+ Error err = connection->get_partial_data(&req_buf[req_pos], 1, read);
+ if (err != OK) // Got an error
+ return FAILED;
+ else if (read != 1) // Busy, wait next poll
+ return ERR_BUSY;
+ char *r = (char *)req_buf;
+ int l = req_pos;
+ if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') {
+ r[l - 3] = '\0';
+ if (!_parse_request(key)) {
+ return FAILED;
+ }
+ String s = "HTTP/1.1 101 Switching Protocols\r\n";
+ s += "Upgrade: websocket\r\n";
+ s += "Connection: Upgrade\r\n";
+ s += "Sec-WebSocket-Accept: " + WSLPeer::compute_key_response(key) + "\r\n";
+ s += "\r\n";
+ response = s.utf8();
+ has_request = true;
+ break;
+ }
+ req_pos += 1;
+ }
+ }
+ if (has_request && response_sent < response.size() - 1) {
+ int sent = 0;
+ Error err = connection->put_partial_data((const uint8_t *)response.get_data() + response_sent, response.size() - response_sent - 1, sent);
+ if (err != OK) {
+ return err;
+ }
+ response_sent += sent;
+ }
+ if (response_sent < response.size() - 1)
+ return ERR_BUSY;
+ return OK;
+}
+
+Error WSLServer::listen(int p_port, PoolVector<String> p_protocols, bool gd_mp_api) {
+ ERR_FAIL_COND_V(is_listening(), ERR_ALREADY_IN_USE);
+
+ _is_multiplayer = gd_mp_api;
+ _server->listen(p_port);
+
+ return OK;
+}
+
+void WSLServer::poll() {
+
+ List<int> remove_ids;
+ for (Map<int, Ref<WebSocketPeer> >::Element *E = _peer_map.front(); E; E = E->next()) {
+ Ref<WSLPeer> peer = (WSLPeer *)E->get().ptr();
+ peer->poll();
+ if (!peer->is_connected_to_host()) {
+ _on_disconnect(E->key(), peer->close_code != -1);
+ remove_ids.push_back(E->key());
+ }
+ }
+ for (List<int>::Element *E = remove_ids.front(); E; E = E->next()) {
+ _peer_map.erase(E->get());
+ }
+ remove_ids.clear();
+
+ List<Ref<PendingPeer> > remove_peers;
+ for (List<Ref<PendingPeer> >::Element *E = _pending.front(); E; E = E->next()) {
+ Ref<PendingPeer> ppeer = E->get();
+ Error err = ppeer->do_handshake();
+ if (err == ERR_BUSY) {
+ continue;
+ } else if (err != OK) {
+ remove_peers.push_back(ppeer);
+ continue;
+ }
+ // Creating new peer
+ int32_t id = _gen_unique_id();
+
+ WSLPeer::PeerData *data = memnew(struct WSLPeer::PeerData);
+ data->obj = this;
+ data->conn = ppeer->connection;
+ data->is_server = true;
+ data->id = id;
+
+ Ref<WSLPeer> ws_peer = memnew(WSLPeer);
+ ws_peer->make_context(data, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size);
+
+ _peer_map[id] = ws_peer;
+ remove_peers.push_back(ppeer);
+ _on_connect(id, "");
+ }
+ for (List<Ref<PendingPeer> >::Element *E = remove_peers.front(); E; E = E->next()) {
+ _pending.erase(E->get());
+ }
+ remove_peers.clear();
+
+ if (!_server->is_listening())
+ return;
+
+ while (_server->is_connection_available()) {
+ Ref<StreamPeer> conn = _server->take_connection();
+ if (is_refusing_new_connections())
+ continue; // Conn will go out-of-scope and be closed.
+
+ Ref<PendingPeer> peer = memnew(PendingPeer);
+ peer->connection = conn;
+ peer->time = OS::get_singleton()->get_ticks_msec();
+ _pending.push_back(peer);
+ }
+}
+
+bool WSLServer::is_listening() const {
+ return _server->is_listening();
+}
+
+int WSLServer::get_max_packet_size() const {
+ return (1 << _out_buf_size) - PROTO_SIZE;
+}
+
+void WSLServer::stop() {
+ _server->stop();
+ for (Map<int, Ref<WebSocketPeer> >::Element *E = _peer_map.front(); E; E = E->next()) {
+ Ref<WSLPeer> peer = (WSLPeer *)E->get().ptr();
+ peer->close_now();
+ }
+ _pending.clear();
+ _peer_map.clear();
+}
+
+bool WSLServer::has_peer(int p_id) const {
+ return _peer_map.has(p_id);
+}
+
+Ref<WebSocketPeer> WSLServer::get_peer(int p_id) const {
+ ERR_FAIL_COND_V(!has_peer(p_id), NULL);
+ return _peer_map[p_id];
+}
+
+IP_Address WSLServer::get_peer_address(int p_peer_id) const {
+ ERR_FAIL_COND_V(!has_peer(p_peer_id), IP_Address());
+
+ return _peer_map[p_peer_id]->get_connected_host();
+}
+
+int WSLServer::get_peer_port(int p_peer_id) const {
+ ERR_FAIL_COND_V(!has_peer(p_peer_id), 0);
+
+ return _peer_map[p_peer_id]->get_connected_port();
+}
+
+void WSLServer::disconnect_peer(int p_peer_id, int p_code, String p_reason) {
+ ERR_FAIL_COND(!has_peer(p_peer_id));
+
+ get_peer(p_peer_id)->close(p_code, p_reason);
+}
+
+Error WSLServer::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) {
+ ERR_EXPLAIN("Buffers sizes can only be set before listening or connecting");
+ ERR_FAIL_COND_V(_server->is_listening(), FAILED);
+
+ _in_buf_size = nearest_shift(p_in_buffer - 1) + 10;
+ _in_pkt_size = nearest_shift(p_in_packets - 1);
+ _out_buf_size = nearest_shift(p_out_buffer - 1) + 10;
+ _out_pkt_size = nearest_shift(p_out_packets - 1);
+ return OK;
+}
+
+WSLServer::WSLServer() {
+ _in_buf_size = nearest_shift((int)GLOBAL_GET(WSS_IN_BUF) - 1) + 10;
+ _in_pkt_size = nearest_shift((int)GLOBAL_GET(WSS_IN_PKT) - 1);
+ _out_buf_size = nearest_shift((int)GLOBAL_GET(WSS_OUT_BUF) - 1) + 10;
+ _out_pkt_size = nearest_shift((int)GLOBAL_GET(WSS_OUT_PKT) - 1);
+ _server.instance();
+}
+
+WSLServer::~WSLServer() {
+ stop();
+}
+
+#endif // JAVASCRIPT_ENABLED
diff --git a/modules/websocket/lws_server.h b/modules/websocket/wsl_server.h
index b331852d26..b0520bd731 100644
--- a/modules/websocket/lws_server.h
+++ b/modules/websocket/wsl_server.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* lws_server.h */
+/* wsl_server.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,29 +28,53 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef LWSSERVER_H
-#define LWSSERVER_H
+#ifndef WSLSERVER_H
+#define WSLSERVER_H
#ifndef JAVASCRIPT_ENABLED
-#include "core/reference.h"
-#include "lws_helper.h"
-#include "lws_peer.h"
#include "websocket_server.h"
+#include "wsl_peer.h"
-class LWSServer : public WebSocketServer {
+#include "core/io/stream_peer_tcp.h"
+#include "core/io/tcp_server.h"
- GDCIIMPL(LWSServer, WebSocketServer);
+#define WSL_SERVER_TIMEOUT 1000
- LWS_HELPER(LWSServer);
+class WSLServer : public WebSocketServer {
+
+ GDCIIMPL(WSLServer, WebSocketServer);
private:
- Map<int, Ref<LWSPeer> > peer_map;
+ class PendingPeer : public Reference {
+
+ private:
+ bool _parse_request(String &r_key);
+
+ public:
+ Ref<StreamPeer> connection;
+
+ int time;
+ uint8_t req_buf[WSL_MAX_HEADER_SIZE];
+ int req_pos;
+ String key;
+ bool has_request;
+ CharString response;
+ int response_sent;
+
+ PendingPeer();
+
+ Error do_handshake();
+ };
+
int _in_buf_size;
int _in_pkt_size;
int _out_buf_size;
int _out_pkt_size;
+ List<Ref<PendingPeer> > _pending;
+ Ref<TCP_Server> _server;
+
public:
Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets);
Error listen(int p_port, PoolVector<String> p_protocols = PoolVector<String>(), bool gd_mp_api = false);
@@ -62,12 +86,12 @@ public:
IP_Address get_peer_address(int p_peer_id) const;
int get_peer_port(int p_peer_id) const;
void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "");
- virtual void poll() { _lws_poll(); }
+ virtual void poll();
- LWSServer();
- ~LWSServer();
+ WSLServer();
+ ~WSLServer();
};
#endif // JAVASCRIPT_ENABLED
-#endif // LWSSERVER_H
+#endif // WSLSERVER_H