diff options
39 files changed, 642 insertions, 107 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..533968886e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,140 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). + +## [3.0] - 2018-01-29 + +### Added + +- Physically-based renderer using OpenGL ES 3.0. +  - Uses the Disney PBR model, with clearcoat, sheen and anisotropy parameters available. +  - Uses a forward renderer, supporting multi-sample anti-aliasing (MSAA). +  - Parallax occlusion mapping. +  - Reflection probes. +  - Screen-space reflections. +  - Real-time global illumination using voxel cone tracing (GIProbe). +  - Proximity fade and distance fade (useful for creating soft particles and various effects). +  - [Lightmapper](https://godotengine.org/article/introducing-new-last-minute-lightmapper) for lower-end desktop and mobile platforms, as an alternative to GIProbe. +- New SpatialMaterial resource, replacing FixedMaterial. +  - Multiple passes can now be specified (with an optional "grow" property), allowing for effects such as cel shading. +- Brand new 3D post-processing system. +  - Depth of field (near and far). +  - Fog, supporting light transmittance, sun-oriented fog, depth fog and height fog. +  - Tonemapping and Auto-exposure. +  - Screen-space ambient occlusion. +  - Multi-stage glow and bloom, supporting optional bicubic upscaling for better quality. +  - Color grading and various adjustments. +- Rewritten audio engine from scratch. +  - Supports audio routing with arbitrary number of channels, including Area-based audio redirection ([video](https://youtu.be/K2XOBaJ5OQ0)). +  - More than a dozen of audio effects included. +- Rewritten 3D physics using [Bullet](http://bulletphysics.org/). +- UDP-based high-level networking API using [ENet](http://enet.bespin.org/). +- IPv6 support for all of the engine's networking APIs. +- Visual scripting. +- Rewritten import system. +  - Assets are now referenced with their source files, then imported in a transparent manner by the engine. +  - Imported assets are now cached in a `.import` directory, making distribution and versioning easier. +  - Support for ETC2 compression. +  - Support for uncompressed Targa (.tga) textures, allowing for faster importing. +- Rewritten export system. +  - GPU-based texture compression can now be tweaked per-target. +  - Support for exporting resource packs to build DLC / content addons. +- Improved GDScript. +  - Pattern matching using the `match` keyword. +  - `$` shorthand for `get_node()`. +  - Setters and getters for node properties. +  - Underscores in number literals are now allowed for improved readability (for example,`1_000_000`). +  - Improved performance (+20% to +40%, based on various benchmarks). +- [Feature tags](http://docs.godotengine.org/en/latest/learning/workflow/export/feature_tags.html) in the Project Settings, for custom per-platform settings. +- Full support for the [glTF 2.0](https://www.khronos.org/gltf/) 3D interchange format. +- Freelook and fly navigation to the 3D editor. +- Built-in editor logging (logging standard output to a file), disabled by default. +- Improved, more intuitive file chooser in the editor. +- Smoothed out 3D editor zooming, panning and movement. +- Toggleable rendering information box in the 3D editor viewport. +  - FPS display can also be enabled in the editor viewport. +- Ability to render the 3D editor viewport at half resolution to achieve better performance. +- GDNative for binding languages like C++ to Godot as dynamic libraries. +  - Community bindings for [D](https://github.com/GodotNativeTools/godot-d), [Nim](https://github.com/pragmagic/godot-nim) and [Python](https://github.com/touilleMan/godot-python) are available. +- Editor settings and export templates are now versioned, making it easier to use several Godot versions on the same system. +- Optional soft shadows for 2D rendering. +- HDR sky support. +- Ability to toggle V-Sync while the project is running. +- Panorama sky support (sphere maps). +- Support for WebM videos (VP8/VP9 with Vorbis/Opus). +- Exporting to HTML5 using WebAssembly. +- C# support using Mono. +  - The Mono module is disabled by default, and needs to be compiled in at build-time. +  - The latest Mono version (5.4) can be used, fully supporting C# 7.0. +- Support for rasterizing SVG to images on-the-fly, using the nanosvg library. +  - Editor icons are now in SVG format, making them better-looking at non-integer scales. +  - Due to the library used, only simpler SVGs are well-supported, more complex SVGs may not render correctly. +- Support for oversampling DynamicFonts, keeping them sharp when scaled to high resolutions. +- Improved StyleBoxFlat. +  - Border widths can now be set per-corner. +  - Support for anti-aliased rounded and beveled corners. +  - Support for soft drop shadows. +- VeryLoDPI (75%) and MiDPI (150%) scaling modes for the editor. +- Improved internationalization support for projects. +  - Language changes are now effective without reloading the current scene. +- Implemented missing features in the HTML5 platform. +  - Cursor style changes. +  - Cursor capturing and hiding. +- Improved styling and presentation of HTML5 exports. +  - A spinner is now displayed during loading. +- Rewritten the 2D and 3D particle systems. +  - Particles are now GPU-based, allowing their use in much higher quantities than before. +  - Meshes can now be used as particles. +  - Particles can now be emitted from a mesh's shape. +  - Properties can now be modified over time using an editable curve. +  - Custom particle shaders can now be used. +- New editor theme, with customizable base color, highlight color and contrast. +  - A light editor theme option is now available, with icons suited to light backgrounds. +  - Alternative dark gray and Arc colors are available out of the box. +- New adaptive text editor theme, adjusting automatically based on the editor colors. +- Support for macOS trackpad gestures in the editor. +- Exporting to macOS now creates a `.dmg` disk image if exporting from an editor running on macOS. +  - Signing the macOS export now is possible if running macOS (requires a valid code signing certificate). +- Exporting to Windows now changes the exported project's icon using `rcedit` (requires WINE if exporting from Linux or macOS). +- Improved build system. +  - Support for compiling using Visual Studio 2017. +  - [SCons](http://scons.org/) 3.0 and Python 3 are now supported (SCons 2.5 and Python 2.7 still work). +  - Link-time optimization can now be enabled by passing `use_lto=yes` to the SCons command line. +    - Produces faster and sometimes smaller binaries. +    - Currently only supported with GCC and MSVC. +  - Added a progress percentage when compiling Godot. +  - `.zip` archives are automatically created when compiling HTML5 export templates. +- Easier and more powerful way to create editor plugins with EditorPlugin and related APIs. + +### Changed + +- Increased the default low-processor-usage mode FPS limit (60 → 125). +  - This makes the editor smoother and more responsive. +- Increased the default 3D editor camera's field of view (55 → 70). +- Increased the default 3D Camera node's field of view (65 → 70). +- Changed the default editor font (Droid Sans → [Noto Sans](https://www.google.com/get/noto/)). +- Changed the default script editor font (Source Code Pro → [Hack](http://sourcefoundry.org/hack/)) +- Renamed `engine.cfg` to `project.godot`. +  - This allows users to open a project by double-clicking the file if Godot is associated to `.godot` files. +- Some methods from the `OS` singleton were moved to the new `Engine` singleton. +- Switched from [GLEW](http://glew.sourceforge.net/) to [GLAD](http://glad.dav1d.de/) for OpenGL wrapping. +- Changed the SCons build flag for simple logs (`colored=yes` → `verbose=no`). +- The HTML5 platform now uses WebGL 2.0 (instead of 1.0). +- Redesigned the Godot logo to be more legible at small sizes. + +### Deprecated + +- `opacity` and `self_opacity` are replaced by `modulate` and `self_modulate` in all 2D nodes, allowing for full color changes in addition to opacity changes. + +### Removed + +- Skybox support. +  - Replaced with panorama skies, which are easier to import. +- Opus audio codec support. +  - This is due to the way the new audio engine is designed. +- HTML5 export using asm.js. +  - Only WebAssembly is supported now, since all browsers supporting WebGL 2.0 also support WebAssembly. + +[3.0]: https://github.com/godotengine/godot/compare/2.1-stable...3.0-stable diff --git a/core/class_db.cpp b/core/class_db.cpp index afcc8de0f2..3c9dae1acb 100644 --- a/core/class_db.cpp +++ b/core/class_db.cpp @@ -347,7 +347,7 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {  	OBJTYPE_RLOCK;  #ifdef DEBUG_METHODS_ENABLED -	uint64_t hash = hash_djb2_one_64(HashMapHasherDefault::hash(VERSION_FULL_NAME)); +	uint64_t hash = hash_djb2_one_64(HashMapHasherDefault::hash(VERSION_FULL_CONFIG));  	List<StringName> names; diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index 12060f31df..b9607632f7 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -962,6 +962,11 @@ Ref<InputEvent> InputEventMagnifyGesture::xformed_by(const Transform2D &p_xform,  	return ev;  } +String InputEventMagnifyGesture::as_text() const { + +	return "InputEventMagnifyGesture : factor=" + rtos(get_factor()) + ", position=(" + String(get_position()) + ")"; +} +  void InputEventMagnifyGesture::_bind_methods() {  	ClassDB::bind_method(D_METHOD("set_factor", "factor"), &InputEventMagnifyGesture::set_factor); @@ -999,6 +1004,11 @@ Ref<InputEvent> InputEventPanGesture::xformed_by(const Transform2D &p_xform, con  	return ev;  } +String InputEventPanGesture::as_text() const { + +	return "InputEventPanGesture : delta=(" + String(get_delta()) + "), position=(" + String(get_position()) + ")"; +} +  void InputEventPanGesture::_bind_methods() {  	ClassDB::bind_method(D_METHOD("set_delta", "delta"), &InputEventPanGesture::set_delta); diff --git a/core/os/input_event.h b/core/os/input_event.h index ad754d0d1f..0a33ab18a7 100644 --- a/core/os/input_event.h +++ b/core/os/input_event.h @@ -494,6 +494,7 @@ public:  	real_t get_factor() const;  	virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; +	virtual String as_text() const;  	InputEventMagnifyGesture();  }; @@ -511,6 +512,7 @@ public:  	Vector2 get_delta() const;  	virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; +	virtual String as_text() const;  	InputEventPanGesture();  }; diff --git a/core/version.h b/core/version.h index 7a55d69ad7..d39172865a 100644 --- a/core/version.h +++ b/core/version.h @@ -30,9 +30,32 @@  #include "version_generated.gen.h" +// Godot versions are of the form <major>.<minor> for the initial release, +// and then <major>.<minor>.<patch> for subsequent bugfix releases where <patch> != 0 +// That's arbitrary, but we find it pretty and it's the current policy. + +// Defines the main "branch" version. Patch versions in this branch should be +// forward-compatible. +// Example: "3.1" +#define VERSION_BRANCH "" _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR)  #ifdef VERSION_PATCH -#define VERSION_MKSTRING "" _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) "." _MKSTR(VERSION_PATCH) "." VERSION_STATUS "." VERSION_BUILD VERSION_MODULE_CONFIG +// Example: "3.1.4" +#define VERSION_NUMBER "" VERSION_BRANCH "." _MKSTR(VERSION_PATCH)  #else -#define VERSION_MKSTRING "" _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) "." VERSION_STATUS "." VERSION_BUILD VERSION_MODULE_CONFIG +// Example: "3.1" +#define VERSION_NUMBER "" VERSION_BRANCH  #endif // VERSION_PATCH -#define VERSION_FULL_NAME "" VERSION_NAME " v" VERSION_MKSTRING + +// Describes the full configuration of that Godot version, including the version number, +// the status (beta, stable, etc.) and potential module-specific features (e.g. mono). +// Example: "3.1.4.stable.mono" +#define VERSION_FULL_CONFIG "" VERSION_NUMBER "." VERSION_STATUS VERSION_MODULE_CONFIG + +// Similar to VERSION_FULL_CONFIG, but also includes the (potentially custom) VERSION_BUILD +// description (e.g. official, custom_build, etc.). +// Example: "3.1.4.stable.mono.official" +#define VERSION_FULL_BUILD "" VERSION_FULL_CONFIG "." VERSION_BUILD + +// Same as above, but prepended with Godot's name and a cosmetic "v" for "version". +// Example: "Godot v3.1.4.stable.official.mono" +#define VERSION_FULL_NAME "" VERSION_NAME " v" VERSION_FULL_BUILD diff --git a/doc/classes/StyleBoxTexture.xml b/doc/classes/StyleBoxTexture.xml index 6245400943..f789252e1d 100644 --- a/doc/classes/StyleBoxTexture.xml +++ b/doc/classes/StyleBoxTexture.xml @@ -59,11 +59,11 @@  		</member>  		<member name="modulate_color" type="Color" setter="set_modulate" getter="get_modulate">  		</member> -		<member name="normal_map" type="Resource" setter="set_normal_map" getter="get_normal_map"> +		<member name="normal_map" type="Texture" setter="set_normal_map" getter="get_normal_map">  		</member>  		<member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect">  		</member> -		<member name="texture" type="Resource" setter="set_texture" getter="get_texture"> +		<member name="texture" type="Texture" setter="set_texture" getter="get_texture">  		</member>  	</members>  	<signals> diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 7c053e8f60..5bb332816d 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2356,8 +2356,7 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G  void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy) { -	if (!p_sky) -		return; +	ERR_FAIL_COND(!p_sky);  	RasterizerStorageGLES3::Texture *tex = storage->texture_owner.getornull(p_sky->panorama); @@ -4337,7 +4336,8 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const  			glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.fbo); //switch to alpha fbo for sky, only diffuse/ambient matters  		*/ -		_draw_sky(sky, p_cam_projection, p_cam_transform, false, env->sky_custom_fov, env->bg_energy); +		if (sky && sky->panorama.is_valid()) +			_draw_sky(sky, p_cam_projection, p_cam_transform, false, env->sky_custom_fov, env->bg_energy);  	}  	//_render_list_forward(&alpha_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting,true); diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp index 2e64b55430..cf4d82fb07 100644 --- a/drivers/windows/dir_access_windows.cpp +++ b/drivers/windows/dir_access_windows.cpp @@ -261,13 +261,30 @@ Error DirAccessWindows::rename(String p_path, String p_new_path) {  	p_new_path = fix_path(p_new_path); -	if (file_exists(p_new_path)) { -		if (remove(p_new_path) != OK) { +	// If we're only changing file name case we need to do a little juggling +	if (p_path.to_lower() == p_new_path.to_lower()) { +		WCHAR tmpfile[MAX_PATH]; + +		if (!GetTempFileNameW(fix_path(get_current_dir()).c_str(), NULL, 0, tmpfile)) {  			return FAILED; -		}; -	}; +		} + +		if (!::ReplaceFileW(tmpfile, p_path.c_str(), NULL, 0, NULL, NULL)) { +			DeleteFileW(tmpfile); +			return FAILED; +		} -	return ::_wrename(p_path.c_str(), p_new_path.c_str()) == 0 ? OK : FAILED; +		return ::_wrename(tmpfile, p_new_path.c_str()) == 0 ? OK : FAILED; + +	} else { +		if (file_exists(p_new_path)) { +			if (remove(p_new_path) != OK) { +				return FAILED; +			} +		} + +		return ::_wrename(p_path.c_str(), p_new_path.c_str()) == 0 ? OK : FAILED; +	}  }  Error DirAccessWindows::remove(String p_path) { diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp index 3a418e5f33..3434aa33f9 100644 --- a/editor/doc/doc_data.cpp +++ b/editor/doc/doc_data.cpp @@ -974,7 +974,7 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri  		if (c.category == "")  			category = "Core";  		header += " category=\"" + category + "\""; -		header += String(" version=\"") + itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + VERSION_STATUS + "\""; +		header += String(" version=\"") + VERSION_NUMBER + "\"";  		header += ">";  		_write_string(f, 0, header);  		_write_string(f, 1, "<brief_description>"); diff --git a/editor/doc/doc_dump.cpp b/editor/doc/doc_dump.cpp index 905732a43f..adbe23dcd5 100644 --- a/editor/doc/doc_dump.cpp +++ b/editor/doc/doc_dump.cpp @@ -83,7 +83,7 @@ void DocDump::dump(const String &p_file) {  	FileAccess *f = FileAccess::open(p_file, FileAccess::WRITE);  	_write_string(f, 0, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); -	_write_string(f, 0, String("<doc version=\"") + itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + VERSION_STATUS + "\" name=\"Engine Types\">"); +	_write_string(f, 0, String("<doc version=\"") + VERSION_NUMBER + "\" name=\"Engine Types\">");  	while (class_list.size()) { diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index c9ac62a74d..da4bbf9b7a 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -274,8 +274,6 @@ void EditorExportPlatform::gen_debug_flags(Vector<String> &r_flags, int p_flags)  }  Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total) { -	if (p_path.ends_with(".so") || p_path.ends_with(".dylib") || p_path.ends_with(".dll")) -		return OK;  	PackData *pd = (PackData *)p_userdata; @@ -337,7 +335,7 @@ Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_pat  String EditorExportPlatform::find_export_template(String template_file_name, String *err) const { -	String current_version = itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + VERSION_STATUS + VERSION_MODULE_CONFIG; +	String current_version = VERSION_FULL_CONFIG;  	String template_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(current_version).plus_file(template_file_name);  	if (FileAccess::exists(template_path)) { diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index 41b016bdca..d0f008bd43 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -70,7 +70,7 @@ void ExportTemplateManager::_update_template_list() {  	memdelete(d); -	String current_version = itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + VERSION_STATUS + VERSION_MODULE_CONFIG; +	String current_version = VERSION_FULL_CONFIG;  	Label *current = memnew(Label);  	current->set_h_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 26afc78825..4b9e5ae301 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -30,11 +30,10 @@  #include "asset_library_editor_plugin.h" +#include "core/io/json.h" +#include "core/version.h"  #include "editor_node.h"  #include "editor_settings.h" -#include "io/json.h" - -#include "version_generated.gen.h"  void EditorAssetLibraryItem::configure(const String &p_title, int p_asset_id, const String &p_category, int p_category_id, const String &p_author, int p_author_id, int p_rating, const String &p_cost) { @@ -877,7 +876,8 @@ void EditorAssetLibrary::_search(int p_page) {  	}  	args += String() + "sort=" + sort_key[sort->get_selected()]; -	args += "&godot_version=" + itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR); +	// We use the "branch" version, i.e. major.minor, as patch releases should be compatible +	args += "&godot_version=" + String(VERSION_BRANCH);  	String support_list;  	for (int i = 0; i < SUPPORT_MAX; i++) { diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index f51e691be3..295d9439ad 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -244,7 +244,7 @@ void ThemeEditor::_save_template_cbk(String fname) {  	file->store_line("; ");  	file->store_line("; ******************* ");  	file->store_line("; "); -	file->store_line("; Template Generated Using: " + String(VERSION_MKSTRING)); +	file->store_line("; Template Generated Using: " + String(VERSION_FULL_BUILD));  	file->store_line(";    ");  	file->store_line("; ");  	file->store_line(""); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index bd700342f6..42c2956127 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1570,7 +1570,7 @@ ProjectManager::ProjectManager() {  	String hash = String(VERSION_HASH);  	if (hash.length() != 0)  		hash = "." + hash.left(7); -	l->set_text("v" VERSION_MKSTRING "" + hash); +	l->set_text("v" VERSION_FULL_BUILD "" + hash);  	l->set_align(Label::ALIGN_CENTER);  	top_hb->add_child(l); diff --git a/main/main.cpp b/main/main.cpp index 4d7273b4e4..5f336e17c5 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -175,7 +175,7 @@ static String get_full_version_string() {  	String hash = String(VERSION_HASH);  	if (hash.length() != 0)  		hash = "." + hash.left(7); -	return String(VERSION_MKSTRING) + hash; +	return String(VERSION_FULL_BUILD) + hash;  }  //#define DEBUG_INIT @@ -206,6 +206,7 @@ void Main::print_help(const char *p_binary) {  	OS::get_singleton()->print("  -e, --editor                     Start the editor instead of running the scene.\n");  	OS::get_singleton()->print("  -p, --project-manager            Start the project manager, even if a project is auto-detected.\n");  #endif +	OS::get_singleton()->print("  -q, --quit                       Quit after the first iteration.\n");  	OS::get_singleton()->print("  -l, --language <locale>          Use a specific locale (<locale> being a two-letter code).\n");  	OS::get_singleton()->print("  --path <directory>               Path to a project (<directory> must contain a 'project.godot' file).\n");  	OS::get_singleton()->print("  -u, --upwards                    Scan folders upwards for project.godot file.\n"); @@ -263,7 +264,7 @@ void Main::print_help(const char *p_binary) {  	OS::get_singleton()->print("  --export-debug                   Use together with --export, enables debug mode for the template.\n");  	OS::get_singleton()->print("  --doctool <path>                 Dump the engine API reference to the given <path> in XML format, merging if existing files are found.\n");  	OS::get_singleton()->print("  --no-docbase                     Disallow dumping the base types (used with --doctool).\n"); -	OS::get_singleton()->print("  --build-solutions                Builds the scripting solutions (IE. C#).\n"); +	OS::get_singleton()->print("  --build-solutions                Build the scripting solutions (e.g. for C# projects).\n");  #ifdef DEBUG_METHODS_ENABLED  	OS::get_singleton()->print("  --gdnative-generate-json-api     Generate JSON dump of the Godot API for GDNative bindings.\n");  #endif @@ -558,7 +559,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph  			}  		} else if (I->get() == "-u" || I->get() == "--upwards") { // scan folders upwards  			upwards = true; -		} else if (I->get() == "--quit" || I->get() == "-q") { // Auto quit at the end of the first main loop iteration +		} else if (I->get() == "-q" || I->get() == "--quit") { // Auto quit at the end of the first main loop iteration  			auto_quit = true;  		} else if (I->get().ends_with("project.godot")) {  			String path; diff --git a/misc/dist/linux/godot.6 b/misc/dist/linux/godot.6 index 22836e03ed..04982d9919 100644 --- a/misc/dist/linux/godot.6 +++ b/misc/dist/linux/godot.6 @@ -1,4 +1,4 @@ -.TH GODOT "6" "January 2018" "godot 3.0" "Games" +.TH GODOT "6" "February 2018" "godot 3.1" "Games"  .SH NAME  godot \- multi\-platform 2D and 3D game engine with a feature\-rich editor  .SH SYNOPSIS @@ -31,6 +31,9 @@ Start the editor instead of running the scene.  \fB\-p\fR, \fB\-\-project\-manager\fR  Start the project manager, even if a project is auto\-detected.  .TP +\fB\-q\fR, \fB\-\-quit\fR +Quit after the first iteration. +.TP  \fB\-l\fR, \fB\-\-language\fR <locale>  Use a specific locale (<locale> being a two\-letter code).  .TP @@ -68,6 +71,9 @@ Request a maximized window.  \fB\-w\fR, \fB\-\-windowed\fR  Request windowed mode.  .TP +\fB\-t\fR, \fB\-\-always\-on\-top\fR +Request an always\-on\-top window. +.TP  \fB\-\-resolution\fR <W>x<H>  Request window resolution.  .TP @@ -130,6 +136,9 @@ Dump the engine API reference to the given <path> in XML format, merging if exis  \fB\-\-no\-docbase\fR  Disallow dumping the base types (used with \fB\-\-doctool\fR).  .TP +\fB\-\-build\-solutions\fR +Build the scripting solutions (e.g. for C# projects). +.TP  \fB\-\-gdnative\-generate\-json\-api\fR  Generate JSON dump of the Godot API for GDNative bindings.  .TP diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 505562324f..db3787470f 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -410,13 +410,11 @@ String GDScriptLanguage::make_function(const String &p_class, const String &p_na  	String s = "func " + p_name + "(";  	if (p_args.size()) { -		s += " ";  		for (int i = 0; i < p_args.size(); i++) {  			if (i > 0)  				s += ", ";  			s += p_args[i].get_slice(":", 0);  		} -		s += " ";  	}  	s += "):\n" + _get_indentation() + "pass # replace with function body\n"; diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index fb45136575..b0854658ce 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -118,6 +118,8 @@ void CSharpLanguage::init() {  #ifdef TOOLS_ENABLED  	EditorNode::add_init_callback(&gdsharp_editor_init_callback); + +	GLOBAL_DEF("mono/export/include_scripts_content", true);  #endif  } diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp index 6b41b10981..51e6d76ae6 100644 --- a/modules/mono/editor/godotsharp_builds.cpp +++ b/modules/mono/editor/godotsharp_builds.cpp @@ -200,7 +200,7 @@ bool GodotSharpBuilds::copy_api_assembly(const String &p_src_dir, const String &  		memdelete(da);  		if (err != OK) { -			show_build_error_dialog("Failed to copy " API_ASSEMBLY_NAME ".dll"); +			show_build_error_dialog("Failed to copy " + assembly_file);  			return false;  		}  	} @@ -283,7 +283,7 @@ bool GodotSharpBuilds::make_api_sln(GodotSharpBuilds::APIType p_api_type) {  	return true;  } -bool GodotSharpBuilds::build_project_blocking() { +bool GodotSharpBuilds::build_project_blocking(const String &p_config) {  	if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))  		return true; // No solution to build @@ -298,7 +298,7 @@ bool GodotSharpBuilds::build_project_blocking() {  	pr.step("Building project solution"); -	MonoBuildInfo build_info(GodotSharpDirs::get_project_sln_path(), "Tools"); +	MonoBuildInfo build_info(GodotSharpDirs::get_project_sln_path(), p_config);  	if (!GodotSharpBuilds::get_singleton()->build(build_info)) {  		GodotSharpBuilds::show_build_error_dialog("Failed to build project solution");  		return false; @@ -309,6 +309,11 @@ bool GodotSharpBuilds::build_project_blocking() {  	return true;  } +bool GodotSharpBuilds::editor_build_callback() { + +	return build_project_blocking("Tools"); +} +  GodotSharpBuilds *GodotSharpBuilds::singleton = NULL;  void GodotSharpBuilds::build_exit_callback(const MonoBuildInfo &p_build_info, int p_exit_code) { @@ -362,7 +367,7 @@ GodotSharpBuilds::GodotSharpBuilds() {  	singleton = this; -	EditorNode::get_singleton()->add_build_callback(&GodotSharpBuilds::build_project_blocking); +	EditorNode::get_singleton()->add_build_callback(&GodotSharpBuilds::editor_build_callback);  	// Build tool settings  	EditorSettings *ed_settings = EditorSettings::get_singleton(); @@ -462,6 +467,7 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {  	if (ex) {  		exited = true; +		GDMonoUtils::print_unhandled_exception(ex);  		String message = "The build constructor threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex);  		build_tab->on_build_exec_failed(message);  		ERR_EXPLAIN(message); @@ -482,6 +488,7 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {  	if (ex) {  		exited = true; +		GDMonoUtils::print_unhandled_exception(ex);  		String message = "The build method threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex);  		build_tab->on_build_exec_failed(message);  		ERR_EXPLAIN(message); diff --git a/modules/mono/editor/godotsharp_builds.h b/modules/mono/editor/godotsharp_builds.h index 5d2390ecd9..0574fbfe8c 100644 --- a/modules/mono/editor/godotsharp_builds.h +++ b/modules/mono/editor/godotsharp_builds.h @@ -93,7 +93,9 @@ public:  	static bool make_api_sln(APIType p_api_type); -	static bool build_project_blocking(); +	static bool build_project_blocking(const String &p_config); + +	static bool editor_build_callback();  	GodotSharpBuilds();  	~GodotSharpBuilds(); diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp index 975cf0f030..0919a7355b 100644 --- a/modules/mono/editor/godotsharp_editor.cpp +++ b/modules/mono/editor/godotsharp_editor.cpp @@ -41,6 +41,7 @@  #include "../utils/path_utils.h"  #include "bindings_generator.h"  #include "csharp_project.h" +#include "godotsharp_export.h"  #include "net_solution.h"  #ifdef WINDOWS_ENABLED @@ -316,6 +317,11 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) {  	EditorSettings *ed_settings = EditorSettings::get_singleton();  	EDITOR_DEF("mono/editor/external_editor", EDITOR_NONE);  	ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/editor/external_editor", PROPERTY_HINT_ENUM, "None,MonoDevelop,Visual Studio Code")); + +	// Export plugin +	Ref<GodotSharpExport> godotsharp_export; +	godotsharp_export.instance(); +	EditorExport::get_singleton()->add_export_plugin(godotsharp_export);  }  GodotSharpEditor::~GodotSharpEditor() { diff --git a/modules/mono/editor/godotsharp_editor.h b/modules/mono/editor/godotsharp_editor.h index 81c49aec30..66da814c8b 100644 --- a/modules/mono/editor/godotsharp_editor.h +++ b/modules/mono/editor/godotsharp_editor.h @@ -32,7 +32,6 @@  #define GODOTSHARP_EDITOR_H  #include "godotsharp_builds.h" -  #include "monodevelop_instance.h"  class GodotSharpEditor : public Node { diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp new file mode 100644 index 0000000000..387929a02e --- /dev/null +++ b/modules/mono/editor/godotsharp_export.cpp @@ -0,0 +1,163 @@ +/*************************************************************************/ +/*  godotsharp_export.cpp                                                */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                      https://godotengine.org                          */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */ +/*                                                                       */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the       */ +/* "Software"), to deal in the Software without restriction, including   */ +/* without limitation the rights to use, copy, modify, merge, publish,   */ +/* distribute, sublicense, and/or sell copies of the Software, and to    */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions:                                             */ +/*                                                                       */ +/* The above copyright notice and this permission notice shall be        */ +/* included in all copies or substantial portions of the Software.       */ +/*                                                                       */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ +/*************************************************************************/ + +#include "godotsharp_export.h" + +#include "../csharp_script.h" +#include "../godotsharp_defs.h" +#include "../godotsharp_dirs.h" +#include "godotsharp_builds.h" + +void GodotSharpExport::_export_file(const String &p_path, const String &p_type, const Set<String> &p_features) { + +	if (p_type != CSharpLanguage::get_singleton()->get_type()) +		return; + +	ERR_FAIL_COND(p_path.get_extension() != CSharpLanguage::get_singleton()->get_extension()); + +	// TODO what if the source file is not part of the game's C# project + +	if (!GLOBAL_GET("mono/export/include_scripts_content")) { +		// We don't want to include the source code on exported games +		add_file(p_path, Vector<uint8_t>(), false); +		skip(); +	} +} + +void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug, const String &p_path, int p_flags) { + +	// TODO right now there is no way to stop the export process with an error + +	String build_config = p_debug ? "Debug" : "Release"; + +	ERR_FAIL_COND(!GodotSharpBuilds::build_project_blocking(build_config)); + +	// Add API assemblies + +	String core_api_dll_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(API_ASSEMBLY_NAME ".dll"); +	ERR_FAIL_COND(!_add_assembly(core_api_dll_path, core_api_dll_path)); + +	String editor_api_dll_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"); +	ERR_FAIL_COND(!_add_assembly(editor_api_dll_path, editor_api_dll_path)); + +	// Add project assembly + +	String project_dll_name = ProjectSettings::get_singleton()->get("application/config/name"); +	if (project_dll_name.empty()) { +		project_dll_name = "UnnamedProject"; +	} + +	String project_dll_src_path = GodotSharpDirs::get_res_temp_assemblies_base_dir().plus_file(build_config).plus_file(project_dll_name + ".dll"); +	String project_dll_dst_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(project_dll_name + ".dll"); +	ERR_FAIL_COND(!_add_assembly(project_dll_src_path, project_dll_dst_path)); + +	// Add dependencies + +	MonoDomain *prev_domain = mono_domain_get(); +	MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.ProjectExportDomain"); + +	ERR_FAIL_COND(!export_domain); +	ERR_FAIL_COND(!mono_domain_set(export_domain, false)); + +	Map<String, String> dependencies; +	dependencies.insert("mscorlib", GDMono::get_singleton()->get_corlib_assembly()->get_path()); + +	GDMonoAssembly *scripts_assembly = GDMonoAssembly::load_from(project_dll_name, project_dll_src_path, /* refonly: */ true); + +	ERR_EXPLAIN("Cannot load refonly assembly: " + project_dll_name); +	ERR_FAIL_COND(!scripts_assembly); + +	Error depend_error = _get_assembly_dependencies(scripts_assembly, dependencies); + +	GDMono::get_singleton()->finalize_and_unload_domain(export_domain); +	mono_domain_set(prev_domain, false); + +	ERR_FAIL_COND(depend_error != OK); + +	for (Map<String, String>::Element *E = dependencies.front(); E; E = E->next()) { +		String depend_src_path = E->value(); +		String depend_dst_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(depend_src_path.get_file()); +		ERR_FAIL_COND(!_add_assembly(depend_src_path, depend_dst_path)); +	} +} + +bool GodotSharpExport::_add_assembly(const String &p_src_path, const String &p_dst_path) { + +	FileAccessRef f = FileAccess::open(p_src_path, FileAccess::READ); +	ERR_FAIL_COND_V(!f, false); + +	Vector<uint8_t> data; +	data.resize(f->get_len()); +	f->get_buffer(data.ptrw(), data.size()); + +	add_file(p_dst_path, data, false); + +	return true; +} + +Error GodotSharpExport::_get_assembly_dependencies(GDMonoAssembly *p_assembly, Map<String, String> &r_dependencies) { + +	MonoImage *image = p_assembly->get_image(); + +	for (int i = 0; i < mono_image_get_table_rows(image, MONO_TABLE_ASSEMBLYREF); i++) { +		MonoAssemblyName *ref_aname = aname_prealloc; +		mono_assembly_get_assemblyref(image, i, ref_aname); +		String ref_name = mono_assembly_name_get_name(ref_aname); + +		if (ref_name == "mscorlib" || r_dependencies.find(ref_name)) +			continue; + +		GDMonoAssembly *ref_assembly = NULL; +		if (!GDMono::get_singleton()->load_assembly(ref_name, ref_aname, &ref_assembly, /* refonly: */ true)) { +			ERR_EXPLAIN("Cannot load refonly assembly: " + ref_name); +			ERR_FAIL_V(ERR_CANT_RESOLVE); +		} + +		r_dependencies.insert(ref_name, ref_assembly->get_path()); + +		Error err = _get_assembly_dependencies(ref_assembly, r_dependencies); +		if (err != OK) +			return err; +	} + +	return OK; +} + +GodotSharpExport::GodotSharpExport() { +	// MonoAssemblyName is an incomplete type (internal to mono), so we can't allocate it ourselves. +	// There isn't any api to allocate an empty one either, so we need to do it this way. +	aname_prealloc = mono_assembly_name_new("whatever"); +	mono_assembly_name_free(aname_prealloc); // "it does not frees the object itself, only the name members" (typo included) +} + +GodotSharpExport::~GodotSharpExport() { +	if (aname_prealloc) +		mono_free(aname_prealloc); +} diff --git a/modules/mono/editor/godotsharp_export.h b/modules/mono/editor/godotsharp_export.h new file mode 100644 index 0000000000..b38db9660c --- /dev/null +++ b/modules/mono/editor/godotsharp_export.h @@ -0,0 +1,57 @@ +/*************************************************************************/ +/*  godotsharp_export.h                                                  */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                      https://godotengine.org                          */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */ +/*                                                                       */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the       */ +/* "Software"), to deal in the Software without restriction, including   */ +/* without limitation the rights to use, copy, modify, merge, publish,   */ +/* distribute, sublicense, and/or sell copies of the Software, and to    */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions:                                             */ +/*                                                                       */ +/* The above copyright notice and this permission notice shall be        */ +/* included in all copies or substantial portions of the Software.       */ +/*                                                                       */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ +/*************************************************************************/ + +#ifndef GODOTSHARP_EXPORT_H +#define GODOTSHARP_EXPORT_H + +#include <mono/metadata/image.h> + +#include "editor/editor_export.h" + +#include "../mono_gd/gd_mono_header.h" + +class GodotSharpExport : public EditorExportPlugin { + +	MonoAssemblyName *aname_prealloc; + +	bool _add_assembly(const String &p_src_path, const String &p_dst_path); + +	Error _get_assembly_dependencies(GDMonoAssembly *p_assembly, Map<String, String> &r_dependencies); + +protected: +	virtual void _export_file(const String &p_path, const String &p_type, const Set<String> &p_features); +	virtual void _export_begin(const Set<String> &p_features, bool p_debug, const String &p_path, int p_flags); + +public: +	GodotSharpExport(); +	~GodotSharpExport(); +}; + +#endif // GODOTSHARP_EXPORT_H diff --git a/modules/mono/editor/mono_bottom_panel.cpp b/modules/mono/editor/mono_bottom_panel.cpp index 20378a0162..32aec2a3b5 100644 --- a/modules/mono/editor/mono_bottom_panel.cpp +++ b/modules/mono/editor/mono_bottom_panel.cpp @@ -142,7 +142,7 @@ void MonoBottomPanel::_errors_toggled(bool p_pressed) {  void MonoBottomPanel::_build_project_pressed() { -	GodotSharpBuilds::get_singleton()->build_project_blocking(); +	GodotSharpBuilds::get_singleton()->build_project_blocking("Tools");  	MonoReloadNode::get_singleton()->restart_reload_timer();  	CSharpLanguage::get_singleton()->reload_assemblies_if_needed(true); diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 39474f8cbc..519c30045a 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -271,33 +271,44 @@ GDMonoAssembly **GDMono::get_loaded_assembly(const String &p_name) {  	return assemblies[domain_id].getptr(p_name);  } -bool GDMono::_load_assembly(const String &p_name, GDMonoAssembly **r_assembly) { +bool GDMono::load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly) { + +	CRASH_COND(!r_assembly); + +	MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8()); +	bool result = load_assembly(p_name, aname, r_assembly, p_refonly); +	mono_assembly_name_free(aname); +	mono_free(aname); + +	return result; +} + +bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly) {  	CRASH_COND(!r_assembly);  	if (OS::get_singleton()->is_stdout_verbose()) -		OS::get_singleton()->print((String() + "Mono: Loading assembly " + p_name + "...\n").utf8()); +		OS::get_singleton()->print((String() + "Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "...\n").utf8());  	MonoImageOpenStatus status = MONO_IMAGE_OK; -	MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8()); -	MonoAssembly *assembly = mono_assembly_load_full(aname, NULL, &status, false); -	mono_assembly_name_free(aname); +	MonoAssembly *assembly = mono_assembly_load_full(p_aname, NULL, &status, p_refonly);  	if (!assembly)  		return false; +	ERR_FAIL_COND_V(status != MONO_IMAGE_OK, false); +  	uint32_t domain_id = mono_domain_get_id(mono_domain_get());  	GDMonoAssembly **stored_assembly = assemblies[domain_id].getptr(p_name); -	ERR_FAIL_COND_V(status != MONO_IMAGE_OK, false);  	ERR_FAIL_COND_V(stored_assembly == NULL, false); -  	ERR_FAIL_COND_V((*stored_assembly)->get_assembly() != assembly, false); +  	*r_assembly = *stored_assembly;  	if (OS::get_singleton()->is_stdout_verbose()) -		OS::get_singleton()->print(String("Mono: Assembly " + p_name + " loaded from path: " + (*r_assembly)->get_path() + "\n").utf8()); +		OS::get_singleton()->print(String("Mono: Assembly " + p_name + (p_refonly ? " (refonly)" : "") + " loaded from path: " + (*r_assembly)->get_path() + "\n").utf8());  	return true;  } @@ -307,7 +318,7 @@ bool GDMono::_load_corlib_assembly() {  	if (corlib_assembly)  		return true; -	bool success = _load_assembly("mscorlib", &corlib_assembly); +	bool success = load_assembly("mscorlib", &corlib_assembly);  	if (success)  		GDMonoUtils::update_corlib_cache(); @@ -320,7 +331,7 @@ bool GDMono::_load_core_api_assembly() {  	if (api_assembly)  		return true; -	bool success = _load_assembly(API_ASSEMBLY_NAME, &api_assembly); +	bool success = load_assembly(API_ASSEMBLY_NAME, &api_assembly);  	if (success)  		GDMonoUtils::update_godot_api_cache(); @@ -334,7 +345,7 @@ bool GDMono::_load_editor_api_assembly() {  	if (editor_api_assembly)  		return true; -	return _load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly); +	return load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly);  }  #endif @@ -346,7 +357,7 @@ bool GDMono::_load_editor_tools_assembly() {  	_GDMONO_SCOPE_DOMAIN_(tools_domain) -	return _load_assembly(EDITOR_TOOLS_ASSEMBLY_NAME, &editor_tools_assembly); +	return load_assembly(EDITOR_TOOLS_ASSEMBLY_NAME, &editor_tools_assembly);  }  #endif @@ -360,7 +371,7 @@ bool GDMono::_load_project_assembly() {  		name = "UnnamedProject";  	} -	bool success = _load_assembly(name, &project_assembly); +	bool success = load_assembly(name, &project_assembly);  	if (success)  		mono_assembly_set_main(project_assembly->get_assembly()); @@ -511,6 +522,37 @@ Error GDMono::reload_scripts_domain() {  }  #endif +Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) { + +	CRASH_COND(p_domain == NULL); + +	String domain_name = mono_domain_get_friendly_name(p_domain); + +	if (OS::get_singleton()->is_stdout_verbose()) { +		OS::get_singleton()->print(String("Mono: Unloading domain `" + domain_name + "`...\n").utf8()); +	} + +	if (mono_domain_get() != root_domain) +		mono_domain_set(root_domain, true); + +	mono_gc_collect(mono_gc_max_generation()); +	mono_domain_finalize(p_domain, 2000); +	mono_gc_collect(mono_gc_max_generation()); + +	_domain_assemblies_cleanup(mono_domain_get_id(p_domain)); + +	MonoObject *ex = NULL; +	mono_domain_try_unload(p_domain, &ex); + +	if (ex) { +		ERR_PRINTS("Exception thrown when unloading domain `" + domain_name + "`:"); +		mono_print_unhandled_exception(ex); +		return FAILED; +	} + +	return OK; +} +  GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {  	MonoImage *image = mono_class_get_image(p_raw_class); diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h index 67251778c6..07f649c442 100644 --- a/modules/mono/mono_gd/gd_mono.h +++ b/modules/mono/mono_gd/gd_mono.h @@ -94,8 +94,6 @@ class GDMono {  	void _initialize_and_check_api_hashes();  #endif -	bool _load_assembly(const String &p_name, GDMonoAssembly **r_assembly); -  	GDMonoLog *gdmono_log;  #ifdef WINDOWS_ENABLED @@ -145,6 +143,10 @@ public:  	Error reload_scripts_domain();  #endif +	bool load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly = false); +	bool load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly = false); +	Error finalize_and_unload_domain(MonoDomain *p_domain); +  	void initialize();  	GDMono(); diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp index ef39b8549d..e0743346aa 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ b/modules/mono/mono_gd/gd_mono_assembly.cpp @@ -43,7 +43,23 @@  bool GDMonoAssembly::no_search = false;  Vector<String> GDMonoAssembly::search_dirs; -MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_data) { +MonoAssembly *GDMonoAssembly::assembly_search_hook(MonoAssemblyName *aname, void *user_data) { +	return GDMonoAssembly::_search_hook(aname, user_data, false); +} + +MonoAssembly *GDMonoAssembly::assembly_refonly_search_hook(MonoAssemblyName *aname, void *user_data) { +	return GDMonoAssembly::_search_hook(aname, user_data, true); +} + +MonoAssembly *GDMonoAssembly::assembly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) { +	return GDMonoAssembly::_preload_hook(aname, assemblies_path, user_data, false); +} + +MonoAssembly *GDMonoAssembly::assembly_refonly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) { +	return GDMonoAssembly::_preload_hook(aname, assemblies_path, user_data, true); +} + +MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_data, bool refonly) {  	(void)user_data; // UNUSED @@ -60,7 +76,7 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d  	no_search = true; // Avoid the recursion madness  	String path; -	MonoAssembly *res = NULL; +	GDMonoAssembly *res = NULL;  	for (int i = 0; i < search_dirs.size(); i++) {  		const String &search_dir = search_dirs[i]; @@ -68,19 +84,19 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d  		if (has_extension) {  			path = search_dir.plus_file(name);  			if (FileAccess::exists(path)) { -				res = _load_assembly_from(name.get_basename(), path); +				res = _load_assembly_from(name.get_basename(), path, refonly);  				break;  			}  		} else {  			path = search_dir.plus_file(name + ".dll");  			if (FileAccess::exists(path)) { -				res = _load_assembly_from(name, path); +				res = _load_assembly_from(name, path, refonly);  				break;  			}  			path = search_dir.plus_file(name + ".exe");  			if (FileAccess::exists(path)) { -				res = _load_assembly_from(name, path); +				res = _load_assembly_from(name, path, refonly);  				break;  			}  		} @@ -88,17 +104,15 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d  	no_search = false; -	return res; +	return res ? res->get_assembly() : NULL;  } -MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) { +MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly) {  	(void)user_data; // UNUSED  	if (search_dirs.empty()) { -#ifdef TOOLS_DOMAIN  		search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir()); -#endif  		search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir());  		search_dirs.push_back(OS::get_singleton()->get_resource_dir());  		search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir()); @@ -121,10 +135,11 @@ MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **asse  	if (has_extension ? name == "mscorlib.dll" : name == "mscorlib") {  		GDMonoAssembly **stored_assembly = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name); -		if (stored_assembly) return (*stored_assembly)->get_assembly(); +		if (stored_assembly) +			return (*stored_assembly)->get_assembly();  		String path; -		MonoAssembly *res = NULL; +		GDMonoAssembly *res = NULL;  		for (int i = 0; i < search_dirs.size(); i++) {  			const String &search_dir = search_dirs[i]; @@ -132,53 +147,61 @@ MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **asse  			if (has_extension) {  				path = search_dir.plus_file(name);  				if (FileAccess::exists(path)) { -					res = _load_assembly_from(name.get_basename(), path); +					res = _load_assembly_from(name.get_basename(), path, refonly);  					break;  				}  			} else {  				path = search_dir.plus_file(name + ".dll");  				if (FileAccess::exists(path)) { -					res = _load_assembly_from(name, path); +					res = _load_assembly_from(name, path, refonly); +					break; +				} + +				path = search_dir.plus_file(name + ".exe"); +				if (FileAccess::exists(path)) { +					res = _load_assembly_from(name, path, refonly);  					break;  				}  			}  		} -		if (res) return res; +		return res ? res->get_assembly() : NULL;  	}  	return NULL;  } -MonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path) { +GDMonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly) {  	GDMonoAssembly *assembly = memnew(GDMonoAssembly(p_name, p_path)); -	MonoDomain *domain = mono_domain_get(); - -	Error err = assembly->load(domain); +	Error err = assembly->load(p_refonly);  	if (err != OK) {  		memdelete(assembly);  		ERR_FAIL_V(NULL);  	} +	MonoDomain *domain = mono_domain_get();  	GDMono::get_singleton()->add_assembly(domain ? mono_domain_get_id(domain) : 0, assembly); -	return assembly->get_assembly(); +	return assembly;  }  void GDMonoAssembly::initialize() { -	// TODO refonly as well? -	mono_install_assembly_preload_hook(&GDMonoAssembly::_preload_hook, NULL); -	mono_install_assembly_search_hook(&GDMonoAssembly::_search_hook, NULL); +	mono_install_assembly_search_hook(&assembly_search_hook, NULL); +	mono_install_assembly_refonly_search_hook(&assembly_refonly_search_hook, NULL); +	mono_install_assembly_preload_hook(&assembly_preload_hook, NULL); +	mono_install_assembly_refonly_preload_hook(&assembly_refonly_preload_hook, NULL);  } -Error GDMonoAssembly::load(MonoDomain *p_domain) { +Error GDMonoAssembly::load(bool p_refonly) {  	ERR_FAIL_COND_V(loaded, ERR_FILE_ALREADY_IN_USE); +	refonly = p_refonly; +  	uint64_t last_modified_time = FileAccess::get_modified_time(path);  	Vector<uint8_t> data = FileAccess::get_file_as_array(path); @@ -190,7 +213,7 @@ Error GDMonoAssembly::load(MonoDomain *p_domain) {  	image = mono_image_open_from_data_with_name(  			(char *)&data[0], data.size(), -			true, &status, false, +			true, &status, refonly,  			image_filename.utf8().get_data());  	ERR_FAIL_COND_V(status != MONO_IMAGE_OK || image == NULL, ERR_FILE_CANT_OPEN); @@ -213,15 +236,10 @@ no_pdb:  #endif -	assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, false); +	assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, refonly);  	ERR_FAIL_COND_V(status != MONO_IMAGE_OK || assembly == NULL, ERR_FILE_CANT_OPEN); -	if (p_domain && mono_image_get_entry_point(image)) { -		// TODO should this be removed? do we want to call main? what other effects does this have? -		mono_jit_exec(p_domain, assembly, 0, NULL); -	} -  	loaded = true;  	modified_time = last_modified_time; @@ -373,12 +391,26 @@ GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class)  	return match;  } +GDMonoAssembly *GDMonoAssembly::load_from(const String &p_name, const String &p_path, bool p_refonly) { + +	GDMonoAssembly **loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name); +	if (loaded_asm) +		return *loaded_asm; + +	no_search = true; +	GDMonoAssembly *res = _load_assembly_from(p_name, p_path, p_refonly); +	no_search = false; + +	return res; +} +  GDMonoAssembly::GDMonoAssembly(const String &p_name, const String &p_path) {  	loaded = false;  	gdobject_class_cache_updated = false;  	name = p_name;  	path = p_path; +	refonly = false;  	modified_time = 0;  	assembly = NULL;  	image = NULL; diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h index 8a5fa19626..5cf744a5a2 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.h +++ b/modules/mono/mono_gd/gd_mono_assembly.h @@ -71,6 +71,7 @@ class GDMonoAssembly {  	MonoAssembly *assembly;  	MonoImage *image; +	bool refonly;  	bool loaded;  	String name; @@ -90,19 +91,25 @@ class GDMonoAssembly {  	static bool no_search;  	static Vector<String> search_dirs; -	static MonoAssembly *_search_hook(MonoAssemblyName *aname, void *user_data); -	static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data); +	static MonoAssembly *assembly_search_hook(MonoAssemblyName *aname, void *user_data); +	static MonoAssembly *assembly_refonly_search_hook(MonoAssemblyName *aname, void *user_data); +	static MonoAssembly *assembly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data); +	static MonoAssembly *assembly_refonly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data); -	static MonoAssembly *_load_assembly_from(const String &p_name, const String &p_path); +	static MonoAssembly *_search_hook(MonoAssemblyName *aname, void *user_data, bool refonly); +	static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly); + +	static GDMonoAssembly *_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly);  	friend class GDMono;  	static void initialize();  public: -	Error load(MonoDomain *p_domain); +	Error load(bool p_refonly);  	Error wrapper_for_image(MonoImage *p_image);  	void unload(); +	_FORCE_INLINE_ bool is_refonly() const { return refonly; }  	_FORCE_INLINE_ bool is_loaded() const { return loaded; }  	_FORCE_INLINE_ MonoImage *get_image() const { return image; }  	_FORCE_INLINE_ MonoAssembly *get_assembly() const { return assembly; } @@ -115,6 +122,8 @@ public:  	GDMonoClass *get_object_derived_class(const StringName &p_class); +	static GDMonoAssembly *load_from(const String &p_name, const String &p_path, bool p_refonly); +  	GDMonoAssembly(const String &p_name, const String &p_path = String());  	~GDMonoAssembly();  }; diff --git a/platform/iphone/in_app_store.h b/platform/iphone/in_app_store.h index 7d53eaae20..353438676d 100644 --- a/platform/iphone/in_app_store.h +++ b/platform/iphone/in_app_store.h @@ -46,6 +46,7 @@ class InAppStore : public Object {  public:  	Error request_product_info(Variant p_params); +	Error restore_purchases();  	Error purchase(Variant p_params);  	int get_pending_event_count(); diff --git a/platform/iphone/in_app_store.mm b/platform/iphone/in_app_store.mm index 9bb3d7d3fa..6fa189e917 100644 --- a/platform/iphone/in_app_store.mm +++ b/platform/iphone/in_app_store.mm @@ -63,6 +63,7 @@ InAppStore *InAppStore::instance = NULL;  void InAppStore::_bind_methods() {  	ClassDB::bind_method(D_METHOD("request_product_info"), &InAppStore::request_product_info); +	ClassDB::bind_method(D_METHOD("restore_purchases"), &InAppStore::restore_purchases);  	ClassDB::bind_method(D_METHOD("purchase"), &InAppStore::purchase);  	ClassDB::bind_method(D_METHOD("get_pending_event_count"), &InAppStore::get_pending_event_count); @@ -153,6 +154,14 @@ Error InAppStore::request_product_info(Variant p_params) {  	return OK;  }; +Error InAppStore::restore_purchases() { + +	printf("restoring purchases!\n"); +	[[SKPaymentQueue defaultQueue] restoreCompletedTransactions]; + +	return OK; +}; +  @interface TransObserver : NSObject <SKPaymentTransactionObserver> {  };  @end @@ -236,6 +245,11 @@ Error InAppStore::request_product_info(Variant p_params) {  				printf("status transaction restored!\n");  				String pid = String::utf8([transaction.originalTransaction.payment.productIdentifier UTF8String]);  				InAppStore::get_singleton()->_record_purchase(pid); +				Dictionary ret; +				ret["type"] = "restore"; +				ret["result"] = "ok"; +				ret["product_id"] = pid; +				InAppStore::get_singleton()->_post_event(ret);  				[[SKPaymentQueue defaultQueue] finishTransaction:transaction];  			} break;  			default: { diff --git a/platform/windows/godot_res.rc b/platform/windows/godot_res.rc index c535a749c0..f2dca10d55 100644 --- a/platform/windows/godot_res.rc +++ b/platform/windows/godot_res.rc @@ -3,11 +3,9 @@  #define _STR(m_x) #m_x  #define _MKSTR(m_x) _STR(m_x)  #endif +  #ifndef VERSION_PATCH  #define VERSION_PATCH 0 -#define PATCH_STRING -#else -#define PATCH_STRING "." _MKSTR(VERSION_PATCH)  #endif  GODOT_ICON ICON platform/windows/godot.ico @@ -24,12 +22,12 @@ BEGIN          BEGIN              VALUE "CompanyName",            "Godot Engine"              VALUE "FileDescription",        VERSION_NAME " Editor" -            VALUE "FileVersion",            _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) "." _MKSTR(VERSION_PATCH) +            VALUE "FileVersion",            VERSION_NUMBER              VALUE "ProductName",            VERSION_NAME              VALUE "Licence",                "MIT" -            VALUE "LegalCopyright",         "Copyright (c) 2007-" _MKSTR(VERSION_YEAR) " Juan Linietsky, Ariel Manzur" +            VALUE "LegalCopyright",         "Copyright (c) 2007-" _MKSTR(VERSION_YEAR) " Juan Linietsky, Ariel Manzur and contributors"              VALUE "Info",                   "https://godotengine.org" -            VALUE "ProductVersion",         _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) PATCH_STRING "." VERSION_BUILD +            VALUE "ProductVersion",         VERSION_FULL_BUILD          END      END      BLOCK "VarFileInfo" diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index 721641e09b..f8a5c7f400 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -188,7 +188,9 @@ void Spatial::_notification(int p_what) {  					if (data.gizmo.is_valid()) {  						data.gizmo->create();  						if (data.gizmo->can_draw()) { -							data.gizmo->redraw(); +							if (is_visible_in_tree()) { +								data.gizmo->redraw(); +							}  						}  						data.gizmo->transform();  					} @@ -409,7 +411,9 @@ void Spatial::set_gizmo(const Ref<SpatialGizmo> &p_gizmo) {  		data.gizmo->create();  		if (data.gizmo->can_draw()) { -			data.gizmo->redraw(); +			if (is_visible_in_tree()) { +				data.gizmo->redraw(); +			}  		}  		data.gizmo->transform();  	} diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 3d58aa65f8..ae21775c55 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -121,7 +121,7 @@ Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_h  	}  	if (!has_user_agent) { -		headers.push_back("User-Agent: GodotEngine/" + String(VERSION_MKSTRING) + " (" + OS::get_singleton()->get_name() + ")"); +		headers.push_back("User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")");  	}  	if (!has_accept) { diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp index 91c801c016..bb5295709a 100644 --- a/scene/resources/scene_format_text.cpp +++ b/scene/resources/scene_format_text.cpp @@ -1506,7 +1506,6 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r  			title += "load_steps=" + itos(load_steps) + " ";  		}  		title += "format=" + itos(FORMAT_VERSION) + ""; -		//title+="engine_version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\"";  		f->store_string(title);  		f->store_line("]\n"); //one empty line diff --git a/scene/resources/shape_2d.h b/scene/resources/shape_2d.h index ed655b8a93..7eb0406bd8 100644 --- a/scene/resources/shape_2d.h +++ b/scene/resources/shape_2d.h @@ -45,7 +45,7 @@ protected:  	Shape2D(const RID &p_rid);  public: -	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { return true; } +	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { return get_rect().has_point(p_point); }  	void set_custom_solver_bias(real_t p_bias);  	real_t get_custom_solver_bias() const; diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index f256e0397d..626fda50df 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -101,7 +101,7 @@ StyleBox::StyleBox() {  	}  } -void StyleBoxTexture::set_texture(RES p_texture) { +void StyleBoxTexture::set_texture(Ref<Texture> p_texture) {  	if (texture == p_texture)  		return; @@ -112,12 +112,12 @@ void StyleBoxTexture::set_texture(RES p_texture) {  	_change_notify("texture");  } -RES StyleBoxTexture::get_texture() const { +Ref<Texture> StyleBoxTexture::get_texture() const {  	return texture;  } -void StyleBoxTexture::set_normal_map(RES p_normal_map) { +void StyleBoxTexture::set_normal_map(Ref<Texture> p_normal_map) {  	if (normal_map == p_normal_map)  		return; @@ -125,7 +125,7 @@ void StyleBoxTexture::set_normal_map(RES p_normal_map) {  	emit_changed();  } -RES StyleBoxTexture::get_normal_map() const { +Ref<Texture> StyleBoxTexture::get_normal_map() const {  	return normal_map;  } diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index fb79aa360e..c1d84fe19f 100644 --- a/scene/resources/style_box.h +++ b/scene/resources/style_box.h @@ -112,11 +112,11 @@ public:  	void set_region_rect(const Rect2 &p_region_rect);  	Rect2 get_region_rect() const; -	void set_texture(RES p_texture); -	RES get_texture() const; +	void set_texture(Ref<Texture> p_texture); +	Ref<Texture> get_texture() const; -	void set_normal_map(RES p_normal_map); -	RES get_normal_map() const; +	void set_normal_map(Ref<Texture> p_normal_map); +	Ref<Texture> get_normal_map() const;  	void set_draw_center(bool p_enabled);  	bool is_draw_center_enabled() const;  |