mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-30 21:21:10 +00:00 
			
		
		
		
	Implementation of the Godot Android Plugin configuration file
This commit is contained in:
		
							parent
							
								
									163687d17a
								
							
						
					
					
						commit
						14e6696c8e
					
				
					 11 changed files with 534 additions and 54 deletions
				
			
		|  | @ -1162,6 +1162,7 @@ void EditorExport::save_presets() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void EditorExport::_bind_methods() { | void EditorExport::_bind_methods() { | ||||||
|  | 	ADD_SIGNAL(MethodInfo("export_presets_updated")); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void EditorExport::add_export_platform(const Ref<EditorExportPlatform> &p_platform) { | void EditorExport::add_export_platform(const Ref<EditorExportPlatform> &p_platform) { | ||||||
|  | @ -1229,8 +1230,13 @@ Vector<Ref<EditorExportPlugin>> EditorExport::get_export_plugins() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void EditorExport::_notification(int p_what) { | void EditorExport::_notification(int p_what) { | ||||||
| 	if (p_what == NOTIFICATION_ENTER_TREE) { | 	switch (p_what) { | ||||||
|  | 		case NOTIFICATION_ENTER_TREE: { | ||||||
| 			load_config(); | 			load_config(); | ||||||
|  | 		} break; | ||||||
|  | 		case NOTIFICATION_PROCESS: { | ||||||
|  | 			update_export_presets(); | ||||||
|  | 		} break; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1332,6 +1338,49 @@ void EditorExport::load_config() { | ||||||
| 	block_save = false; | 	block_save = false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void EditorExport::update_export_presets() { | ||||||
|  | 	Map<StringName, List<EditorExportPlatform::ExportOption>> platform_options; | ||||||
|  | 
 | ||||||
|  | 	for (int i = 0; i < export_platforms.size(); i++) { | ||||||
|  | 		Ref<EditorExportPlatform> platform = export_platforms[i]; | ||||||
|  | 
 | ||||||
|  | 		if (platform->should_update_export_options()) { | ||||||
|  | 			List<EditorExportPlatform::ExportOption> options; | ||||||
|  | 			platform->get_export_options(&options); | ||||||
|  | 
 | ||||||
|  | 			platform_options[platform->get_name()] = options; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool export_presets_updated = false; | ||||||
|  | 	for (int i = 0; i < export_presets.size(); i++) { | ||||||
|  | 		Ref<EditorExportPreset> preset = export_presets[i]; | ||||||
|  | 		if (platform_options.has(preset->get_platform()->get_name())) { | ||||||
|  | 			export_presets_updated = true; | ||||||
|  | 
 | ||||||
|  | 			List<EditorExportPlatform::ExportOption> options = platform_options[preset->get_platform()->get_name()]; | ||||||
|  | 
 | ||||||
|  | 			// Copy the previous preset values
 | ||||||
|  | 			Map<StringName, Variant> previous_values = preset->values; | ||||||
|  | 
 | ||||||
|  | 			// Clear the preset properties and values prior to reloading
 | ||||||
|  | 			preset->properties.clear(); | ||||||
|  | 			preset->values.clear(); | ||||||
|  | 
 | ||||||
|  | 			for (List<EditorExportPlatform::ExportOption>::Element *E = options.front(); E; E = E->next()) { | ||||||
|  | 				preset->properties.push_back(E->get().option); | ||||||
|  | 
 | ||||||
|  | 				StringName option_name = E->get().option.name; | ||||||
|  | 				preset->values[option_name] = previous_values.has(option_name) ? previous_values[option_name] : E->get().default_value; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (export_presets_updated) { | ||||||
|  | 		emit_signal(_export_presets_updated); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool EditorExport::poll_export_platforms() { | bool EditorExport::poll_export_platforms() { | ||||||
| 	bool changed = false; | 	bool changed = false; | ||||||
| 	for (int i = 0; i < export_platforms.size(); i++) { | 	for (int i = 0; i < export_platforms.size(); i++) { | ||||||
|  | @ -1351,7 +1400,10 @@ EditorExport::EditorExport() { | ||||||
| 	save_timer->connect("timeout", callable_mp(this, &EditorExport::_save)); | 	save_timer->connect("timeout", callable_mp(this, &EditorExport::_save)); | ||||||
| 	block_save = false; | 	block_save = false; | ||||||
| 
 | 
 | ||||||
|  | 	_export_presets_updated = "export_presets_updated"; | ||||||
|  | 
 | ||||||
| 	singleton = this; | 	singleton = this; | ||||||
|  | 	set_process(true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| EditorExport::~EditorExport() { | EditorExport::~EditorExport() { | ||||||
|  |  | ||||||
|  | @ -227,6 +227,7 @@ public: | ||||||
| 	virtual Ref<EditorExportPreset> create_preset(); | 	virtual Ref<EditorExportPreset> create_preset(); | ||||||
| 
 | 
 | ||||||
| 	virtual void get_export_options(List<ExportOption> *r_options) = 0; | 	virtual void get_export_options(List<ExportOption> *r_options) = 0; | ||||||
|  | 	virtual bool should_update_export_options() { return false; } | ||||||
| 	virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const { return true; } | 	virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const { return true; } | ||||||
| 
 | 
 | ||||||
| 	virtual String get_os_name() const = 0; | 	virtual String get_os_name() const = 0; | ||||||
|  | @ -350,6 +351,8 @@ class EditorExport : public Node { | ||||||
| 	Vector<Ref<EditorExportPreset>> export_presets; | 	Vector<Ref<EditorExportPreset>> export_presets; | ||||||
| 	Vector<Ref<EditorExportPlugin>> export_plugins; | 	Vector<Ref<EditorExportPlugin>> export_plugins; | ||||||
| 
 | 
 | ||||||
|  | 	StringName _export_presets_updated; | ||||||
|  | 
 | ||||||
| 	Timer *save_timer; | 	Timer *save_timer; | ||||||
| 	bool block_save; | 	bool block_save; | ||||||
| 
 | 
 | ||||||
|  | @ -381,7 +384,7 @@ public: | ||||||
| 	Vector<Ref<EditorExportPlugin>> get_export_plugins(); | 	Vector<Ref<EditorExportPlugin>> get_export_plugins(); | ||||||
| 
 | 
 | ||||||
| 	void load_config(); | 	void load_config(); | ||||||
| 
 | 	void update_export_presets(); | ||||||
| 	bool poll_export_platforms(); | 	bool poll_export_platforms(); | ||||||
| 
 | 
 | ||||||
| 	EditorExport(); | 	EditorExport(); | ||||||
|  |  | ||||||
|  | @ -133,6 +133,12 @@ void ProjectExportDialog::_add_preset(int p_platform) { | ||||||
| 	_edit_preset(EditorExport::get_singleton()->get_export_preset_count() - 1); | 	_edit_preset(EditorExport::get_singleton()->get_export_preset_count() - 1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void ProjectExportDialog::_force_update_current_preset_parameters() { | ||||||
|  | 	// Force the parameters section to refresh its UI.
 | ||||||
|  | 	parameters->edit(nullptr); | ||||||
|  | 	_update_current_preset(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void ProjectExportDialog::_update_current_preset() { | void ProjectExportDialog::_update_current_preset() { | ||||||
| 	_edit_preset(presets->get_current()); | 	_edit_preset(presets->get_current()); | ||||||
| } | } | ||||||
|  | @ -1101,6 +1107,7 @@ ProjectExportDialog::ProjectExportDialog() { | ||||||
| 	parameters->set_name(TTR("Options")); | 	parameters->set_name(TTR("Options")); | ||||||
| 	parameters->set_v_size_flags(Control::SIZE_EXPAND_FILL); | 	parameters->set_v_size_flags(Control::SIZE_EXPAND_FILL); | ||||||
| 	parameters->connect("property_edited", callable_mp(this, &ProjectExportDialog::_update_parameters)); | 	parameters->connect("property_edited", callable_mp(this, &ProjectExportDialog::_update_parameters)); | ||||||
|  | 	EditorExport::get_singleton()->connect("export_presets_updated", callable_mp(this, &ProjectExportDialog::_force_update_current_preset_parameters)); | ||||||
| 
 | 
 | ||||||
| 	// Resources export parameters.
 | 	// Resources export parameters.
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -123,6 +123,7 @@ private: | ||||||
| 	void _delete_preset_confirm(); | 	void _delete_preset_confirm(); | ||||||
| 	void _update_export_all(); | 	void _update_export_all(); | ||||||
| 
 | 
 | ||||||
|  | 	void _force_update_current_preset_parameters(); | ||||||
| 	void _update_current_preset(); | 	void _update_current_preset(); | ||||||
| 	void _update_presets(); | 	void _update_presets(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -44,6 +44,7 @@ | ||||||
| #include "editor/editor_node.h" | #include "editor/editor_node.h" | ||||||
| #include "editor/editor_settings.h" | #include "editor/editor_settings.h" | ||||||
| #include "platform/android/logo.gen.h" | #include "platform/android/logo.gen.h" | ||||||
|  | #include "platform/android/plugin/godot_plugin_config.h" | ||||||
| #include "platform/android/run_icon.gen.h" | #include "platform/android/run_icon.gen.h" | ||||||
| 
 | 
 | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  | @ -252,16 +253,45 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { | ||||||
| 		EditorProgress *ep; | 		EditorProgress *ep; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
|  | 	Vector<PluginConfig> plugins; | ||||||
|  | 	volatile bool plugins_changed; | ||||||
|  | 	Mutex plugins_lock; | ||||||
| 	Vector<Device> devices; | 	Vector<Device> devices; | ||||||
| 	volatile bool devices_changed; | 	volatile bool devices_changed; | ||||||
| 	Mutex device_lock; | 	Mutex device_lock; | ||||||
| 	Thread *device_thread; | 	Thread *check_for_changes_thread; | ||||||
| 	volatile bool quit_request; | 	volatile bool quit_request; | ||||||
| 
 | 
 | ||||||
| 	static void _device_poll_thread(void *ud) { | 	static void _check_for_changes_poll_thread(void *ud) { | ||||||
| 		EditorExportPlatformAndroid *ea = (EditorExportPlatformAndroid *)ud; | 		EditorExportPlatformAndroid *ea = (EditorExportPlatformAndroid *)ud; | ||||||
| 
 | 
 | ||||||
| 		while (!ea->quit_request) { | 		while (!ea->quit_request) { | ||||||
|  | 			// Check for plugins updates
 | ||||||
|  | 			{ | ||||||
|  | 				// Nothing to do if we already know the plugins have changed.
 | ||||||
|  | 				if (!ea->plugins_changed) { | ||||||
|  | 					Vector<PluginConfig> loaded_plugins = get_plugins(); | ||||||
|  | 
 | ||||||
|  | 					MutexLock lock(ea->plugins_lock); | ||||||
|  | 
 | ||||||
|  | 					if (ea->plugins.size() != loaded_plugins.size()) { | ||||||
|  | 						ea->plugins_changed = true; | ||||||
|  | 					} else { | ||||||
|  | 						for (int i = 0; i < ea->plugins.size(); i++) { | ||||||
|  | 							if (ea->plugins[i].name != loaded_plugins[i].name) { | ||||||
|  | 								ea->plugins_changed = true; | ||||||
|  | 								break; | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if (ea->plugins_changed) { | ||||||
|  | 						ea->plugins = loaded_plugins; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			// Check for devices updates
 | ||||||
| 			String adb = EditorSettings::get_singleton()->get("export/android/adb"); | 			String adb = EditorSettings::get_singleton()->get("export/android/adb"); | ||||||
| 			if (FileAccess::exists(adb)) { | 			if (FileAccess::exists(adb)) { | ||||||
| 				String devices; | 				String devices; | ||||||
|  | @ -573,6 +603,73 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { | ||||||
| 		return abis; | 		return abis; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/// List the gdap files in the directory specified by the p_path parameter.
 | ||||||
|  | 	static Vector<String> list_gdap_files(const String &p_path) { | ||||||
|  | 		Vector<String> dir_files; | ||||||
|  | 		DirAccessRef da = DirAccess::open(p_path); | ||||||
|  | 		if (da) { | ||||||
|  | 			da->list_dir_begin(); | ||||||
|  | 			while (true) { | ||||||
|  | 				String file = da->get_next(); | ||||||
|  | 				if (file == "") { | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (da->current_is_dir() || da->current_is_hidden()) { | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (file.ends_with(PLUGIN_CONFIG_EXT)) { | ||||||
|  | 					dir_files.push_back(file); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			da->list_dir_end(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return dir_files; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	static Vector<PluginConfig> get_plugins() { | ||||||
|  | 		Vector<PluginConfig> loaded_plugins; | ||||||
|  | 
 | ||||||
|  | 		String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/plugins"); | ||||||
|  | 
 | ||||||
|  | 		// Add the prebuilt plugins
 | ||||||
|  | 		loaded_plugins.append_array(get_prebuilt_plugins(plugins_dir)); | ||||||
|  | 
 | ||||||
|  | 		if (DirAccess::exists(plugins_dir)) { | ||||||
|  | 			Vector<String> plugins_filenames = list_gdap_files(plugins_dir); | ||||||
|  | 
 | ||||||
|  | 			if (!plugins_filenames.empty()) { | ||||||
|  | 				Ref<ConfigFile> config_file = memnew(ConfigFile); | ||||||
|  | 				for (int i = 0; i < plugins_filenames.size(); i++) { | ||||||
|  | 					PluginConfig config = load_plugin_config(config_file, plugins_dir.plus_file(plugins_filenames[i])); | ||||||
|  | 					if (config.valid_config) { | ||||||
|  | 						loaded_plugins.push_back(config); | ||||||
|  | 					} else { | ||||||
|  | 						print_error("Invalid plugin config file " + plugins_filenames[i]); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return loaded_plugins; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	static Vector<PluginConfig> get_enabled_plugins(const Ref<EditorExportPreset> &p_presets) { | ||||||
|  | 		Vector<PluginConfig> enabled_plugins; | ||||||
|  | 		Vector<PluginConfig> all_plugins = get_plugins(); | ||||||
|  | 		for (int i = 0; i < all_plugins.size(); i++) { | ||||||
|  | 			PluginConfig plugin = all_plugins[i]; | ||||||
|  | 			bool enabled = p_presets->get("plugins/" + plugin.name); | ||||||
|  | 			if (enabled) { | ||||||
|  | 				enabled_plugins.push_back(plugin); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return enabled_plugins; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	static Error store_in_apk(APKExportData *ed, const String &p_path, const Vector<uint8_t> &p_data, int compression_method = Z_DEFLATED) { | 	static Error store_in_apk(APKExportData *ed, const String &p_path, const Vector<uint8_t> &p_data, int compression_method = Z_DEFLATED) { | ||||||
| 		zip_fileinfo zipfi = get_zip_fileinfo(); | 		zip_fileinfo zipfi = get_zip_fileinfo(); | ||||||
| 		zipOpenNewFileInZip(ed->apk, | 		zipOpenNewFileInZip(ed->apk, | ||||||
|  | @ -674,7 +771,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { | ||||||
| 
 | 
 | ||||||
| 		int xr_mode_index = p_preset->get("xr_features/xr_mode"); | 		int xr_mode_index = p_preset->get("xr_features/xr_mode"); | ||||||
| 
 | 
 | ||||||
| 		String plugins = p_preset->get("custom_template/plugins"); | 		String plugins_names = get_plugins_names(get_enabled_plugins(p_preset)); | ||||||
| 
 | 
 | ||||||
| 		Vector<String> perms; | 		Vector<String> perms; | ||||||
| 
 | 
 | ||||||
|  | @ -829,9 +926,9 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { | ||||||
| 							} | 							} | ||||||
| 						} | 						} | ||||||
| 
 | 
 | ||||||
| 						if (tname == "meta-data" && attrname == "value" && value == "custom_template_plugins_value") { | 						if (tname == "meta-data" && attrname == "value" && value == "plugins_value" && !plugins_names.empty()) { | ||||||
| 							// Update the meta-data 'android:value' attribute with the list of enabled plugins.
 | 							// Update the meta-data 'android:value' attribute with the list of enabled plugins.
 | ||||||
| 							string_table.write[attr_value] = plugins; | 							string_table.write[attr_value] = plugins_names; | ||||||
| 						} | 						} | ||||||
| 
 | 
 | ||||||
| 						iofs += 20; | 						iofs += 20; | ||||||
|  | @ -1354,7 +1451,14 @@ public: | ||||||
| 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); | 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); | ||||||
| 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); | 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); | ||||||
| 		r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_template/use_custom_build"), false)); | 		r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_template/use_custom_build"), false)); | ||||||
| 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/plugins", PROPERTY_HINT_PLACEHOLDER_TEXT, "Plugin1,Plugin2,..."), "")); | 
 | ||||||
|  | 		Vector<PluginConfig> plugins_configs = get_plugins(); | ||||||
|  | 		for (int i = 0; i < plugins_configs.size(); i++) { | ||||||
|  | 			print_verbose("Found Android plugin " + plugins_configs[i].name); | ||||||
|  | 			r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + plugins_configs[i].name), false)); | ||||||
|  | 		} | ||||||
|  | 		plugins_changed = false; | ||||||
|  | 
 | ||||||
| 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), "")); | 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), "")); | ||||||
| 		r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1)); | 		r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1)); | ||||||
| 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0")); | 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0")); | ||||||
|  | @ -1409,6 +1513,15 @@ public: | ||||||
| 		return logo; | 		return logo; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	virtual bool should_update_export_options() { | ||||||
|  | 		bool export_options_changed = plugins_changed; | ||||||
|  | 		if (export_options_changed) { | ||||||
|  | 			// don't clear unless we're reporting true, to avoid race
 | ||||||
|  | 			plugins_changed = false; | ||||||
|  | 		} | ||||||
|  | 		return export_options_changed; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	virtual bool poll_export() { | 	virtual bool poll_export() { | ||||||
| 		bool dc = devices_changed; | 		bool dc = devices_changed; | ||||||
| 		if (dc) { | 		if (dc) { | ||||||
|  | @ -1755,18 +1868,22 @@ public: | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 			String build_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/build"); | 			String build_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/build"); | ||||||
| 			String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/plugins"); |  | ||||||
| 
 | 
 | ||||||
| 			build_command = build_path.plus_file(build_command); | 			build_command = build_path.plus_file(build_command); | ||||||
| 
 | 
 | ||||||
| 			String package_name = get_package_name(p_preset->get("package/unique_name")); | 			String package_name = get_package_name(p_preset->get("package/unique_name")); | ||||||
| 			String plugins = p_preset->get("custom_template/plugins"); | 
 | ||||||
|  | 			Vector<PluginConfig> enabled_plugins = get_enabled_plugins(p_preset); | ||||||
|  | 			String local_plugins_binaries = get_plugins_binaries(BINARY_TYPE_LOCAL, enabled_plugins); | ||||||
|  | 			String remote_plugins_binaries = get_plugins_binaries(BINARY_TYPE_REMOTE, enabled_plugins); | ||||||
|  | 			String custom_maven_repos = get_plugins_custom_maven_repos(enabled_plugins); | ||||||
| 
 | 
 | ||||||
| 			List<String> cmdline; | 			List<String> cmdline; | ||||||
| 			cmdline.push_back("build"); | 			cmdline.push_back("build"); | ||||||
| 			cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name.
 | 			cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name.
 | ||||||
| 			cmdline.push_back("-Pcustom_template_plugins_dir=" + plugins_dir); // argument to specify the plugins directory.
 | 			cmdline.push_back("-Pplugins_local_binaries=" + local_plugins_binaries); // argument to specify the list of plugins local dependencies.
 | ||||||
| 			cmdline.push_back("-Pcustom_template_plugins=" + plugins); // argument to specify the list of plugins to enable.
 | 			cmdline.push_back("-Pplugins_remote_binaries=" + remote_plugins_binaries); // argument to specify the list of plugins remote dependencies.
 | ||||||
|  | 			cmdline.push_back("-Pplugins_maven_repos=" + custom_maven_repos); // argument to specify the list of custom maven repos for the plugins dependencies.
 | ||||||
| 			cmdline.push_back("-p"); // argument to specify the start directory.
 | 			cmdline.push_back("-p"); // argument to specify the start directory.
 | ||||||
| 			cmdline.push_back(build_path); // start directory.
 | 			cmdline.push_back(build_path); // start directory.
 | ||||||
| 			/*{ used for debug
 | 			/*{ used for debug
 | ||||||
|  | @ -2283,14 +2400,15 @@ public: | ||||||
| 		run_icon->create_from_image(img); | 		run_icon->create_from_image(img); | ||||||
| 
 | 
 | ||||||
| 		devices_changed = true; | 		devices_changed = true; | ||||||
|  | 		plugins_changed = true; | ||||||
| 		quit_request = false; | 		quit_request = false; | ||||||
| 		device_thread = Thread::create(_device_poll_thread, this); | 		check_for_changes_thread = Thread::create(_check_for_changes_poll_thread, this); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	~EditorExportPlatformAndroid() { | 	~EditorExportPlatformAndroid() { | ||||||
| 		quit_request = true; | 		quit_request = true; | ||||||
| 		Thread::wait_to_finish(device_thread); | 		Thread::wait_to_finish(check_for_changes_thread); | ||||||
| 		memdelete(device_thread); | 		memdelete(check_for_changes_thread); | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -32,8 +32,8 @@ | ||||||
| 
 | 
 | ||||||
|         <!-- Metadata populated at export time and used by Godot to figure out which plugins must be enabled. --> |         <!-- Metadata populated at export time and used by Godot to figure out which plugins must be enabled. --> | ||||||
|         <meta-data |         <meta-data | ||||||
|             android:name="custom_template_plugins" |             android:name="plugins" | ||||||
|             android:value="custom_template_plugins_value"/> |             android:value="plugins_value"/> | ||||||
| 
 | 
 | ||||||
|         <activity |         <activity | ||||||
|             android:name=".GodotApp" |             android:name=".GodotApp" | ||||||
|  |  | ||||||
|  | @ -21,6 +21,16 @@ allprojects { | ||||||
|         mavenCentral() |         mavenCentral() | ||||||
|         google() |         google() | ||||||
|         jcenter() |         jcenter() | ||||||
|  | 
 | ||||||
|  |         // Godot user plugins custom maven repos | ||||||
|  |         String[] mavenRepos = getGodotPluginsMavenRepos() | ||||||
|  |         if (mavenRepos != null && mavenRepos.size() > 0) { | ||||||
|  |             for (String repoUrl : mavenRepos) { | ||||||
|  |                 maven { | ||||||
|  |                     url repoUrl | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -40,15 +50,18 @@ dependencies { | ||||||
|         releaseImplementation fileTree(dir: 'libs/release', include: ['*.jar', '*.aar']) |         releaseImplementation fileTree(dir: 'libs/release', include: ['*.jar', '*.aar']) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Godot prebuilt plugins |     // Godot user plugins remote dependencies | ||||||
|     implementation fileTree(dir: 'libs/plugins', include: ["GodotPayment*.aar"]) |     String[] remoteDeps = getGodotPluginsRemoteBinaries() | ||||||
|  |     if (remoteDeps != null && remoteDeps.size() > 0) { | ||||||
|  |         for (String dep : remoteDeps) { | ||||||
|  |             implementation dep | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     // Godot user plugins dependencies |     // Godot user plugins local dependencies | ||||||
|     String pluginsDir = getGodotPluginsDirectory() |     String[] pluginsBinaries = getGodotPluginsLocalBinaries() | ||||||
|     String[] pluginsBinaries = getGodotPluginsBinaries() |     if (pluginsBinaries != null && pluginsBinaries.size() > 0) { | ||||||
|     if (pluginsDir != null && !pluginsDir.isEmpty() && |         implementation files(pluginsBinaries) | ||||||
|         pluginsBinaries != null && pluginsBinaries.size() > 0) { |  | ||||||
|         implementation fileTree(dir: pluginsDir, include: pluginsBinaries) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -28,39 +28,68 @@ ext.getExportPackageName = { -> | ||||||
|     return appId |     return appId | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | final String PLUGIN_VALUE_SEPARATOR_REGEX = "\\|" | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * Parse the project properties for the 'custom_template_plugins' property and return |  * Parse the project properties for the 'plugins_maven_repos' property and return the list | ||||||
|  |  * of maven repos. | ||||||
|  |  */ | ||||||
|  | ext.getGodotPluginsMavenRepos = { -> | ||||||
|  |     Set<String> mavenRepos = [] | ||||||
|  | 
 | ||||||
|  |     // Retrieve the list of maven repos. | ||||||
|  |     if (project.hasProperty("plugins_maven_repos")) { | ||||||
|  |         String mavenReposProperty = project.property("plugins_maven_repos") | ||||||
|  |         if (mavenReposProperty != null && !mavenReposProperty.trim().isEmpty()) { | ||||||
|  |             for (String mavenRepoUrl : mavenReposProperty.split(PLUGIN_VALUE_SEPARATOR_REGEX)) { | ||||||
|  |                 mavenRepos += mavenRepoUrl.trim() | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return mavenRepos | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Parse the project properties for the 'plugins_remote_binaries' property and return | ||||||
|  |  * it for inclusion in the build dependencies. | ||||||
|  |  */ | ||||||
|  | ext.getGodotPluginsRemoteBinaries = { -> | ||||||
|  |     Set<String> remoteDeps = [] | ||||||
|  | 
 | ||||||
|  |     // Retrieve the list of remote plugins binaries. | ||||||
|  |     if (project.hasProperty("plugins_remote_binaries")) { | ||||||
|  |         String remoteDepsList = project.property("plugins_remote_binaries") | ||||||
|  |         if (remoteDepsList != null && !remoteDepsList.trim().isEmpty()) { | ||||||
|  |             for (String dep: remoteDepsList.split(PLUGIN_VALUE_SEPARATOR_REGEX)) { | ||||||
|  |                 remoteDeps += dep.trim() | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return remoteDeps | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Parse the project properties for the 'plugins_local_binaries' property and return | ||||||
|  * their binaries for inclusion in the build dependencies. |  * their binaries for inclusion in the build dependencies. | ||||||
|  * |  * | ||||||
|  * The listed plugins must have their binaries in the project plugins directory. |  * Returns the prebuilt plugins if the 'plugins_local_binaries' property is unavailable. | ||||||
|  */ |  */ | ||||||
| ext.getGodotPluginsBinaries = { -> | ext.getGodotPluginsLocalBinaries = { -> | ||||||
|     String[] binDeps = [] |     // Set the prebuilt plugins as default. If custom build is enabled, | ||||||
|  |     // the 'plugins_local_binaries' will be defined so we can use it instead. | ||||||
|  |     Set<String> binDeps = ["libs/plugins/GodotPayment.release.aar"] | ||||||
| 
 | 
 | ||||||
|     // Retrieve the list of enabled plugins. |     // Retrieve the list of local plugins binaries. | ||||||
|     if (project.hasProperty("custom_template_plugins")) { |     if (project.hasProperty("plugins_local_binaries")) { | ||||||
|         String pluginsList = project.property("custom_template_plugins") |         binDeps.clear() | ||||||
|  |         String pluginsList = project.property("plugins_local_binaries") | ||||||
|         if (pluginsList != null && !pluginsList.trim().isEmpty()) { |         if (pluginsList != null && !pluginsList.trim().isEmpty()) { | ||||||
|             for (String plugin : pluginsList.split(",")) { |             for (String plugin : pluginsList.split(PLUGIN_VALUE_SEPARATOR_REGEX)) { | ||||||
|                 binDeps += plugin.trim() + "*.aar" |                 binDeps += plugin.trim() | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return binDeps |     return binDeps | ||||||
| } | } | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Parse the project properties for the 'custom_template_plugins_dir' property and return |  | ||||||
|  * its value. |  | ||||||
|  * |  | ||||||
|  * The returned value is the directory containing user plugins. |  | ||||||
|  */ |  | ||||||
| ext.getGodotPluginsDirectory = { -> |  | ||||||
|     // The plugins directory is provided by the 'custom_template_plugins_dir' property. |  | ||||||
|     String pluginsDir = project.hasProperty("custom_template_plugins_dir") |  | ||||||
|         ? project.property("custom_template_plugins_dir") |  | ||||||
|         : "" |  | ||||||
| 
 |  | ||||||
|     return pluginsDir |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -140,7 +140,7 @@ task generateGodotTemplates(type: GradleBuild) { | ||||||
|         startParameter.excludedTaskNames += ":lib:" + getSconsTaskName(buildType) |         startParameter.excludedTaskNames += ":lib:" + getSconsTaskName(buildType) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     tasks = ["copyGodotPaymentPluginToAppModule"] |     tasks = [] | ||||||
| 
 | 
 | ||||||
|     // Only build the apks and aar files for which we have native shared libraries. |     // Only build the apks and aar files for which we have native shared libraries. | ||||||
|     for (String target : supportedTargets) { |     for (String target : supportedTargets) { | ||||||
|  | @ -161,6 +161,7 @@ task generateGodotTemplates(type: GradleBuild) { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     dependsOn 'copyGodotPaymentPluginToAppModule' | ||||||
|     finalizedBy 'zipCustomBuild' |     finalizedBy 'zipCustomBuild' | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -58,7 +58,9 @@ public final class GodotPluginRegistry { | ||||||
| 	/** | 	/** | ||||||
| 	 * Name for the metadata containing the list of Godot plugins to enable. | 	 * Name for the metadata containing the list of Godot plugins to enable. | ||||||
| 	 */ | 	 */ | ||||||
| 	private static final String GODOT_ENABLED_PLUGINS_LABEL = "custom_template_plugins"; | 	private static final String GODOT_ENABLED_PLUGINS_LABEL = "plugins"; | ||||||
|  | 
 | ||||||
|  | 	private static final String PLUGIN_VALUE_SEPARATOR_REGEX = "\\|"; | ||||||
| 
 | 
 | ||||||
| 	private static GodotPluginRegistry instance; | 	private static GodotPluginRegistry instance; | ||||||
| 	private final ConcurrentHashMap<String, GodotPlugin> registry; | 	private final ConcurrentHashMap<String, GodotPlugin> registry; | ||||||
|  | @ -128,13 +130,13 @@ public final class GodotPluginRegistry { | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			// When using the Godot editor for building and exporting the apk, this is used to check | 			// When using the Godot editor for building and exporting the apk, this is used to check | ||||||
| 			// which plugins to enable since the custom build template may contain prebuilt plugins. | 			// which plugins to enable. | ||||||
| 			// When using a custom process to generate the apk, the metadata is not needed since | 			// When using a custom process to generate the apk, the metadata is not needed since | ||||||
| 			// it's assumed that the developer is aware of the dependencies included in the apk. | 			// it's assumed that the developer is aware of the dependencies included in the apk. | ||||||
| 			final Set<String> enabledPluginsSet; | 			final Set<String> enabledPluginsSet; | ||||||
| 			if (metaData.containsKey(GODOT_ENABLED_PLUGINS_LABEL)) { | 			if (metaData.containsKey(GODOT_ENABLED_PLUGINS_LABEL)) { | ||||||
| 				String enabledPlugins = metaData.getString(GODOT_ENABLED_PLUGINS_LABEL, ""); | 				String enabledPlugins = metaData.getString(GODOT_ENABLED_PLUGINS_LABEL, ""); | ||||||
| 				String[] enabledPluginsList = enabledPlugins.split(","); | 				String[] enabledPluginsList = enabledPlugins.split(PLUGIN_VALUE_SEPARATOR_REGEX); | ||||||
| 				if (enabledPluginsList.length == 0) { | 				if (enabledPluginsList.length == 0) { | ||||||
| 					// No plugins to enable. Aborting early. | 					// No plugins to enable. Aborting early. | ||||||
| 					return; | 					return; | ||||||
|  | @ -158,6 +160,8 @@ public final class GodotPluginRegistry { | ||||||
| 						continue; | 						continue; | ||||||
| 					} | 					} | ||||||
| 
 | 
 | ||||||
|  | 					Log.i(TAG, "Initializing Godot plugin " + pluginName); | ||||||
|  | 
 | ||||||
| 					// Retrieve the plugin class full name. | 					// Retrieve the plugin class full name. | ||||||
| 					String pluginHandleClassFullName = metaData.getString(metaDataName); | 					String pluginHandleClassFullName = metaData.getString(metaDataName); | ||||||
| 					if (!TextUtils.isEmpty(pluginHandleClassFullName)) { | 					if (!TextUtils.isEmpty(pluginHandleClassFullName)) { | ||||||
|  | @ -177,6 +181,7 @@ public final class GodotPluginRegistry { | ||||||
| 										"Meta-data plugin name does not match the value returned by the plugin handle: " + pluginName + " =/= " + pluginHandle.getPluginName()); | 										"Meta-data plugin name does not match the value returned by the plugin handle: " + pluginName + " =/= " + pluginHandle.getPluginName()); | ||||||
| 							} | 							} | ||||||
| 							registry.put(pluginName, pluginHandle); | 							registry.put(pluginName, pluginHandle); | ||||||
|  | 							Log.i(TAG, "Completed initialization for Godot plugin " + pluginHandle.getPluginName()); | ||||||
| 						} catch (ClassNotFoundException e) { | 						} catch (ClassNotFoundException e) { | ||||||
| 							Log.w(TAG, "Unable to load Godot plugin " + pluginName, e); | 							Log.w(TAG, "Unable to load Godot plugin " + pluginName, e); | ||||||
| 						} catch (IllegalAccessException e) { | 						} catch (IllegalAccessException e) { | ||||||
|  |  | ||||||
							
								
								
									
										251
									
								
								platform/android/plugin/godot_plugin_config.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								platform/android/plugin/godot_plugin_config.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,251 @@ | ||||||
|  | /*************************************************************************/ | ||||||
|  | /*  godot_plugin_config.h                                                */ | ||||||
|  | /*************************************************************************/ | ||||||
|  | /*                       This file is part of:                           */ | ||||||
|  | /*                           GODOT ENGINE                                */ | ||||||
|  | /*                      https://godotengine.org                          */ | ||||||
|  | /*************************************************************************/ | ||||||
|  | /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */ | ||||||
|  | /* Copyright (c) 2014-2020 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 GODOT_PLUGIN_CONFIG_H | ||||||
|  | #define GODOT_PLUGIN_CONFIG_H | ||||||
|  | 
 | ||||||
|  | #include "core/error_list.h" | ||||||
|  | #include "core/io/config_file.h" | ||||||
|  | #include "core/ustring.h" | ||||||
|  | 
 | ||||||
|  | static const char *PLUGIN_CONFIG_EXT = ".gdap"; | ||||||
|  | 
 | ||||||
|  | static const char *CONFIG_SECTION = "config"; | ||||||
|  | static const char *CONFIG_NAME_KEY = "name"; | ||||||
|  | static const char *CONFIG_BINARY_TYPE_KEY = "binary_type"; | ||||||
|  | static const char *CONFIG_BINARY_KEY = "binary"; | ||||||
|  | 
 | ||||||
|  | static const char *DEPENDENCIES_SECTION = "dependencies"; | ||||||
|  | static const char *DEPENDENCIES_LOCAL_KEY = "local"; | ||||||
|  | static const char *DEPENDENCIES_REMOTE_KEY = "remote"; | ||||||
|  | static const char *DEPENDENCIES_CUSTOM_MAVEN_REPOS_KEY = "custom_maven_repos"; | ||||||
|  | 
 | ||||||
|  | static const char *BINARY_TYPE_LOCAL = "local"; | ||||||
|  | static const char *BINARY_TYPE_REMOTE = "remote"; | ||||||
|  | 
 | ||||||
|  | static const char *PLUGIN_VALUE_SEPARATOR = "|"; | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  The `config` section and fields are required and defined as follow: | ||||||
|  | - **name**: name of the plugin | ||||||
|  | - **binary_type**: can be either `local` or `remote`.  The type affects the **binary** field | ||||||
|  | - **binary**: | ||||||
|  |   - if **binary_type** is `local`, then this should be the filename of the plugin `aar` file in the `res://android/plugins` directory (e.g: `MyPlugin.aar`).
 | ||||||
|  |   - if **binary_type** is `remote`, then this should be a declaration for a remote gradle binary (e.g: "org.godot.example:my-plugin:0.0.0"). | ||||||
|  | 
 | ||||||
|  | The `dependencies` section and fields are optional and defined as follow: | ||||||
|  | - **local**: contains a list of local `.aar` binary files the plugin depends on. The local binary dependencies must also be located in the `res://android/plugins` directory.
 | ||||||
|  | - **remote**: contains a list of remote binary gradle dependencies for the plugin. | ||||||
|  | - **custom_maven_repos**: contains a list of urls specifying custom maven repos required for the plugin's dependencies. | ||||||
|  | 
 | ||||||
|  |  See https://github.com/godotengine/godot/issues/38157#issuecomment-618773871
 | ||||||
|  |  */ | ||||||
|  | struct PluginConfig { | ||||||
|  | 	// Set to true when the config file is properly loaded.
 | ||||||
|  | 	bool valid_config = false; | ||||||
|  | 
 | ||||||
|  | 	// Required config section
 | ||||||
|  | 	String name; | ||||||
|  | 	String binary_type; | ||||||
|  | 	String binary; | ||||||
|  | 
 | ||||||
|  | 	// Optional dependencies section
 | ||||||
|  | 	Vector<String> local_dependencies; | ||||||
|  | 	Vector<String> remote_dependencies; | ||||||
|  | 	Vector<String> custom_maven_repos; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Set of prebuilt plugins. | ||||||
|  |  */ | ||||||
|  | static const PluginConfig GODOT_PAYMENT = { | ||||||
|  | 	/*.valid_config =*/true, | ||||||
|  | 	/*.name =*/"GodotPayment", | ||||||
|  | 	/*.binary_type =*/"local", | ||||||
|  | 	/*.binary =*/"res://android/build/libs/plugins/GodotPayment.release.aar", | ||||||
|  | 	/*.local_dependencies =*/{}, | ||||||
|  | 	/*.remote_dependencies =*/{}, | ||||||
|  | 	/*.custom_maven_repos =*/{} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static inline String resolve_local_dependency_path(String plugin_config_dir, String dependency_path) { | ||||||
|  | 	String absolute_path; | ||||||
|  | 	if (!dependency_path.empty()) { | ||||||
|  | 		if (dependency_path.is_abs_path()) { | ||||||
|  | 			absolute_path = ProjectSettings::get_singleton()->globalize_path(dependency_path); | ||||||
|  | 		} else { | ||||||
|  | 			absolute_path = plugin_config_dir.plus_file(dependency_path); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return absolute_path; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline PluginConfig resolve_prebuilt_plugin(PluginConfig prebuilt_plugin, String plugin_config_dir) { | ||||||
|  | 	PluginConfig resolved = prebuilt_plugin; | ||||||
|  | 	resolved.binary = resolved.binary_type == BINARY_TYPE_LOCAL ? resolve_local_dependency_path(plugin_config_dir, prebuilt_plugin.binary) : prebuilt_plugin.binary; | ||||||
|  | 	if (!prebuilt_plugin.local_dependencies.empty()) { | ||||||
|  | 		resolved.local_dependencies.clear(); | ||||||
|  | 		for (int i = 0; i < prebuilt_plugin.local_dependencies.size(); i++) { | ||||||
|  | 			resolved.local_dependencies.push_back(resolve_local_dependency_path(plugin_config_dir, prebuilt_plugin.local_dependencies[i])); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return resolved; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline Vector<PluginConfig> get_prebuilt_plugins(String plugins_base_dir) { | ||||||
|  | 	Vector<PluginConfig> prebuilt_plugins; | ||||||
|  | 	prebuilt_plugins.push_back(resolve_prebuilt_plugin(GODOT_PAYMENT, plugins_base_dir)); | ||||||
|  | 	return prebuilt_plugins; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline bool is_plugin_config_valid(PluginConfig plugin_config) { | ||||||
|  | 	bool valid_name = !plugin_config.name.empty(); | ||||||
|  | 	bool valid_binary_type = plugin_config.binary_type == BINARY_TYPE_LOCAL || | ||||||
|  | 							 plugin_config.binary_type == BINARY_TYPE_REMOTE; | ||||||
|  | 
 | ||||||
|  | 	bool valid_binary = false; | ||||||
|  | 	if (valid_binary_type) { | ||||||
|  | 		valid_binary = !plugin_config.binary.empty() && | ||||||
|  | 					   (plugin_config.binary_type == BINARY_TYPE_REMOTE || | ||||||
|  | 							   FileAccess::exists(plugin_config.binary)); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool valid_local_dependencies = true; | ||||||
|  | 	if (!plugin_config.local_dependencies.empty()) { | ||||||
|  | 		for (int i = 0; i < plugin_config.local_dependencies.size(); i++) { | ||||||
|  | 			if (!FileAccess::exists(plugin_config.local_dependencies[i])) { | ||||||
|  | 				valid_local_dependencies = false; | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return valid_name && valid_binary && valid_binary_type && valid_local_dependencies; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline PluginConfig load_plugin_config(Ref<ConfigFile> config_file, const String &path) { | ||||||
|  | 	PluginConfig plugin_config = {}; | ||||||
|  | 
 | ||||||
|  | 	if (config_file.is_valid()) { | ||||||
|  | 		Error err = config_file->load(path); | ||||||
|  | 		if (err == OK) { | ||||||
|  | 			String config_base_dir = path.get_base_dir(); | ||||||
|  | 
 | ||||||
|  | 			plugin_config.name = config_file->get_value(CONFIG_SECTION, CONFIG_NAME_KEY, String()); | ||||||
|  | 			plugin_config.binary_type = config_file->get_value(CONFIG_SECTION, CONFIG_BINARY_TYPE_KEY, String()); | ||||||
|  | 
 | ||||||
|  | 			String binary_path = config_file->get_value(CONFIG_SECTION, CONFIG_BINARY_KEY, String()); | ||||||
|  | 			plugin_config.binary = plugin_config.binary_type == BINARY_TYPE_LOCAL ? resolve_local_dependency_path(config_base_dir, binary_path) : binary_path; | ||||||
|  | 
 | ||||||
|  | 			if (config_file->has_section(DEPENDENCIES_SECTION)) { | ||||||
|  | 				Vector<String> local_dependencies_paths = config_file->get_value(DEPENDENCIES_SECTION, DEPENDENCIES_LOCAL_KEY, Vector<String>()); | ||||||
|  | 				if (!local_dependencies_paths.empty()) { | ||||||
|  | 					for (int i = 0; i < local_dependencies_paths.size(); i++) { | ||||||
|  | 						plugin_config.local_dependencies.push_back(resolve_local_dependency_path(config_base_dir, local_dependencies_paths[i])); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				plugin_config.remote_dependencies = config_file->get_value(DEPENDENCIES_SECTION, DEPENDENCIES_REMOTE_KEY, Vector<String>()); | ||||||
|  | 				plugin_config.custom_maven_repos = config_file->get_value(DEPENDENCIES_SECTION, DEPENDENCIES_CUSTOM_MAVEN_REPOS_KEY, Vector<String>()); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			plugin_config.valid_config = is_plugin_config_valid(plugin_config); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return plugin_config; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline String get_plugins_binaries(String binary_type, Vector<PluginConfig> plugins_configs) { | ||||||
|  | 	String plugins_binaries; | ||||||
|  | 	if (!plugins_configs.empty()) { | ||||||
|  | 		Vector<String> binaries; | ||||||
|  | 		for (int i = 0; i < plugins_configs.size(); i++) { | ||||||
|  | 			PluginConfig config = plugins_configs[i]; | ||||||
|  | 			if (!config.valid_config) { | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (config.binary_type == binary_type) { | ||||||
|  | 				binaries.push_back(config.binary); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (binary_type == BINARY_TYPE_LOCAL) { | ||||||
|  | 				binaries.append_array(config.local_dependencies); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (binary_type == BINARY_TYPE_REMOTE) { | ||||||
|  | 				binaries.append_array(config.remote_dependencies); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		plugins_binaries = String(PLUGIN_VALUE_SEPARATOR).join(binaries); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return plugins_binaries; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline String get_plugins_custom_maven_repos(Vector<PluginConfig> plugins_configs) { | ||||||
|  | 	String custom_maven_repos; | ||||||
|  | 	if (!plugins_configs.empty()) { | ||||||
|  | 		Vector<String> repos_urls; | ||||||
|  | 		for (int i = 0; i < plugins_configs.size(); i++) { | ||||||
|  | 			PluginConfig config = plugins_configs[i]; | ||||||
|  | 			if (!config.valid_config) { | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			repos_urls.append_array(config.custom_maven_repos); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		custom_maven_repos = String(PLUGIN_VALUE_SEPARATOR).join(repos_urls); | ||||||
|  | 	} | ||||||
|  | 	return custom_maven_repos; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline String get_plugins_names(Vector<PluginConfig> plugins_configs) { | ||||||
|  | 	String plugins_names; | ||||||
|  | 	if (!plugins_configs.empty()) { | ||||||
|  | 		Vector<String> names; | ||||||
|  | 		for (int i = 0; i < plugins_configs.size(); i++) { | ||||||
|  | 			PluginConfig config = plugins_configs[i]; | ||||||
|  | 			if (!config.valid_config) { | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			names.push_back(config.name); | ||||||
|  | 		} | ||||||
|  | 		plugins_names = String(PLUGIN_VALUE_SEPARATOR).join(names); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return plugins_names; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif // GODOT_PLUGIN_CONFIG_H
 | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Fredia Huya-Kouadio
						Fredia Huya-Kouadio