From a556bdf131a913f482f3586bba8d89d2ec0136d2 Mon Sep 17 00:00:00 2001 From: Cedric Hippmann Date: Wed, 25 Aug 2021 11:44:16 +0200 Subject: [PATCH] Show warning when JAVA_HOME is not defined (#261) * #133 Don't crash when JAVA_HOME is not defined and show a warning instead * #133 Add super constructor call * #133 Centralize configuration check and error message production and use them from within the editor plugin * Remove test error * Use getters to prevent modifications outside GDKotlin * Return const reference and mark getter as const --- CMakeLists.txt | 2 +- src/editor/dialog/about_dialog.cpp | 4 +- src/editor/dialog/error_dialog.cpp | 55 ++++++++++++++++++++++++++ src/editor/dialog/error_dialog.h | 23 +++++++++++ src/editor/godot_kotlin_jvm_editor.cpp | 12 +++++- src/editor/godot_kotlin_jvm_editor.h | 2 + src/gd_kotlin.cpp | 34 ++++++++++++++-- src/gd_kotlin.h | 10 +++++ 8 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 src/editor/dialog/error_dialog.cpp create mode 100644 src/editor/dialog/error_dialog.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 992afc300d..5f33f98d0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ set(GODOT_ROOT_DIR ../../) # Get sources file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.cpp) -add_library(${PROJECT_NAME} SHARED register_types.cpp ${SOURCES} src/gd_kotlin.cpp src/gd_kotlin.h src/godotkotlin_defs.h src/jni/wrapper.h src/kt_function.cpp src/kt_function.h src/kt_property.cpp src/kt_property.h src/jni/local_frame.cpp src/jni/local_frame.h src/kt_signal_info.cpp src/kt_signal_info.h src/bridges/memory_bridge.cpp src/bridges/memory_bridge.h src/jni/java_method_signature.cpp src/jni/java_method_signature.h src/java_instance_wrapper.h src/shared_buffer.h src/shared_buffer.cpp src/type_manager.cpp src/type_manager.h src/bridges_manager.cpp src/bridges_manager.h src/bridges/variant_array_bridge.cpp src/bridges/variant_array_bridge.h src/bridges/constants.h src/bridges/dictionary_bridge.cpp src/bridges/dictionary_bridge.h src/bridges/bridges_utils.h src/bridges/rid_bridge.cpp src/bridges/rid_bridge.h src/bridges/node_path_bridge.cpp src/bridges/node_path_bridge.h src/bridges/pool_byte_array_bridge.h src/bridges/pool_byte_array_bridge.cpp src/bridges/pool_color_array_bridge.h src/bridges/pool_color_array_bridge.cpp src/bridges/pool_int_array_bridge.h src/bridges/pool_int_array_bridge.cpp src/bridges/pool_real_array_bridge.h src/bridges/pool_real_array_bridge.cpp src/bridges/pool_string_array_bridge.h src/bridges/pool_string_array_bridge.cpp src/bridges/pool_vector2_array_bridge.h src/bridges/pool_vector2_array_bridge.cpp src/bridges/pool_vector3_array_bridge.h src/bridges/pool_vector3_array_bridge.cpp src/logging.h src/kt_constructor.cpp src/kt_constructor.h src/bridges/gd_print_bridge.cpp src/bridges/gd_print_bridge.h src/kotlin_editor_export_plugin.cpp src/kotlin_editor_export_plugin.h src/jni/platforms/jvm_desktop.cpp src/jni/platforms/jvm_android.cpp src/jni/platforms/init_args_desktop.cpp src/jni/platforms/init_args_android.cpp src/ref_db.h src/ref_db.cpp src/editor/godot_kotlin_jvm_editor.cpp src/editor/godot_kotlin_jvm_editor.h src/editor/menu_option.h src/editor/build/build_manager.cpp src/editor/build/build_manager.h src/editor/panel/bottom_panel.cpp src/editor/panel/bottom_panel.h src/editor/dialog/build_dialog.cpp src/editor/dialog/build_dialog.h src/editor/dialog/about_dialog.cpp src/editor/dialog/about_dialog.h src/long_string_queue.h src/long_string_queue.cpp src/jni/class_loader.h src/jni/class_loader.cpp src/java_singleton_wrapper.h) +add_library(${PROJECT_NAME} SHARED register_types.cpp ${SOURCES} src/gd_kotlin.cpp src/gd_kotlin.h src/godotkotlin_defs.h src/jni/wrapper.h src/kt_function.cpp src/kt_function.h src/kt_property.cpp src/kt_property.h src/jni/local_frame.cpp src/jni/local_frame.h src/kt_signal_info.cpp src/kt_signal_info.h src/bridges/memory_bridge.cpp src/bridges/memory_bridge.h src/jni/java_method_signature.cpp src/jni/java_method_signature.h src/java_instance_wrapper.h src/shared_buffer.h src/shared_buffer.cpp src/type_manager.cpp src/type_manager.h src/bridges_manager.cpp src/bridges_manager.h src/bridges/variant_array_bridge.cpp src/bridges/variant_array_bridge.h src/bridges/constants.h src/bridges/dictionary_bridge.cpp src/bridges/dictionary_bridge.h src/bridges/bridges_utils.h src/bridges/rid_bridge.cpp src/bridges/rid_bridge.h src/bridges/node_path_bridge.cpp src/bridges/node_path_bridge.h src/bridges/pool_byte_array_bridge.h src/bridges/pool_byte_array_bridge.cpp src/bridges/pool_color_array_bridge.h src/bridges/pool_color_array_bridge.cpp src/bridges/pool_int_array_bridge.h src/bridges/pool_int_array_bridge.cpp src/bridges/pool_real_array_bridge.h src/bridges/pool_real_array_bridge.cpp src/bridges/pool_string_array_bridge.h src/bridges/pool_string_array_bridge.cpp src/bridges/pool_vector2_array_bridge.h src/bridges/pool_vector2_array_bridge.cpp src/bridges/pool_vector3_array_bridge.h src/bridges/pool_vector3_array_bridge.cpp src/logging.h src/kt_constructor.cpp src/kt_constructor.h src/bridges/gd_print_bridge.cpp src/bridges/gd_print_bridge.h src/kotlin_editor_export_plugin.cpp src/kotlin_editor_export_plugin.h src/jni/platforms/jvm_desktop.cpp src/jni/platforms/jvm_android.cpp src/jni/platforms/init_args_desktop.cpp src/jni/platforms/init_args_android.cpp src/ref_db.h src/ref_db.cpp src/editor/godot_kotlin_jvm_editor.cpp src/editor/godot_kotlin_jvm_editor.h src/editor/menu_option.h src/editor/build/build_manager.cpp src/editor/build/build_manager.h src/editor/panel/bottom_panel.cpp src/editor/panel/bottom_panel.h src/editor/dialog/build_dialog.cpp src/editor/dialog/build_dialog.h src/editor/dialog/about_dialog.cpp src/editor/dialog/about_dialog.h src/long_string_queue.h src/long_string_queue.cpp src/jni/class_loader.h src/jni/class_loader.cpp src/java_singleton_wrapper.h src/editor/dialog/error_dialog.cpp src/editor/dialog/error_dialog.h) # JNI find_package(JNI REQUIRED) diff --git a/src/editor/dialog/about_dialog.cpp b/src/editor/dialog/about_dialog.cpp index d6a6ecff6c..1e17138bfd 100644 --- a/src/editor/dialog/about_dialog.cpp +++ b/src/editor/dialog/about_dialog.cpp @@ -9,7 +9,7 @@ #include #include "about_dialog.h" -AboutDialog::AboutDialog(): about_dialog_check_box(memnew(CheckBox)) { +AboutDialog::AboutDialog(): AcceptDialog(), about_dialog_check_box(memnew(CheckBox)) { _EDITOR_DEF("kotlin_jvm/editor/show_info_on_start", true, false); ClassDB::bind_method(D_METHOD("on_about_to_show"), &AboutDialog::on_about_to_show); ClassDB::bind_method(D_METHOD("on_checkbox_toggled"), &AboutDialog::on_checkbox_toggled); @@ -28,7 +28,7 @@ AboutDialog::AboutDialog(): about_dialog_check_box(memnew(CheckBox)) { about_vbox->add_child(about_hbox); TextureRect* about_icon{memnew(TextureRect)}; - about_icon->set_texture(about_icon->get_icon("NodeWarning", "EditorIcons")); + about_icon->set_texture(get_icon("Warning", "EditorIcons")); about_hbox->add_child(about_icon); RichTextLabel* about_label{memnew(RichTextLabel)}; diff --git a/src/editor/dialog/error_dialog.cpp b/src/editor/dialog/error_dialog.cpp new file mode 100644 index 0000000000..912e76cfd0 --- /dev/null +++ b/src/editor/dialog/error_dialog.cpp @@ -0,0 +1,55 @@ + +#ifdef TOOLS_ENABLED + +#include +#include +#include +#include +#include "error_dialog.h" + +ErrorDialog::ErrorDialog(): AcceptDialog(), error_message_label(memnew(RichTextLabel)) { + VBoxContainer* about_vbox{memnew(VBoxContainer)}; + add_child(about_vbox); + + HBoxContainer* about_hbox{memnew(HBoxContainer)}; + about_vbox->add_child(about_hbox); + + TextureRect* icon{memnew(TextureRect)}; + icon->set_texture(get_icon("Warning", "EditorIcons")); + about_hbox->add_child(icon); + + about_hbox->add_child(error_message_label); + error_message_label->set_custom_minimum_size(Size2{600, 300} * EDSCALE); + error_message_label->set_v_size_flags(Control::SizeFlags::SIZE_EXPAND_FILL); + + error_message_label->set_scroll_active(true); + error_message_label->set_use_bbcode(true); +} + +void ErrorDialog::show_with_error(const String& error_title, const String& error_message) { + set_title(error_title); + error_message_label->set_bbcode(error_message); + popup_centered_minsize(); +} + +void ErrorDialog::show_with_errors(const String& dialog_title, const Vector>& errors) { + set_title(dialog_title); + String error_message{}; + + for (int i = 0; i < errors.size(); i++) { + Pair error = errors[i]; + + if (i != 0) { + error_message += String{"\n\n"}; + } + + error_message += String{"[u]"} + error.first + String{"[/u]"}; + error_message += String{"\n"}; + error_message += error.second; + } + + error_message_label->set_bbcode(error_message); + popup_centered_minsize(); +} + +#endif //TOOLS_ENABLED \ No newline at end of file diff --git a/src/editor/dialog/error_dialog.h b/src/editor/dialog/error_dialog.h new file mode 100644 index 0000000000..8bb1cca3ba --- /dev/null +++ b/src/editor/dialog/error_dialog.h @@ -0,0 +1,23 @@ +#ifdef TOOLS_ENABLED + +#ifndef GODOT_JVM_ERROR_DIALOG_H +#define GODOT_JVM_ERROR_DIALOG_H + + +#include +#include + +class ErrorDialog : public AcceptDialog { +public: + ErrorDialog(); + + void show_with_error(const String& error_title, const String& error_message); + void show_with_errors(const String& dialog_title, const Vector>& errors); + +private: + RichTextLabel* error_message_label; +}; + + +#endif //GODOT_JVM_ERROR_DIALOG_H +#endif //TOOLS_ENABLED \ No newline at end of file diff --git a/src/editor/godot_kotlin_jvm_editor.cpp b/src/editor/godot_kotlin_jvm_editor.cpp index 081fed9cd0..3c2bfe8d0c 100644 --- a/src/editor/godot_kotlin_jvm_editor.cpp +++ b/src/editor/godot_kotlin_jvm_editor.cpp @@ -6,6 +6,7 @@ #include #include #include +#include void GodotKotlinJvmEditor::on_file_system_dock_file_moved( // NOLINT(readability-convert-member-functions-to-static) const String& file, @@ -143,11 +144,19 @@ void GodotKotlinJvmEditor::_notificationv(int p_notification, bool p_reversed) { menu_pop_up->add_item("About Godot Kotlin JVM"); editor_base_control->add_child(about_dialog); + editor_base_control->add_child(error_dialog); FileSystemDock* file_system_dock = get_editor_interface()->get_file_system_dock(); file_system_dock->connect("files_moved", this, "on_file_system_dock_file_moved"); file_system_dock->connect("file_removed", this, "on_file_system_dock_file_removed"); file_system_dock->connect("folder_moved", this, "on_file_system_dock_folder_moved"); + + if (!GDKotlin::get_instance().initialized()) { + error_dialog->show_with_errors( + "Godot-Jvm configuration errors encountered", + GDKotlin::get_instance().get_configuration_errors() + ); + } } } @@ -183,7 +192,8 @@ GodotKotlinJvmEditor::GodotKotlinJvmEditor() : bottom_panel(memnew(BottomPanel)), tool_bar_build_button(memnew(ToolButton)), build_dialog(memnew(BuildDialog)), - about_dialog(memnew(AboutDialog)) { + about_dialog(memnew(AboutDialog)), + error_dialog(memnew(ErrorDialog)) { } diff --git a/src/editor/godot_kotlin_jvm_editor.h b/src/editor/godot_kotlin_jvm_editor.h index f67b2428c3..c2616fcaa6 100644 --- a/src/editor/godot_kotlin_jvm_editor.h +++ b/src/editor/godot_kotlin_jvm_editor.h @@ -6,6 +6,7 @@ #include +#include "dialog/error_dialog.h" #include "dialog/about_dialog.h" #include "dialog/build_dialog.h" #include "menu_option.h" @@ -31,6 +32,7 @@ class GodotKotlinJvmEditor : public EditorPlugin { private: GodotKotlinJvmEditor(); AboutDialog* about_dialog; + ErrorDialog* error_dialog; BuildDialog* build_dialog; ToolButton* tool_bar_build_button; BottomPanel* bottom_panel; diff --git a/src/gd_kotlin.cpp b/src/gd_kotlin.cpp index 6bdbf603f1..be26590ff9 100644 --- a/src/gd_kotlin.cpp +++ b/src/gd_kotlin.cpp @@ -139,6 +139,10 @@ void GDKotlin::init() { return; } + if (!check_configuration()) { + return; + } + jni::InitArgs args; #ifndef __ANDROID__ args.version = JNI_VERSION_1_8; @@ -264,8 +268,7 @@ void GDKotlin::init() { #ifndef __ANDROID__ if (jvm_type_argument == GdKotlinConfiguration::jvm_string_identifier) { configuration.set_vm_type(jni::Jvm::JVM); - } - else if (jvm_type_argument == GdKotlinConfiguration::graal_native_image_string_identifier) { + } else if (jvm_type_argument == GdKotlinConfiguration::graal_native_image_string_identifier) { configuration.set_vm_type(jni::Jvm::GRAAL_NATIVE_IMAGE); } @@ -376,6 +379,7 @@ void GDKotlin::init() { jni::JObject() #endif ); + is_initialized = true; } void GDKotlin::finish() { @@ -543,7 +547,7 @@ jni::JObject GDKotlin::_prepare_class_loader(jni::Env& p_env, jni::Jvm::Type typ LOG_INFO(vformat("Loading bootstrap jar: %s", bootstrap_jar)) - jni::JObject class_loader {ClassLoader::provide_loader(p_env, bootstrap_jar, jni::JObject(nullptr))}; + jni::JObject class_loader{ClassLoader::provide_loader(p_env, bootstrap_jar, jni::JObject(nullptr))}; ClassLoader::set_default_loader(class_loader); class_loader.delete_local_ref(p_env); @@ -566,3 +570,27 @@ void GDKotlin::register_members(jni::Env& p_env) { map_entry = map_entry->next(); } } + +bool GDKotlin::check_configuration() { + bool has_configuration_error = false; + if (Engine::get_singleton()->is_editor_hint() && OS::get_singleton()->get_environment("JAVA_HOME").empty()) { + LOG_WARNING("JAVA_HOME not defined. Godot-JVM module won't be loaded!") + configuration_errors.push_back( + { + "JAVA_HOME not defined", + "JAVA_HOME environment variable is not defined. This is necessary for Godot-Jvm to work while you develop on your machine.\n" + "You can continue to use the editor but all Godot-Jvm related functionality remains disabled until you define JAVA_HOME and restart the editor." + } + ); + has_configuration_error = true; + } + return !has_configuration_error; +} + +bool GDKotlin::initialized() const { + return is_initialized; +} + +const Vector>& GDKotlin::get_configuration_errors() const { + return configuration_errors; +} diff --git a/src/gd_kotlin.h b/src/gd_kotlin.h index 0f169ec3f2..dcdf478aa0 100644 --- a/src/gd_kotlin.h +++ b/src/gd_kotlin.h @@ -30,6 +30,12 @@ class GDKotlin { static void _check_and_copy_jar(const String& jar_name); static jni::JObject _prepare_class_loader(jni::Env& p_env, jni::Jvm::Type type); + bool check_configuration(); + + bool is_initialized; + + Vector> configuration_errors; + public: TransferContext* transfer_context; Vector engine_type_names; @@ -57,6 +63,10 @@ class GDKotlin { KtClass* find_class(const StringName& p_script_path); const GdKotlinConfiguration& get_configuration(); + + bool initialized() const; + + const Vector>& get_configuration_errors() const; };