diff options
77 files changed, 960 insertions, 414 deletions
diff --git a/SConstruct b/SConstruct index 3ff6bb739a..88bb43fbc7 100644 --- a/SConstruct +++ b/SConstruct @@ -562,7 +562,7 @@ if 'env' in locals(): # (filename, size, weight). current_time = time.time() file_stat = [(x[0], x[1][0], (current_time - x[1][1])) for x in file_stat] - # Sort by the most resently accessed files (most sensible to keep) first + # Sort by the most recently accessed files (most sensible to keep) first file_stat.sort(key=lambda x: x[2]) # Search for the first entry where the storage limit is # reached diff --git a/core/error_macros.h b/core/error_macros.h index 78e29551d4..f72e987e23 100644 --- a/core/error_macros.h +++ b/core/error_macros.h @@ -41,7 +41,7 @@ */ /** - * Pointer to the error macro priting function. Reassign to any function to have errors printed + * Pointer to the error macro printing function. Reassign to any function to have errors printed */ /** Function used by the error macros */ diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index e5c6d2a4f2..ce2054db36 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -429,7 +429,7 @@ Error HTTPClient::poll() { response_num = RESPONSE_OK; // Per the HTTP 1.1 spec, keep-alive is the default. - // Not following that specification breaks standard implemetations. + // Not following that specification breaks standard implementations. // Broken web servers should be fixed. bool keep_alive = true; diff --git a/core/io/zip_io.h b/core/io/zip_io.h index fb63878a4c..4eb1c8b46c 100644 --- a/core/io/zip_io.h +++ b/core/io/zip_io.h @@ -33,7 +33,7 @@ #include "core/os/file_access.h" -// Not direclty used in this header, but assumed available in downstream users +// Not directly used in this header, but assumed available in downstream users // like platform/*/export/export.cpp. Could be fixed, but probably better to have // thirdparty includes in as little headers as possible. #include "thirdparty/minizip/unzip.h" diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index e1388ad2ac..3d71e66f80 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -54,7 +54,8 @@ void AStar::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) { pt->pos = p_pos; pt->weight_scale = p_weight_scale; pt->prev_point = NULL; - pt->last_pass = 0; + pt->open_pass = 0; + pt->closed_pass = 0; pt->enabled = true; points[p_id] = pt; } else { @@ -246,86 +247,62 @@ bool AStar::_solve(Point *begin_point, Point *end_point) { if (!end_point->enabled) return false; - SelfList<Point>::List open_list; - bool found_route = false; - for (Set<Point *>::Element *E = begin_point->neighbours.front(); E; E = E->next()) { - - Point *n = E->get(); + Vector<Point *> open_list; + SortArray<Point *, SortPoints> sorter; - if (!n->enabled) - continue; + begin_point->g_score = 0; + begin_point->f_score = _estimate_cost(begin_point->id, end_point->id); - n->prev_point = begin_point; - n->distance = _compute_cost(begin_point->id, n->id) * n->weight_scale; - n->last_pass = pass; - open_list.add(&n->list); - } + open_list.push_back(begin_point); while (true) { - if (open_list.first() == NULL) { - // No path found + if (open_list.size() == 0) // No path found break; - } - // Check open list - - SelfList<Point> *least_cost_point = open_list.first(); - real_t least_cost = Math_INF; - // TODO: Cache previous results - for (SelfList<Point> *E = open_list.first(); E; E = E->next()) { - - Point *p = E->self(); - - real_t cost = p->distance; - cost += _estimate_cost(p->id, end_point->id); - - if (cost < least_cost) { - least_cost_point = E; - least_cost = cost; - } - } + Point *p = open_list[0]; // The currently processed point - Point *p = least_cost_point->self(); if (p == end_point) { found_route = true; break; } + sorter.pop_heap(0, open_list.size(), open_list.ptrw()); // Remove the current point from the open list + open_list.remove(open_list.size() - 1); + p->closed_pass = pass; // Mark the point as closed + for (Set<Point *>::Element *E = p->neighbours.front(); E; E = E->next()) { - Point *e = E->get(); + Point *e = E->get(); // The neighbour point - if (!e->enabled) + if (!e->enabled || e->closed_pass == pass) continue; - real_t distance = _compute_cost(p->id, e->id) * e->weight_scale + p->distance; + real_t tentative_g_score = p->g_score + _compute_cost(p->id, e->id) * e->weight_scale; + + bool new_point = false; - if (e->last_pass == pass) { - // Already visited, is this cheaper? + if (e->open_pass != pass) { // The point wasn't inside the open list - if (e->distance > distance) { - e->prev_point = p; - e->distance = distance; - } - } else { - // Add to open neighbours + e->open_pass = pass; + open_list.push_back(e); + new_point = true; + } else if (tentative_g_score >= e->g_score) { // The new path is worse than the previous - e->prev_point = p; - e->distance = distance; - e->last_pass = pass; // Mark as used - open_list.add(&e->list); + continue; } - } - open_list.remove(least_cost_point); - } + e->prev_point = p; + e->g_score = tentative_g_score; + e->f_score = e->g_score + _estimate_cost(e->id, end_point->id); - // Clear the openf list - while (open_list.first()) { - open_list.remove(open_list.first()); + if (new_point) // The position of the new points is already known + sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptrw()); + else + sorter.push_heap(0, open_list.find(e), 0, e, open_list.ptrw()); + } } return found_route; @@ -352,8 +329,6 @@ PoolVector<Vector3> AStar::get_point_path(int p_from_id, int p_to_id) { ERR_FAIL_COND_V(!points.has(p_from_id), PoolVector<Vector3>()); ERR_FAIL_COND_V(!points.has(p_to_id), PoolVector<Vector3>()); - pass++; - Point *a = points[p_from_id]; Point *b = points[p_to_id]; @@ -403,8 +378,6 @@ PoolVector<int> AStar::get_id_path(int p_from_id, int p_to_id) { ERR_FAIL_COND_V(!points.has(p_from_id), PoolVector<int>()); ERR_FAIL_COND_V(!points.has(p_to_id), PoolVector<int>()); - pass++; - Point *a = points[p_from_id]; Point *b = points[p_to_id]; diff --git a/core/math/a_star.h b/core/math/a_star.h index c63e1aa4dc..fac8a9d312 100644 --- a/core/math/a_star.h +++ b/core/math/a_star.h @@ -48,26 +48,34 @@ class AStar : public Reference { struct Point { - SelfList<Point> list; - int id; Vector3 pos; real_t weight_scale; - uint64_t last_pass; bool enabled; Set<Point *> neighbours; // Used for pathfinding Point *prev_point; - real_t distance; - - Point() : - list(this) {} + real_t g_score; + real_t f_score; + uint64_t open_pass; + uint64_t closed_pass; }; Map<int, Point *> points; + struct SortPoints { + _FORCE_INLINE_ bool operator()(const Point *A, const Point *B) const { // Returns true when the Point A is worse than Point B + if (A->f_score > B->f_score) + return true; + else if (A->f_score < B->f_score) + return false; + else + return A->g_score < B->g_score; // If the f_costs are the same then prioritize the points that are further away from the start + } + }; + struct Segment { union { struct { diff --git a/core/math/geometry.h b/core/math/geometry.h index f3a671aa9a..0b2adf9513 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -833,7 +833,7 @@ public: further_away_opposite.y = MIN(p[i].y, further_away_opposite.y); } - further_away += (further_away - further_away_opposite) * Vector2(1.221313, 1.512312); // make point outside that wont intersect with points in segment from p_point + further_away += (further_away - further_away_opposite) * Vector2(1.221313, 1.512312); // make point outside that won't intersect with points in segment from p_point int intersections = 0; for (int i = 0; i < c; i++) { diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp index 69581e4115..f7ca6d3bde 100644 --- a/core/undo_redo.cpp +++ b/core/undo_redo.cpp @@ -239,8 +239,8 @@ void UndoRedo::_pop_history_tail() { } } -bool UndoRedo::is_commiting_action() const { - return commiting > 0; +bool UndoRedo::is_committing_action() const { + return committing > 0; } void UndoRedo::commit_action() { @@ -255,9 +255,9 @@ void UndoRedo::commit_action() { merging = false; } - commiting++; + committing++; redo(); // perform action - commiting--; + committing--; if (callback && actions.size() > 0) { callback(callback_ud, actions[actions.size() - 1].name); } @@ -396,7 +396,7 @@ void UndoRedo::set_property_notify_callback(PropertyNotifyCallback p_property_ca UndoRedo::UndoRedo() { - commiting = 0; + committing = 0; version = 1; action_level = 0; current_action = -1; @@ -496,10 +496,8 @@ void UndoRedo::_bind_methods() { ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE)); ClassDB::bind_method(D_METHOD("commit_action"), &UndoRedo::commit_action); - ClassDB::bind_method(D_METHOD("is_commiting_action"), &UndoRedo::is_commiting_action); - - //ClassDB::bind_method(D_METHOD("add_do_method","p_object", "p_method", "VARIANT_ARG_LIST"),&UndoRedo::add_do_method); - //ClassDB::bind_method(D_METHOD("add_undo_method","p_object", "p_method", "VARIANT_ARG_LIST"),&UndoRedo::add_undo_method); + // FIXME: Typo in "commiting", fix in 4.0 when breaking compat. + ClassDB::bind_method(D_METHOD("is_commiting_action"), &UndoRedo::is_committing_action); { MethodInfo mi; diff --git a/core/undo_redo.h b/core/undo_redo.h index 6293e77acc..e2cc6c659b 100644 --- a/core/undo_redo.h +++ b/core/undo_redo.h @@ -95,7 +95,7 @@ private: MethodNotifyCallback method_callback; PropertyNotifyCallback property_callback; - int commiting; + int committing; protected: static void _bind_methods(); @@ -110,7 +110,7 @@ public: void add_do_reference(Object *p_object); void add_undo_reference(Object *p_object); - bool is_commiting_action() const; + bool is_committing_action() const; void commit_action(); bool redo(); diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml index e61fe374fa..c1307be924 100644 --- a/doc/classes/AnimationNode.xml +++ b/doc/classes/AnimationNode.xml @@ -153,7 +153,7 @@ <argument index="0" name="path" type="NodePath"> </argument> <description> - Return [code]true[/code] wether a given path is filtered. + Return [code]true[/code] whether a given path is filtered. </description> </method> <method name="process" qualifiers="virtual"> diff --git a/doc/classes/AnimationNodeStateMachine.xml b/doc/classes/AnimationNodeStateMachine.xml index e46a40c4de..8f4e6dff69 100644 --- a/doc/classes/AnimationNodeStateMachine.xml +++ b/doc/classes/AnimationNodeStateMachine.xml @@ -3,7 +3,7 @@ <brief_description> </brief_description> <description> - Contains multiple root nodes as children in a graph. Each node is used as a state, and provides multiple functions to alternate between states. Retrieve the AnimationNodeStateMachinePlayback object from the [AnimationTree] node to control it programatically. + Contains multiple root nodes as children in a graph. Each node is used as a state, and provides multiple functions to alternate between states. Retrieve the AnimationNodeStateMachinePlayback object from the [AnimationTree] node to control it programmatically. [codeblock] var state_machine = anim_tree["parameters/StateMachine/playback"] state_machine.travel("SomeState") diff --git a/doc/classes/EditorInspectorPlugin.xml b/doc/classes/EditorInspectorPlugin.xml index f2dcd2177c..da23218bdc 100644 --- a/doc/classes/EditorInspectorPlugin.xml +++ b/doc/classes/EditorInspectorPlugin.xml @@ -21,7 +21,7 @@ <argument index="0" name="control" type="Control"> </argument> <description> - Add a custom control, not necesarily a property editor. + Add a custom control, not necessarily a property editor. </description> </method> <method name="add_property_editor"> diff --git a/doc/classes/PrismMesh.xml b/doc/classes/PrismMesh.xml index 0d0f330647..4c282c5e8d 100644 --- a/doc/classes/PrismMesh.xml +++ b/doc/classes/PrismMesh.xml @@ -12,7 +12,7 @@ </methods> <members> <member name="left_to_right" type="float" setter="set_left_to_right" getter="get_left_to_right"> - Displacement of the upper edge along the x-axis. 0.0 positions edge straight above the bottome left edge. Defaults to 0.5 (positioned on the midpoint). + Displacement of the upper edge along the x-axis. 0.0 positions edge straight above the bottom left edge. Defaults to 0.5 (positioned on the midpoint). </member> <member name="size" type="Vector3" setter="set_size" getter="get_size"> Size of the prism. Defaults to (2.0, 2.0, 2.0). diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml index c0b73cd8e3..ce6405b96c 100644 --- a/doc/classes/UndoRedo.xml +++ b/doc/classes/UndoRedo.xml @@ -141,7 +141,7 @@ This is useful mostly to check if something changed from a saved version. </description> </method> - <method name="is_commiting_action" qualifiers="const"> + <method name="is_committing_action" qualifiers="const"> <return type="bool"> </return> <description> diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 3b3fbf9ed5..2d9eec10d2 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -580,7 +580,7 @@ bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance //the approach below is fatal for powervr - // Set the initial (empty) mipmaps, all need to be set for this to work in GLES2, even if later wont be used. + // Set the initial (empty) mipmaps, all need to be set for this to work in GLES2, even if they won't be used later. while (size >= 1) { for (int i = 0; i < 6; i++) { diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl index 7ba2856216..7dce784f52 100644 --- a/drivers/gles2/shaders/canvas.glsl +++ b/drivers/gles2/shaders/canvas.glsl @@ -347,7 +347,7 @@ void main() { vec4 color = color_interp; vec2 uv = uv_interp; #ifdef USE_FORCE_REPEAT - //needs to use this to workaround GLES2/WebGL1 forcing tiling that textures that dont support it + //needs to use this to workaround GLES2/WebGL1 forcing tiling that textures that don't support it uv = mod(uv, vec2(1.0, 1.0)); #endif diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 61244ab78c..b2af11fab0 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -3520,7 +3520,7 @@ void AnimationTrackEditor::_update_tracks() { void AnimationTrackEditor::_animation_changed() { if (animation_changing_awaiting_update) { - return; //all will be updated, dont bother with anything + return; //all will be updated, don't bother with anything } if (key_edit && key_edit->setting) { diff --git a/editor/doc/doc_dump.cpp b/editor/doc/doc_dump.cpp index 6ccf0e26ea..866d57e054 100644 --- a/editor/doc/doc_dump.cpp +++ b/editor/doc/doc_dump.cpp @@ -111,7 +111,7 @@ void DocDump::dump(const String &p_file) { for (List<MethodInfo>::Element *E = method_list.front(); E; E = E->next()) { if (E->get().name == "" || E->get().name[0] == '_') - continue; //hiden + continue; //hidden MethodBind *m = ClassDB::get_method(name, E->get().name); diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index 2beb0153f4..9cd7d781a4 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -322,13 +322,13 @@ void EditorAudioBus::_volume_changed(float p_normalized) { float EditorAudioBus::_normalized_volume_to_scaled_db(float normalized) { /* There are three different formulas for the conversion from normalized - * values to relative decibal values. - * One formula is an exponential graph which intends to counteract - * the logorithmic nature of human hearing. This is an approximation - * of the behaviour of a 'logarithmic potentiometer' found on most - * musical instruments and also emulated in popular software. - * The other two equations are hand-tuned linear tapers that intend to - * try to ease the exponential equation in areas where it makes sense.*/ + * values to relative decibal values. + * One formula is an exponential graph which intends to counteract + * the logorithmic nature of human hearing. This is an approximation + * of the behaviour of a 'logarithmic potentiometer' found on most + * musical instruments and also emulated in popular software. + * The other two equations are hand-tuned linear tapers that intend to + * try to ease the exponential equation in areas where it makes sense.*/ if (normalized > 0.6f) { return 22.22f * normalized - 16.2f; @@ -341,16 +341,16 @@ float EditorAudioBus::_normalized_volume_to_scaled_db(float normalized) { float EditorAudioBus::_scaled_db_to_normalized_volume(float db) { /* Inversion of equations found in _normalized_volume_to_scaled_db. - * IMPORTANT: If one function changes, the other much change to reflect it. */ + * IMPORTANT: If one function changes, the other much change to reflect it. */ if (db > -2.88) { return (db + 16.2f) / 22.22f; } else if (db < -38.602f) { return (db + 80.00f) / 830.72f; } else { if (db < 0.0) { - /* To acommodate for NaN on negative numbers for root, we will mirror the - * results of the postive db range in order to get the desired numerical - * value on the negative side. */ + /* To accommodate for NaN on negative numbers for root, we will mirror the + * results of the positive db range in order to get the desired numerical + * value on the negative side. */ float positive_x = Math::pow(Math::abs(db) / 45.0f, 1.0f / 3.0f) + 1.0f; Vector2 translation = Vector2(1.0f, 0.0f) - Vector2(positive_x, Math::abs(db)); Vector2 reflected_position = Vector2(1.0, 0.0f) + translation; diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index dc43faeff1..6751e58bb2 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -335,7 +335,9 @@ Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_pa pd->file_ofs.push_back(sd); - pd->ep->step(TTR("Storing File:") + " " + p_path, 2 + p_file * 100 / p_total, false); + if (pd->ep->step(TTR("Storing File:") + " " + p_path, 2 + p_file * 100 / p_total, false)) { + return ERR_SKIP; + } return OK; } @@ -362,7 +364,9 @@ Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_pat zipWriteInFileInZip(zip, p_data.ptr(), p_data.size()); zipCloseFileInZip(zip); - zd->ep->step(TTR("Storing File:") + " " + p_path, 2 + p_file * 100 / p_total, false); + if (zd->ep->step(TTR("Storing File:") + " " + p_path, 2 + p_file * 100 / p_total, false)) { + return ERR_SKIP; + } return OK; } @@ -749,27 +753,37 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & this->resolve_platform_feature_priorities(p_preset, remap_features); } + err = OK; + for (List<String>::Element *F = remaps.front(); F; F = F->next()) { String remap = F->get(); if (remap == "path") { String remapped_path = config->get_value("remap", remap); Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path); - p_func(p_udata, remapped_path, array, idx, total); + err = p_func(p_udata, remapped_path, array, idx, total); } else if (remap.begins_with("path.")) { String feature = remap.get_slice(".", 1); if (remap_features.has(feature)) { String remapped_path = config->get_value("remap", remap); Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path); - p_func(p_udata, remapped_path, array, idx, total); + err = p_func(p_udata, remapped_path, array, idx, total); } } } + if (err != OK) { + return err; + } + //also save the .import file Vector<uint8_t> array = FileAccess::get_file_as_array(path + ".import"); - p_func(p_udata, path + ".import", array, idx, total); + err = p_func(p_udata, path + ".import", array, idx, total); + + if (err != OK) { + return err; + } } else { @@ -884,7 +898,7 @@ Error EditorExportPlatform::_add_shared_object(void *p_userdata, const SharedObj Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, const String &p_path, Vector<SharedObject> *p_so_files) { - EditorProgress ep("savepack", TTR("Packing"), 102); + EditorProgress ep("savepack", TTR("Packing"), 102, true); String tmppath = EditorSettings::get_singleton()->get_cache_dir().plus_file("packtmp"); FileAccess *ftmp = FileAccess::open(tmppath, FileAccess::WRITE); @@ -982,7 +996,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c Error EditorExportPlatform::save_zip(const Ref<EditorExportPreset> &p_preset, const String &p_path) { - EditorProgress ep("savezip", TTR("Packing"), 102); + EditorProgress ep("savezip", TTR("Packing"), 102, true); //FileAccess *tmp = FileAccess::open(tmppath,FileAccess::WRITE); @@ -995,7 +1009,7 @@ Error EditorExportPlatform::save_zip(const Ref<EditorExportPreset> &p_preset, co zd.zip = zip; Error err = export_project_files(p_preset, _save_zip_file, &zd); - if (err != OK) + if (err != OK && err != ERR_SKIP) ERR_PRINT("Failed to export project files"); zipClose(zip, NULL); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index abd3bea951..90af593166 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -218,7 +218,7 @@ void EditorFileSystem::_scan_filesystem() { if (first_scan) { // only use this on first scan, afterwards it gets ignored // this is so on first reimport we synchronize versions, then - // we dont care until editor restart. This is for usability mainly so + // we don't care until editor restart. This is for usability mainly so // your workflow is not killed after changing a setting by forceful reimporting // everything there is. filesystem_settings_version_for_import = l.strip_edges(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 40e05940a7..907d43b26f 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1955,6 +1955,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { _scene_tab_closed(editor_data.get_edited_scene()); } + if (p_confirmed) + _menu_option_confirm(SCENE_TAB_CLOSE, true); + } break; case FILE_CLOSE_ALL_AND_QUIT: case FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER: @@ -2287,10 +2290,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { project_settings->popup_project_settings(); } break; - case RUN_PROJECT_DATA_FOLDER: { - - OS::get_singleton()->shell_open(String("file://") + OS::get_singleton()->get_user_data_dir()); - } break; case FILE_INSTALL_ANDROID_SOURCE: { if (p_confirmed) { @@ -2527,6 +2526,9 @@ void EditorNode::_tool_menu_option(int p_idx) { case TOOLS_ORPHAN_RESOURCES: { orphan_resources->show(); } break; + case RUN_PROJECT_DATA_FOLDER: { + OS::get_singleton()->shell_open(String("file://") + OS::get_singleton()->get_user_data_dir()); + } break; case TOOLS_CUSTOM: { if (tool_menu->get_item_submenu(p_idx) == "") { Array params = tool_menu->get_item_metadata(p_idx); diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index e3dc517a39..5f18959689 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -645,7 +645,7 @@ void EditorPropertyDictionary::update_property() { page->set_h_size_flags(SIZE_EXPAND_FILL); page->connect("value_changed", this, "_page_changed"); } else { - // Queue childs for deletion, delete immediately might cause errors. + // Queue children for deletion, deleting immediately might cause errors. for (int i = 1; i < vbox->get_child_count(); i++) { vbox->get_child(i)->queue_delete(); } diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index ed6d6578ad..4e499021f9 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -566,7 +566,7 @@ Error ExportTemplateManager::install_android_template() { f->close(); } { - //add version, to ensure building wont work if template and Godot version are mismatch + //add version, to ensure building won't work if template and Godot version don't match FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::WRITE); ERR_FAIL_COND_V(!f, ERR_CANT_CREATE); f->store_line(VERSION_FULL_CONFIG); @@ -636,7 +636,7 @@ Error ExportTemplateManager::install_android_template() { FileAccess::set_unix_permissions(to_write, (info.external_fa >> 16) & 0x01FF); #endif } else { - ERR_PRINTS("Cant uncompress file: " + to_write); + ERR_PRINTS("Can't uncompress file: " + to_write); } } diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 5ce22154e0..b7e9d36d88 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -90,7 +90,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory String file_type = p_dir->get_file_type(i); if (_is_file_type_disabled_by_feature_profile(file_type)) { - //if type is disabled, file wont be displayed. + //if type is disabled, file won't be displayed. continue; } String file_name = p_dir->get_file(i); diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index d72de3de48..5865ceb3af 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -81,7 +81,7 @@ void ResourceImporterTexture::_texture_reimport_normal(const Ref<StreamTexture> void ResourceImporterTexture::update_imports() { if (EditorFileSystem::get_singleton()->is_scanning() || EditorFileSystem::get_singleton()->is_importing()) { - return; // do nothing for noe + return; // do nothing for now } mutex->lock(); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 92579e5cef..828abef9a9 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -3305,9 +3305,7 @@ void ScriptEditorPlugin::edit(Object *p_object) { } else { script_editor->edit(p_script); } - } - - if (Object::cast_to<TextFile>(p_object)) { + } else if (Object::cast_to<TextFile>(p_object)) { script_editor->edit(Object::cast_to<TextFile>(p_object)); } } diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 21470d81ed..93c6614841 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -1654,7 +1654,7 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { edited_collision_shape = _convex; _set_edited_shape_points(_get_collision_shape_points(concave)); } else { - // Shoudn't haphen + // Shouldn't happen } for (int i = 0; i < sd.size(); i++) { if (sd[i].get("shape") == previous_shape) { @@ -1892,7 +1892,7 @@ void TileSetEditor::_update_toggle_shape_button() { tools[SHAPE_TOGGLE_TYPE]->set_icon(get_icon("ConcavePolygonShape2D", "EditorIcons")); tools[SHAPE_TOGGLE_TYPE]->set_text("Make Concave"); } else { - // Shoudn't happen + // Shouldn't happen separator_shape_toggle->hide(); tools[SHAPE_TOGGLE_TYPE]->hide(); } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index f3eb5d1483..ad698be0a3 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -1588,6 +1588,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Min", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Returns the lesser of two values."), VisualShaderNodeScalarOp::OP_MIN, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Mix", "Scalar", "Functions", "VisualShaderNodeScalarInterp", TTR("Linear interpolation between two scalars."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Negate", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeScalarFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("OneMinus", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("1.0 - scalar"), VisualShaderNodeScalarFunc::FUNC_ONEMINUS, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Pow", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Returns the value of the first parameter raised to the power of the second."), VisualShaderNodeScalarOp::OP_POW, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Radians", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Converts a quantity in degrees to radians."), VisualShaderNodeScalarFunc::FUNC_RADIANS, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Reciprocal", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("1.0 / scalar"), VisualShaderNodeScalarFunc::FUNC_RECIPROCAL, VisualShaderNode::PORT_TYPE_SCALAR)); @@ -1677,6 +1678,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Mix", "Vector", "Functions", "VisualShaderNodeVectorInterp", TTR("Linear interpolation between two vectors."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Negate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Normalize", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("OneMinus", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Pow", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), VisualShaderNodeVectorOp::OP_POW, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Radians", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in degrees to radians."), VisualShaderNodeVectorFunc::FUNC_RADIANS, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Reciprocal", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 / vector"), VisualShaderNodeVectorFunc::FUNC_RECIPROCAL, VisualShaderNode::PORT_TYPE_VECTOR)); @@ -1708,6 +1710,8 @@ VisualShaderEditor::VisualShaderEditor() { // SPECIAL + add_options.push_back(AddOption("Fresnel", "Special", "", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT)); add_options.push_back(AddOption("VectorDerivativeFunc", "Special", "Common", "VisualShaderNodeVectorDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) Vector derivative function."), -1, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT)); diff --git a/editor/project_export.cpp b/editor/project_export.cpp index b9cf7ec10a..e1950c666c 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -972,7 +972,7 @@ void ProjectExportDialog::_export_project_to_path(const String &p_path) { current->set_export_path(p_path); Error err = platform->export_project(current, export_debug->is_pressed(), p_path, 0); - if (err != OK) { + if (err != OK && err != ERR_SKIP) { if (err == ERR_FILE_NOT_FOUND) { error_dialog->set_text(vformat(TTR("Failed to export the project for platform '%s'.\nExport templates seem to be missing or invalid."), platform->get_name())); } else { // Assume misconfiguration. FIXME: Improve error handling and preset config validation. @@ -1001,7 +1001,7 @@ void ProjectExportDialog::_export_all_dialog_action(const String &p_str) { void ProjectExportDialog::_export_all(bool p_debug) { String mode = p_debug ? TTR("Debug") : TTR("Release"); - EditorProgress ep("exportall", TTR("Exporting All") + " " + mode, EditorExport::get_singleton()->get_export_preset_count()); + EditorProgress ep("exportall", TTR("Exporting All") + " " + mode, EditorExport::get_singleton()->get_export_preset_count(), true); for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) { Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(i); @@ -1012,7 +1012,7 @@ void ProjectExportDialog::_export_all(bool p_debug) { ep.step(preset->get_name(), i); Error err = platform->export_project(preset, p_debug, preset->get_export_path(), 0); - if (err != OK) { + if (err != OK && err != ERR_SKIP) { if (err == ERR_FILE_BAD_PATH) { error_dialog->set_text(TTR("The given export path doesn't exist:") + "\n" + preset->get_export_path().get_base_dir()); } else { diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 62845bfb9b..76feaedb1a 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -49,7 +49,7 @@ Node *SceneTreeEditor::get_scene_node() { void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_id) { if (connect_to_script_mode) { - return; //dont do anything in this mode + return; //don't do anything in this mode } TreeItem *item = Object::cast_to<TreeItem>(p_item); ERR_FAIL_COND(!item); diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot index f9408cfbbc..218eef4fc1 100644 --- a/editor/translations/editor.pot +++ b/editor/translations/editor.pot @@ -9860,7 +9860,7 @@ msgstr "" msgid "" "Container by itself serves no purpose unless a script configures it's " "children placement behavior.\n" -"If you dont't intend to add a script, then please use a plain 'Control' node " +"If you don't intend to add a script, then please use a plain 'Control' node " "instead." msgstr "" diff --git a/modules/assimp/editor_scene_importer_assimp.cpp b/modules/assimp/editor_scene_importer_assimp.cpp index 8d82fb2eeb..4cf8782721 100644 --- a/modules/assimp/editor_scene_importer_assimp.cpp +++ b/modules/assimp/editor_scene_importer_assimp.cpp @@ -310,8 +310,8 @@ void EditorSceneImporterAssimp::_generate_bone_groups(ImportState &state, const const aiBone *bone = mesh->mBones[j]; String name = _assimp_get_string(bone->mName); ownership[name] = owned_by; - //store the actuall full path for the bone transform - //when skeleton finds it's place in the tree, it will be restored + //store the actual full path for the bone transform + //when skeleton finds its place in the tree, it will be restored bind_xforms[name] = mesh_offset * _assimp_matrix_transform(bone->mOffsetMatrix); } } @@ -1460,7 +1460,7 @@ void EditorSceneImporterAssimp::_generate_node(ImportState &state, const aiNode int mesh_index = p_assimp_node->mMeshes[i]; surface_indices.push_back(mesh_index); - //take the chane and attempt to find the skeleton from the bones + //take the chance and attempt to find the skeleton from the bones if (!skeleton) { aiMesh *ai_mesh = state.assimp_scene->mMeshes[p_assimp_node->mMeshes[i]]; for (uint32_t j = 0; j < ai_mesh->mNumBones; j++) { @@ -1598,7 +1598,7 @@ void EditorSceneImporterAssimp::_generate_node(ImportState &state, const aiNode skeleton->localize_rests(); node_name = "Skeleton"; //don't use the bone root name - node_transform = Transform(); //dont transform + node_transform = Transform(); //don't transform new_node = skeleton; } else { diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index 6bfd98873e..738b415d16 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -1152,7 +1152,7 @@ public: bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) { - // Calculate the cummulative AABB of all shapes of the kinematic body + // Calculate the cumulative AABB of all shapes of the kinematic body btVector3 aabb_min, aabb_max; bool shapes_found = false; @@ -1347,7 +1347,7 @@ int SpaceBullet::add_separation_result(PhysicsServer::SeparationResult *r_result int SpaceBullet::recover_from_penetration_ray(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, int p_result_max, btVector3 &r_delta_recover_movement, PhysicsServer::SeparationResult *r_results) { - // Calculate the cummulative AABB of all shapes of the kinematic body + // Calculate the cumulative AABB of all shapes of the kinematic body btVector3 aabb_min, aabb_max; bool shapes_found = false; diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index 7e1cc937cd..3a61afa023 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -611,7 +611,7 @@ void CSGBrushOperation::_add_poly_points(const BuildPoly &p_poly, int p_edge, in { EdgeSort es; - es.angle = 0; //wont be checked here + es.angle = 0; //won't be checked here es.edge = p_edge; es.prev_point = p_from_point; es.edge_point = p_to_point; diff --git a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml index 894c17c684..d3d1e58b7b 100644 --- a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml +++ b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml @@ -110,7 +110,7 @@ Always use [code]TRANSFER_MODE_ORDERED[/code] in place of [code]TRANSFER_MODE_UNRELIABLE[/code]. This is the only way to use ordering with the RPC system. </member> <member name="channel_count" type="int" setter="set_channel_count" getter="get_channel_count"> - The number of channels to be used by ENet. Default: [code]3[/code]. Channels are used to separate different kinds of data. In realiable or ordered mode, for example, the packet delivery order is ensured on a per channel basis. + The number of channels to be used by ENet. Default: [code]3[/code]. Channels are used to separate different kinds of data. In reliable or ordered mode, for example, the packet delivery order is ensured on a per channel basis. </member> <member name="compression_mode" type="int" setter="set_compression_mode" getter="get_compression_mode" enum="NetworkedMultiplayerENet.CompressionMode"> The compression method used for network packets. Default is no compression. These have different tradeoffs of compression speed versus bandwidth, you may need to test which one works best for your use case if you use compression at all. diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp index 492b365128..18dfe08e85 100644 --- a/modules/enet/networked_multiplayer_enet.cpp +++ b/modules/enet/networked_multiplayer_enet.cpp @@ -231,7 +231,7 @@ void NetworkedMultiplayerENet::poll() { break; } - // A client joined with an invalid ID (neagtive values, 0, and 1 are reserved). + // A client joined with an invalid ID (negative values, 0, and 1 are reserved). // Probably trying to exploit us. if (server && ((int)event.data < 2 || peer_map.has((int)event.data))) { enet_peer_reset(event.peer); diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp index c8e17e8dc5..a27935bfe2 100644 --- a/modules/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative.cpp @@ -404,7 +404,7 @@ bool GDNative::terminate() { } else if (gdnatives->size() == 1) { // we're the last one, terminate! gdnatives->clear(); - // wew this looks scary, but all it does is remove the entry completely + // whew this looks scary, but all it does is remove the entry completely GDNativeLibrary::loaded_libraries->erase(GDNativeLibrary::loaded_libraries->find(library->get_current_library_path())); } } diff --git a/modules/gdnative/pluginscript/pluginscript_instance.h b/modules/gdnative/pluginscript/pluginscript_instance.h index b279fdad8b..381c334231 100644 --- a/modules/gdnative/pluginscript/pluginscript_instance.h +++ b/modules/gdnative/pluginscript/pluginscript_instance.h @@ -62,7 +62,7 @@ public: virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error); #if 0 // Rely on default implementations provided by ScriptInstance for the moment. - // Note that multilevel call could be removed in 3.0 release, so stay tunned + // Note that multilevel call could be removed in 3.0 release, so stay tuned // (see https://godotengine.org/qa/9244/can-override-the-_ready-and-_process-functions-child-classes) virtual void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount); virtual void call_multilevel_reversed(const StringName& p_method,const Variant** p_args,int p_argcount); diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 33e99cb82f..d7a809eb5f 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1064,7 +1064,7 @@ Variant::Type GDScriptInstance::get_property_type(const StringName &p_name, bool } void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const { - // exported members, not doen yet! + // exported members, not done yet! const GDScript *sptr = script.ptr(); List<PropertyInfo> props; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 903b3892d1..de15f939ce 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -7473,7 +7473,7 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { return; } - // Replace assignment with implict conversion + // Replace assignment with implicit conversion BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>(); convert->line = v.line; convert->function = GDScriptFunctions::TYPE_CONVERT; @@ -7837,14 +7837,14 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { if (_is_type_compatible(assign_type, lv->datatype)) { _mark_line_as_unsafe(lv->line); } else { - // Try implict conversion + // Try implicit conversion if (lv->datatype.kind != DataType::BUILTIN || !_is_type_compatible(lv->datatype, assign_type, true)) { _set_error("Assigned value type (" + assign_type.to_string() + ") doesn't match the variable's type (" + lv->datatype.to_string() + ").", lv->line); return; } - // Replace assignment with implict conversion + // Replace assignment with implicit conversion BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>(); convert->line = lv->line; convert->function = GDScriptFunctions::TYPE_CONVERT; @@ -7968,14 +7968,14 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { if (_is_type_compatible(rh_type, lh_type)) { _mark_line_as_unsafe(op->line); } else { - // Try implict conversion + // Try implicit conversion if (lh_type.kind != DataType::BUILTIN || !_is_type_compatible(lh_type, rh_type, true)) { _set_error("Assigned value type (" + rh_type.to_string() + ") doesn't match the variable's type (" + lh_type.to_string() + ").", op->line); return; } - // Replace assignment with implict conversion + // Replace assignment with implicit conversion BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>(); convert->line = op->line; convert->function = GDScriptFunctions::TYPE_CONVERT; diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index ef09e76d11..bfbd6ca80e 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -2020,7 +2020,7 @@ bool CSharpScript::_update_exports() { for (int i = fields.size() - 1; i >= 0; i--) { GDMonoField *field = fields[i]; - if (_get_member_export(top, field, prop_info, exported)) { + if (_get_member_export(field, prop_info, exported)) { StringName name = field->get_name(); if (exported) { @@ -2041,7 +2041,7 @@ bool CSharpScript::_update_exports() { for (int i = properties.size() - 1; i >= 0; i--) { GDMonoProperty *property = properties[i]; - if (_get_member_export(top, property, prop_info, exported)) { + if (_get_member_export(property, prop_info, exported)) { StringName name = property->get_name(); if (exported) { @@ -2168,17 +2168,19 @@ bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Ve * Returns false if there was an error, otherwise true. * If there was an error, r_prop_info and r_exported are not assigned any value. */ -bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported) { +bool CSharpScript::_get_member_export(IMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported) { - StringName name = p_member->get_name(); + // Goddammit, C++. All I wanted was some nested functions. +#define MEMBER_FULL_QUALIFIED_NAME(m_member) \ + (m_member->get_enclosing_class()->get_full_name() + "." + (String)m_member->get_name()) if (p_member->is_static()) { if (p_member->has_attribute(CACHED_CLASS(ExportAttribute))) - ERR_PRINTS("Cannot export member because it is static: " + p_class->get_full_name() + "." + name.operator String()); + ERR_PRINTS("Cannot export member because it is static: " + MEMBER_FULL_QUALIFIED_NAME(p_member)); return false; } - if (member_info.has(name)) + if (member_info.has(p_member->get_name())) return false; ManagedType type; @@ -2191,19 +2193,22 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_ CRASH_NOW(); } - GDMonoMarshal::ExportInfo export_info; - Variant::Type variant_type = GDMonoMarshal::managed_to_variant_type(type, &export_info); + Variant::Type variant_type = GDMonoMarshal::managed_to_variant_type(type); if (!p_member->has_attribute(CACHED_CLASS(ExportAttribute))) { - r_prop_info = PropertyInfo(variant_type, name.operator String(), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE); + r_prop_info = PropertyInfo(variant_type, (String)p_member->get_name(), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE); r_exported = false; return true; } if (p_member->get_member_type() == IMonoClassMember::MEMBER_TYPE_PROPERTY) { GDMonoProperty *property = static_cast<GDMonoProperty *>(p_member); - if (!property->has_getter() || !property->has_setter()) { - ERR_PRINTS("Cannot export property because it does not provide a getter or a setter: " + p_class->get_full_name() + "." + name.operator String()); + if (!property->has_getter()) { + ERR_PRINTS("Read-only property cannot be exported: " + MEMBER_FULL_QUALIFIED_NAME(p_member)); + return false; + } + if (!property->has_setter()) { + ERR_PRINTS("Set-only property (without getter) cannot be exported: " + MEMBER_FULL_QUALIFIED_NAME(p_member)); return false; } } @@ -2214,16 +2219,38 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_ String hint_string; if (variant_type == Variant::NIL) { - ERR_PRINTS("Unknown type of exported member: " + p_class->get_full_name() + "." + name.operator String()); + ERR_PRINTS("Unknown exported member type: " + MEMBER_FULL_QUALIFIED_NAME(p_member)); return false; - } else if (variant_type == Variant::INT && type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(type.type_class->get_mono_ptr())) { - // TODO: Move to ExportInfo? - variant_type = Variant::INT; - hint = PROPERTY_HINT_ENUM; + } + + int hint_res = _try_get_member_export_hint(p_member, type, variant_type, /* allow_generics: */ true, hint, hint_string); + + if (hint_res == -1) { + ERR_EXPLAIN("Error while trying to determine information about the exported member: " + MEMBER_FULL_QUALIFIED_NAME(p_member)); + ERR_FAIL_V(false); + } + + if (hint_res == 0) { + hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr)); + hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr); + } + + r_prop_info = PropertyInfo(variant_type, (String)p_member->get_name(), hint, hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE); + r_exported = true; + + return true; + +#undef MEMBER_FULL_QUALIFIED_NAME +} + +int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string) { + + if (p_variant_type == Variant::INT && p_type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(p_type.type_class->get_mono_ptr())) { + r_hint = PROPERTY_HINT_ENUM; - Vector<MonoClassField *> fields = type.type_class->get_enum_fields(); + Vector<MonoClassField *> fields = p_type.type_class->get_enum_fields(); - MonoType *enum_basetype = mono_class_enum_basetype(type.type_class->get_mono_ptr()); + MonoType *enum_basetype = mono_class_enum_basetype(p_type.type_class->get_mono_ptr()); String name_only_hint_string; @@ -2236,12 +2263,12 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_ MonoClassField *field = fields[i]; if (i > 0) { - hint_string += ","; + r_hint_string += ","; name_only_hint_string += ","; } String enum_field_name = mono_field_get_name(field); - hint_string += enum_field_name; + r_hint_string += enum_field_name; name_only_hint_string += enum_field_name; // TODO: @@ -2251,54 +2278,73 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_ MonoObject *val_obj = mono_field_get_value_object(mono_domain_get(), field, NULL); if (val_obj == NULL) { - ERR_PRINTS("Failed to get '" + enum_field_name + "' constant enum value of exported member: " + - p_class->get_full_name() + "." + name.operator String()); - return false; + ERR_EXPLAIN("Failed to get '" + enum_field_name + "' constant enum value"); + ERR_FAIL_V(-1); } bool r_error; uint64_t val = GDMonoUtils::unbox_enum_value(val_obj, enum_basetype, r_error); if (r_error) { - ERR_PRINTS("Failed to unbox '" + enum_field_name + "' constant enum value of exported member: " + - p_class->get_full_name() + "." + name.operator String()); - return false; + ERR_EXPLAIN("Failed to unbox '" + enum_field_name + "' constant enum value"); + ERR_FAIL_V(-1); } if (val != (unsigned int)i) { uses_default_values = false; } - hint_string += ":"; - hint_string += String::num_uint64(val); + r_hint_string += ":"; + r_hint_string += String::num_uint64(val); } if (uses_default_values) { // If we use the format NAME:VAL, that's what the editor displays. // That's annoying if the user is not using custom values for the enum constants. // This may not be needed in the future if the editor is changed to not display values. - hint_string = name_only_hint_string; + r_hint_string = name_only_hint_string; } - } else if (variant_type == Variant::OBJECT && CACHED_CLASS(GodotReference)->is_assignable_from(type.type_class)) { - GDMonoClass *field_native_class = GDMonoUtils::get_class_native_base(type.type_class); + } else if (p_variant_type == Variant::OBJECT && CACHED_CLASS(GodotResource)->is_assignable_from(p_type.type_class)) { + GDMonoClass *field_native_class = GDMonoUtils::get_class_native_base(p_type.type_class); CRASH_COND(field_native_class == NULL); - hint = PROPERTY_HINT_RESOURCE_TYPE; - hint_string = NATIVE_GDMONOCLASS_NAME(field_native_class); - } else if (variant_type == Variant::ARRAY && export_info.array.element_type != Variant::NIL) { - String elem_type_str = itos(export_info.array.element_type); - hint = PROPERTY_HINT_TYPE_STRING; - hint_string = elem_type_str + "/" + elem_type_str + ":" + export_info.array.element_native_name; - } else if (variant_type == Variant::DICTIONARY && export_info.dictionary.key_type != Variant::NIL && export_info.dictionary.value_type != Variant::NIL) { - // TODO: There is no hint for this yet + r_hint = PROPERTY_HINT_RESOURCE_TYPE; + r_hint_string = NATIVE_GDMONOCLASS_NAME(field_native_class); + } else if (p_allow_generics && p_variant_type == Variant::ARRAY) { + // Nested arrays are not supported in the inspector + + ManagedType elem_type; + + if (!GDMonoMarshal::try_get_array_element_type(p_type, elem_type)) + return 0; + + Variant::Type elem_variant_type = GDMonoMarshal::managed_to_variant_type(elem_type); + + PropertyHint elem_hint = PROPERTY_HINT_NONE; + String elem_hint_string; + + if (elem_variant_type == Variant::NIL) { + ERR_EXPLAIN("Unknown array element type"); + ERR_FAIL_V(-1); + } + + int hint_res = _try_get_member_export_hint(p_member, elem_type, elem_variant_type, /* allow_generics: */ false, elem_hint, elem_hint_string); + + if (hint_res == -1) { + ERR_EXPLAIN("Error while trying to determine information about the array element type"); + ERR_FAIL_V(-1); + } + + // Format: type/hint:hint_string + r_hint_string = itos(elem_variant_type) + "/" + itos(elem_hint) + ":" + elem_hint_string; + r_hint = PROPERTY_HINT_TYPE_STRING; + + } else if (p_allow_generics && p_variant_type == Variant::DICTIONARY) { + // TODO: Dictionaries are not supported in the inspector } else { - hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr)); - hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr); + return 0; } - r_prop_info = PropertyInfo(variant_type, name.operator String(), hint, hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE); - r_exported = true; - - return true; + return 1; } #endif diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index fe4eed2e24..298d55c4df 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -127,7 +127,8 @@ class CSharpScript : public Script { bool _update_exports(); #ifdef TOOLS_ENABLED - bool _get_member_export(GDMonoClass *p_class, IMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported); + bool _get_member_export(IMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported); + static int _try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string); #endif CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error); diff --git a/modules/mono/glue/Managed/Files/DynamicObject.cs b/modules/mono/glue/Managed/Files/DynamicObject.cs index 9860feafdd..a0f105d55e 100644 --- a/modules/mono/glue/Managed/Files/DynamicObject.cs +++ b/modules/mono/glue/Managed/Files/DynamicObject.cs @@ -202,7 +202,7 @@ namespace Godot //public override bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes); //public override bool TryDeleteMember(DeleteMemberBinder binder); - // Invokation on the object itself, e.g.: obj(param) + // Invocation on the object itself, e.g.: obj(param) //public override bool TryInvoke(InvokeBinder binder, object[] args, out object result); // No unnary operations to handle diff --git a/modules/mono/glue/Managed/Files/MarshalUtils.cs b/modules/mono/glue/Managed/Files/MarshalUtils.cs index 7e72b0edb5..730a1e1585 100644 --- a/modules/mono/glue/Managed/Files/MarshalUtils.cs +++ b/modules/mono/glue/Managed/Files/MarshalUtils.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Collections.Generic; namespace Godot { @@ -8,29 +9,113 @@ namespace Godot static class MarshalUtils { + /// <summary> + /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> + /// is <see cref="Godot.Collections.Array{T}"/>; otherwise returns <see langword="false"/>. + /// </summary> + /// <exception cref="System.InvalidOperationException"> + /// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false. + /// </exception> static bool TypeIsGenericArray(Type type) { return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Array<>); } + /// <summary> + /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> + /// is <see cref="Godot.Collections.Dictionary{T}"/>; otherwise returns <see langword="false"/>. + /// </summary> + /// <exception cref="System.InvalidOperationException"> + /// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false. + /// </exception> static bool TypeIsGenericDictionary(Type type) { return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Dictionary<,>); } - static void ArrayGetElementType(Type type, out Type elementType) + static void ArrayGetElementType(Type arrayType, out Type elementType) { - elementType = type.GetGenericArguments()[0]; + elementType = arrayType.GetGenericArguments()[0]; } - static void DictionaryGetKeyValueTypes(Type type, out Type keyType, out Type valueType) + static void DictionaryGetKeyValueTypes(Type dictionaryType, out Type keyType, out Type valueType) { - var genericArgs = type.GetGenericArguments(); - + var genericArgs = dictionaryType.GetGenericArguments(); keyType = genericArgs[0]; valueType = genericArgs[1]; } + static bool GenericIEnumerableIsAssignableFromType(Type type, out Type elementType) + { + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>)) + { + elementType = type.GetGenericArguments()[0]; + return true; + } + + foreach (var interfaceType in type.GetInterfaces()) + { + if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) + { + elementType = interfaceType.GetGenericArguments()[0]; + return true; + } + } + + Type baseType = type.BaseType; + + if (baseType == null) + { + elementType = null; + return false; + } + + return GenericIEnumerableIsAssignableFromType(baseType, out elementType); + } + + static bool GenericIDictionaryIsAssignableFromType(Type type, out Type keyType, out Type valueType) + { + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>)) + { + var genericArgs = type.GetGenericArguments(); + keyType = genericArgs[0]; + valueType = genericArgs[1]; + return true; + } + + foreach (var interfaceType in type.GetInterfaces()) + { + if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IDictionary<,>)) + { + var genericArgs = interfaceType.GetGenericArguments(); + keyType = genericArgs[0]; + valueType = genericArgs[1]; + return true; + } + } + + Type baseType = type.BaseType; + + if (baseType == null) + { + keyType = null; + valueType = null; + return false; + } + + return GenericIDictionaryIsAssignableFromType(baseType, out keyType, out valueType); + } + + static Type MakeGenericArrayType(Type elemType) + { + return typeof(Godot.Collections.Array<>).MakeGenericType(elemType); + } + + static Type MakeGenericDictionaryType(Type keyType, Type valueType) + { + return typeof(Godot.Collections.Dictionary<,>).MakeGenericType(keyType, valueType); + } + // TODO Add support for IEnumerable<T> and IDictionary<TKey, TValue> // TODO: EnumerableToArray and IDictionaryToDictionary can be optimized @@ -64,5 +149,26 @@ namespace Godot Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, entry.Key, entry.Value); } } + + internal static void GenericIDictionaryToDictionary(object dictionary, IntPtr godotDictionaryPtr) + { +#if DEBUG + if (!GenericIDictionaryIsAssignableFromType(dictionary.GetType())) + throw new InvalidOperationException("The type does not implement IDictionary<,>"); +#endif + + // TODO: Can we optimize this? + + var keys = ((IEnumerable)dictionary.GetType().GetProperty("Keys").GetValue(dictionary)).GetEnumerator(); + var values = ((IEnumerable)dictionary.GetType().GetProperty("Values").GetValue(dictionary)).GetEnumerator(); + + while (keys.MoveNext() && values.MoveNext()) + { + object key = keys.Current; + object value = values.Current; + + Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, key, value); + } + } } } diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp index 9779797d1a..2e79f87625 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -313,12 +313,32 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ break; } + // The order in which we check the following interfaces is very important (dictionaries and generics first) + + MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type()); + + MonoReflectionType *key_reftype, *value_reftype; + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) { + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), + GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype)); + mono_field_set_value(p_object, mono_field, managed); + break; + } + if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary)); mono_field_set_value(p_object, mono_field, managed); break; } + MonoReflectionType *elem_reftype; + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) { + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), + GDMonoUtils::Marshal::make_generic_array_type(elem_reftype)); + mono_field_set_value(p_object, mono_field, managed); + break; + } + if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array)); mono_field_set_value(p_object, mono_field, managed); @@ -432,26 +452,24 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ case MONO_TYPE_GENERICINST: { MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type.type_class->get_mono_type()); - MonoException *exc = NULL; - - GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary); - MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - - if (is_dict) { + if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), type.type_class); mono_field_set_value(p_object, mono_field, managed); break; } - exc = NULL; + if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), type.type_class); + mono_field_set_value(p_object, mono_field, managed); + break; + } - GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray); - MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + // The order in which we check the following interfaces is very important (dictionaries and generics first) - if (is_array) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), type.type_class); + MonoReflectionType *key_reftype, *value_reftype; + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) { + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), + GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype)); mono_field_set_value(p_object, mono_field, managed); break; } @@ -462,6 +480,14 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ break; } + MonoReflectionType *elem_reftype; + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) { + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), + GDMonoUtils::Marshal::make_generic_array_type(elem_reftype)); + mono_field_set_value(p_object, mono_field, managed); + break; + } + if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array)); mono_field_set_value(p_object, mono_field, managed); diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h index e348583370..a7727ddf34 100644 --- a/modules/mono/mono_gd/gd_mono_field.h +++ b/modules/mono/mono_gd/gd_mono_field.h @@ -47,9 +47,11 @@ class GDMonoField : public IMonoClassMember { MonoCustomAttrInfo *attributes; public: - virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_FIELD; } + virtual GDMonoClass *get_enclosing_class() const GD_FINAL { return owner; } - virtual StringName get_name() GD_FINAL { return name; } + virtual MemberType get_member_type() const GD_FINAL { return MEMBER_TYPE_FIELD; } + + virtual StringName get_name() const GD_FINAL { return name; } virtual bool is_static() GD_FINAL; virtual Visibility get_visibility() GD_FINAL; diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index d586b73cf9..461dcf3ec0 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -35,7 +35,7 @@ namespace GDMonoMarshal { -Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_export_info) { +Variant::Type managed_to_variant_type(const ManagedType &p_type) { switch (p_type.type_encoding) { case MONO_TYPE_BOOLEAN: return Variant::BOOL; @@ -157,10 +157,24 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_e return Variant::ARRAY; } + // The order in which we check the following interfaces is very important (dictionaries and generics first) + + MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type()); + + MonoReflectionType *key_reftype, *value_reftype; + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) { + return Variant::DICTIONARY; + } + if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { return Variant::DICTIONARY; } + MonoReflectionType *elem_reftype; + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) { + return Variant::ARRAY; + } + if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { return Variant::ARRAY; } @@ -169,71 +183,96 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_e case MONO_TYPE_GENERICINST: { MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type()); - MonoException *exc = NULL; - GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary); - MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - - if (is_dict) { - if (r_export_info) { - MonoReflectionType *key_reftype; - MonoReflectionType *value_reftype; + if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { + return Variant::DICTIONARY; + } - exc = NULL; - invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes), - reftype, &key_reftype, &value_reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { + return Variant::ARRAY; + } - ManagedType key_type = ManagedType::from_reftype(key_reftype); - ManagedType value_type = ManagedType::from_reftype(value_reftype); + // The order in which we check the following interfaces is very important (dictionaries and generics first) - r_export_info->dictionary.key_type = managed_to_variant_type(key_type); - r_export_info->dictionary.key_native_name = NATIVE_GDMONOCLASS_NAME(key_type.type_class); - r_export_info->dictionary.value_type = managed_to_variant_type(value_type); - r_export_info->dictionary.value_native_name = NATIVE_GDMONOCLASS_NAME(value_type.type_class); - } + MonoReflectionType *key_reftype, *value_reftype; + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) + return Variant::DICTIONARY; + if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { return Variant::DICTIONARY; } - exc = NULL; - GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray); - MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + MonoReflectionType *elem_reftype; + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) + return Variant::ARRAY; - if (is_array) { - if (r_export_info) { - MonoReflectionType *elem_reftype; + if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { + return Variant::ARRAY; + } + } break; + + default: { + } break; + } - exc = NULL; - invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType), - reftype, &elem_reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); + // Unknown + return Variant::NIL; +} - ManagedType elem_type = ManagedType::from_reftype(elem_reftype); +bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type) { + switch (p_array_type.type_encoding) { + case MONO_TYPE_GENERICINST: { + MonoReflectionType *array_reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_array_type.type_class->get_mono_type()); - r_export_info->array.element_type = managed_to_variant_type(elem_type); - r_export_info->array.element_native_name = NATIVE_GDMONOCLASS_NAME(elem_type.type_class); - } + if (GDMonoUtils::Marshal::type_is_generic_array(array_reftype)) { + MonoReflectionType *elem_reftype; - return Variant::ARRAY; - } + GDMonoUtils::Marshal::array_get_element_type(array_reftype, &elem_reftype); - if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { - return Variant::DICTIONARY; + r_elem_type = ManagedType::from_reftype(elem_reftype); + return true; } - if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { - return Variant::ARRAY; + MonoReflectionType *elem_reftype; + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(array_reftype, &elem_reftype)) { + r_elem_type = ManagedType::from_reftype(elem_reftype); + return true; } } break; + default: { + } break; + } + + return false; +} +bool try_get_dictionary_key_value_types(const ManagedType &p_dictionary_type, ManagedType &r_key_type, ManagedType &r_value_type) { + switch (p_dictionary_type.type_encoding) { + case MONO_TYPE_GENERICINST: { + MonoReflectionType *dict_reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_dictionary_type.type_class->get_mono_type()); + + if (GDMonoUtils::Marshal::type_is_generic_dictionary(dict_reftype)) { + MonoReflectionType *key_reftype; + MonoReflectionType *value_reftype; + + GDMonoUtils::Marshal::dictionary_get_key_value_types(dict_reftype, &key_reftype, &value_reftype); + + r_key_type = ManagedType::from_reftype(key_reftype); + r_value_type = ManagedType::from_reftype(value_reftype); + return true; + } + + MonoReflectionType *key_reftype, *value_reftype; + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(dict_reftype, &key_reftype, &value_reftype)) { + r_key_type = ManagedType::from_reftype(key_reftype); + r_value_type = ManagedType::from_reftype(value_reftype); + return true; + } + } break; default: { } break; } - // Unknown - return Variant::NIL; + return false; } String mono_to_utf8_string(MonoString *p_mono_string) { @@ -502,10 +541,26 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); } + // The order in which we check the following interfaces is very important (dictionaries and generics first) + + MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type()); + + MonoReflectionType *key_reftype, *value_reftype; + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) { + return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), + GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype)); + } + if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary)); } + MonoReflectionType *elem_reftype; + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) { + return GDMonoUtils::create_managed_from(p_var->operator Array(), + GDMonoUtils::Marshal::make_generic_array_type(elem_reftype)); + } + if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); } @@ -603,28 +658,32 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty case MONO_TYPE_GENERICINST: { MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type()); - MonoException *exc = NULL; - GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary); - MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - - if (is_dict) { + if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), p_type.type_class); } - exc = NULL; - GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray); - MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - - if (is_array) { + if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class); } + // The order in which we check the following interfaces is very important (dictionaries and generics first) + + MonoReflectionType *key_reftype, *value_reftype; + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) { + return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), + GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype)); + } + if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary)); } + MonoReflectionType *elem_reftype; + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) { + return GDMonoUtils::create_managed_from(p_var->operator Array(), + GDMonoUtils::Marshal::make_generic_array_type(elem_reftype)); + } + if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); } @@ -787,66 +846,64 @@ Variant mono_object_to_variant(MonoObject *p_obj) { return ptr ? Variant(*ptr) : Variant(); } + // The order in which we check the following interfaces is very important (dictionaries and generics first) + + MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type()); + + MonoReflectionType *key_reftype, *value_reftype; + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) { + return GDMonoUtils::Marshal::generic_idictionary_to_dictionary(p_obj); + } + if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { - Dictionary dict; - MonoException *exc = NULL; - invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary), p_obj, &dict, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - return dict; + return GDMonoUtils::Marshal::idictionary_to_dictionary(p_obj); + } + + MonoReflectionType *elem_reftype; + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) { + return GDMonoUtils::Marshal::enumerable_to_array(p_obj); } if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { - Array array; - MonoException *exc = NULL; - invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray), p_obj, &array, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - return array; + return GDMonoUtils::Marshal::enumerable_to_array(p_obj); } } break; case MONO_TYPE_GENERICINST: { MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type.type_class->get_mono_type()); - MonoException *exc = NULL; - - GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary); - MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - - if (is_dict) { - exc = NULL; + if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { + MonoException *exc = NULL; MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc); UNLIKELY_UNHANDLED_EXCEPTION(exc); return *unbox<Dictionary *>(ret); } - exc = NULL; - - GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray); - MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - - if (is_array) { - exc = NULL; + if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { + MonoException *exc = NULL; MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc); UNLIKELY_UNHANDLED_EXCEPTION(exc); return *unbox<Array *>(ret); } + // The order in which we check the following interfaces is very important (dictionaries and generics first) + + MonoReflectionType *key_reftype, *value_reftype; + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) { + return GDMonoUtils::Marshal::generic_idictionary_to_dictionary(p_obj); + } + if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { - Dictionary dict; - exc = NULL; - invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary), p_obj, &dict, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - return dict; + return GDMonoUtils::Marshal::idictionary_to_dictionary(p_obj); + } + + MonoReflectionType *elem_reftype; + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) { + return GDMonoUtils::Marshal::enumerable_to_array(p_obj); } if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { - Array array; - exc = NULL; - invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray), p_obj, &array, &exc); - UNLIKELY_UNHANDLED_EXCEPTION(exc); - return array; + return GDMonoUtils::Marshal::enumerable_to_array(p_obj); } } break; } @@ -1075,4 +1132,5 @@ PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array) { return ret; } + } // namespace GDMonoMarshal diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index 8d3fd4b349..3fa958ac32 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -57,28 +57,10 @@ T unbox(MonoObject *p_obj) { #define BOX_PTR(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(IntPtr), x) #define BOX_ENUM(m_enum_class, x) mono_value_box(mono_domain_get(), m_enum_class, &x) -// FIXME: Made this struct in a hurry. It could be done differently. -struct ExportInfo { - struct ArrayInfo { - Variant::Type element_type; - String element_native_name; - - ArrayInfo() : - element_type(Variant::NIL) {} - } array; - struct DictionaryInfo { - Variant::Type key_type; - String key_native_name; - Variant::Type value_type; - String value_native_name; - - DictionaryInfo() : - key_type(Variant::NIL), - value_type(Variant::NIL) {} - } dictionary; -}; +Variant::Type managed_to_variant_type(const ManagedType &p_type); -Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_export_info = NULL); +bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type); +bool try_get_dictionary_key_value_types(const ManagedType &p_dictionary_type, ManagedType &r_key_type, ManagedType &r_value_type); // String diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp index 7f11e4671d..f290c6c8ac 100644 --- a/modules/mono/mono_gd/gd_mono_method.cpp +++ b/modules/mono/mono_gd/gd_mono_method.cpp @@ -74,6 +74,10 @@ void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) { method_info = MethodInfo(); } +GDMonoClass *GDMonoMethod::get_enclosing_class() const { + return GDMono::get_singleton()->get_class(mono_method_get_class(mono_method)); +} + bool GDMonoMethod::is_static() { return mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_STATIC; } diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h index f74cef438d..2fc8628f27 100644 --- a/modules/mono/mono_gd/gd_mono_method.h +++ b/modules/mono/mono_gd/gd_mono_method.h @@ -57,9 +57,11 @@ class GDMonoMethod : public IMonoClassMember { MonoMethod *mono_method; public: - virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_METHOD; } + virtual GDMonoClass *get_enclosing_class() const GD_FINAL; - virtual StringName get_name() GD_FINAL { return name; } + virtual MemberType get_member_type() const GD_FINAL { return MEMBER_TYPE_METHOD; } + + virtual StringName get_name() const GD_FINAL { return name; } virtual bool is_static() GD_FINAL; diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h index 2700c460b0..d6efa60412 100644 --- a/modules/mono/mono_gd/gd_mono_property.h +++ b/modules/mono/mono_gd/gd_mono_property.h @@ -47,9 +47,11 @@ class GDMonoProperty : public IMonoClassMember { MonoCustomAttrInfo *attributes; public: - virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_PROPERTY; } + virtual GDMonoClass *get_enclosing_class() const GD_FINAL { return owner; } - virtual StringName get_name() GD_FINAL { return name; } + virtual MemberType get_member_type() const GD_FINAL { return MEMBER_TYPE_PROPERTY; } + + virtual StringName get_name() const GD_FINAL { return name; } virtual bool is_static() GD_FINAL; virtual Visibility get_visibility() GD_FINAL; diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index bcf5712d16..5236e43c90 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -109,7 +109,7 @@ void MonoCache::clear_members() { class_NodePath = NULL; class_RID = NULL; class_GodotObject = NULL; - class_GodotReference = NULL; + class_GodotResource = NULL; class_Node = NULL; class_Control = NULL; class_Spatial = NULL; @@ -151,12 +151,25 @@ void MonoCache::clear_members() { methodthunk_SignalAwaiter_FailureCallback = NULL; methodthunk_GodotTaskScheduler_Activate = NULL; + // Start of MarshalUtils methods + methodthunk_MarshalUtils_TypeIsGenericArray = NULL; methodthunk_MarshalUtils_TypeIsGenericDictionary = NULL; + methodthunk_MarshalUtils_ArrayGetElementType = NULL; methodthunk_MarshalUtils_DictionaryGetKeyValueTypes = NULL; + + methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType = NULL; + methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType = NULL; + + methodthunk_MarshalUtils_MakeGenericArrayType = NULL; + methodthunk_MarshalUtils_MakeGenericDictionaryType = NULL; + methodthunk_MarshalUtils_EnumerableToArray = NULL; methodthunk_MarshalUtils_IDictionaryToDictionary = NULL; + methodthunk_MarshalUtils_GenericIDictionaryToDictionary = NULL; + + // End of MarshalUtils methods task_scheduler_handle = Ref<MonoGCHandle>(); } @@ -217,7 +230,7 @@ void update_godot_api_cache() { CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath)); CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(RID)); CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object)); - CACHE_CLASS_AND_CHECK(GodotReference, GODOT_API_CLASS(Reference)); + CACHE_CLASS_AND_CHECK(GodotResource, GODOT_API_CLASS(Resource)); CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node)); CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control)); CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial)); @@ -258,12 +271,28 @@ void update_godot_api_cache() { CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("FailureCallback", 0)); CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method_thunk("Activate", 0)); + // Start of MarshalUtils methods + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, (TypeIsGenericArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericArray", 1)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, (TypeIsGenericDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericDictionary", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, (ArrayGetElementType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("ArrayGetElementType", 2)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, (DictionaryGetKeyValueTypes)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("DictionaryGetKeyValueTypes", 3)); + + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, (ArrayGetElementType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("ArrayGetElementType", 2)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, (DictionaryGetKeyValueTypes)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("DictionaryGetKeyValueTypes", 3)); + + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType, (GenericIEnumerableIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIEnumerableIsAssignableFromType", 2)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType, (GenericIDictionaryIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryIsAssignableFromType", 3)); + + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericArrayType, (MakeGenericArrayType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("MakeGenericArrayType", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericDictionaryType, (MakeGenericDictionaryType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("MakeGenericDictionaryType", 2)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, EnumerableToArray, (EnumerableToArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("EnumerableToArray", 2)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IDictionaryToDictionary, (IDictionaryToDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IDictionaryToDictionary", 2)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryToDictionary, (GenericIDictionaryToDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryToDictionary", 2)); + + // End of MarshalUtils methods #ifdef DEBUG_ENABLED CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method_thunk("GetStackFrameInfo", 4)); @@ -727,4 +756,99 @@ void dispose(MonoObject *p_mono_object, MonoException **r_exc) { invoke_method_thunk(CACHED_METHOD_THUNK(GodotObject, Dispose), p_mono_object, r_exc); } +namespace Marshal { + +MonoBoolean type_is_generic_array(MonoReflectionType *p_reftype) { + TypeIsGenericArray thunk = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray); + MonoException *exc = NULL; + MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return res; +} + +MonoBoolean type_is_generic_dictionary(MonoReflectionType *p_reftype) { + TypeIsGenericDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary); + MonoException *exc = NULL; + MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return res; +} + +void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) { + ArrayGetElementType thunk = CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType); + MonoException *exc = NULL; + invoke_method_thunk(thunk, p_array_reftype, r_elem_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); +} + +void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) { + DictionaryGetKeyValueTypes thunk = CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes); + MonoException *exc = NULL; + invoke_method_thunk(thunk, p_dict_reftype, r_key_reftype, r_value_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); +} + +MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype) { + GenericIEnumerableIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType); + MonoException *exc = NULL; + MonoBoolean res = invoke_method_thunk(thunk, p_reftype, r_elem_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return res; +} + +MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) { + GenericIDictionaryIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType); + MonoException *exc = NULL; + MonoBoolean res = invoke_method_thunk(thunk, p_reftype, r_key_reftype, r_value_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return res; +} + +Array enumerable_to_array(MonoObject *p_enumerable) { + Array result; + EnumerableToArray thunk = CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray); + MonoException *exc = NULL; + invoke_method_thunk(thunk, p_enumerable, &result, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return result; +} + +Dictionary idictionary_to_dictionary(MonoObject *p_idictionary) { + Dictionary result; + IDictionaryToDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary); + MonoException *exc = NULL; + invoke_method_thunk(thunk, p_idictionary, &result, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return result; +} + +Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary) { + Dictionary result; + GenericIDictionaryToDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryToDictionary); + MonoException *exc = NULL; + invoke_method_thunk(thunk, p_generic_idictionary, &result, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return result; +} + +GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype) { + MakeGenericArrayType thunk = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericArrayType); + MonoException *exc = NULL; + MonoReflectionType *reftype = invoke_method_thunk(thunk, p_elem_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype))); +} + +GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) { + MakeGenericDictionaryType thunk = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericDictionaryType); + MonoException *exc = NULL; + MonoReflectionType *reftype = invoke_method_thunk(thunk, p_key_reftype, p_value_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype))); +} + +} // namespace Marshal + +// namespace Marshal + } // namespace GDMonoUtils diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index 87610e286c..081a8a9813 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -60,10 +60,41 @@ typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, Mo typedef MonoBoolean (*TypeIsGenericArray)(MonoReflectionType *, MonoException **); typedef MonoBoolean (*TypeIsGenericDictionary)(MonoReflectionType *, MonoException **); -typedef MonoBoolean (*ArrayGetElementType)(MonoReflectionType *, MonoReflectionType **, MonoException **); -typedef MonoBoolean (*DictionaryGetKeyValueTypes)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **); + +typedef void (*ArrayGetElementType)(MonoReflectionType *, MonoReflectionType **, MonoException **); +typedef void (*DictionaryGetKeyValueTypes)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **); + +typedef MonoBoolean (*GenericIEnumerableIsAssignableFromType)(MonoReflectionType *, MonoReflectionType **, MonoException **); +typedef MonoBoolean (*GenericIDictionaryIsAssignableFromType)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **); + +typedef MonoReflectionType *(*MakeGenericArrayType)(MonoReflectionType *, MonoException **); +typedef MonoReflectionType *(*MakeGenericDictionaryType)(MonoReflectionType *, MonoReflectionType *, MonoException **); + typedef void (*EnumerableToArray)(MonoObject *, Array *, MonoException **); typedef void (*IDictionaryToDictionary)(MonoObject *, Dictionary *, MonoException **); +typedef void (*GenericIDictionaryToDictionary)(MonoObject *, Dictionary *, MonoException **); + +namespace Marshal { + +MonoBoolean type_is_generic_array(MonoReflectionType *p_reftype); +MonoBoolean type_is_generic_dictionary(MonoReflectionType *p_reftype); + +void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype); +void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype); + +MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype); +MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype); + +GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype); +GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype); + +Array enumerable_to_array(MonoObject *p_enumerable); +Dictionary idictionary_to_dictionary(MonoObject *p_idictionary); +Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary); + +} // namespace Marshal + +// End of MarshalUtils methods struct MonoCache { @@ -114,7 +145,7 @@ struct MonoCache { GDMonoClass *class_NodePath; GDMonoClass *class_RID; GDMonoClass *class_GodotObject; - GDMonoClass *class_GodotReference; + GDMonoClass *class_GodotResource; GDMonoClass *class_Node; GDMonoClass *class_Control; GDMonoClass *class_Spatial; @@ -156,12 +187,25 @@ struct MonoCache { SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback; GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate; + // Start of MarshalUtils methods + TypeIsGenericArray methodthunk_MarshalUtils_TypeIsGenericArray; TypeIsGenericDictionary methodthunk_MarshalUtils_TypeIsGenericDictionary; + ArrayGetElementType methodthunk_MarshalUtils_ArrayGetElementType; DictionaryGetKeyValueTypes methodthunk_MarshalUtils_DictionaryGetKeyValueTypes; + + GenericIEnumerableIsAssignableFromType methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType; + GenericIDictionaryIsAssignableFromType methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType; + + MakeGenericArrayType methodthunk_MarshalUtils_MakeGenericArrayType; + MakeGenericDictionaryType methodthunk_MarshalUtils_MakeGenericDictionaryType; + EnumerableToArray methodthunk_MarshalUtils_EnumerableToArray; IDictionaryToDictionary methodthunk_MarshalUtils_IDictionaryToDictionary; + GenericIDictionaryToDictionary methodthunk_MarshalUtils_GenericIDictionaryToDictionary; + + // End of MarshalUtils methods Ref<MonoGCHandle> task_scheduler_handle; diff --git a/modules/mono/mono_gd/i_mono_class_member.h b/modules/mono/mono_gd/i_mono_class_member.h index 553d9edc72..f4de4e3230 100644 --- a/modules/mono/mono_gd/i_mono_class_member.h +++ b/modules/mono/mono_gd/i_mono_class_member.h @@ -53,9 +53,11 @@ public: virtual ~IMonoClassMember() {} - virtual MemberType get_member_type() = 0; + virtual GDMonoClass *get_enclosing_class() const = 0; - virtual StringName get_name() = 0; + virtual MemberType get_member_type() const = 0; + + virtual StringName get_name() const = 0; virtual bool is_static() = 0; diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index f45644f1eb..b987b3aebd 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -617,7 +617,9 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { String dst_path = p_path.replace_first("res://", "assets/"); store_in_apk(ed, dst_path, p_data, _should_compress_asset(p_path, p_data) ? Z_DEFLATED : 0); - ed->ep->step("File: " + p_path, 3 + p_file * 100 / p_total); + if (ed->ep->step("File: " + p_path, 3 + p_file * 100 / p_total)) { + return ERR_SKIP; + } return OK; } @@ -1255,7 +1257,9 @@ public: } //export_temp - ep.step("Exporting APK", 0); + if (ep.step("Exporting APK", 0)) { + return ERR_SKIP; + } const bool use_remote = (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) || (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT); const bool use_reverse = devices[p_device].api_level >= 21; @@ -1278,7 +1282,9 @@ public: String package_name = p_preset->get("package/unique_name"); if (remove_prev) { - ep.step("Uninstalling...", 1); + if (ep.step("Uninstalling...", 1)) { + return ERR_SKIP; + } print_line("Uninstalling previous version: " + devices[p_device].name); @@ -1291,7 +1297,9 @@ public: } print_line("Installing to device (please wait...): " + devices[p_device].name); - ep.step("Installing to device (please wait...)", 2); + if (ep.step("Installing to device (please wait...)", 2)) { + return ERR_SKIP; + } args.clear(); args.push_back("-s"); @@ -1357,7 +1365,9 @@ public: } } - ep.step("Running on Device...", 3); + if (ep.step("Running on Device...", 3)) { + return ERR_SKIP; + } args.clear(); args.push_back("-s"); args.push_back(devices[p_device].id); @@ -1763,7 +1773,7 @@ public: String src_apk; - EditorProgress ep("export", "Exporting for Android", 105); + EditorProgress ep("export", "Exporting for Android", 105, true); if (bool(p_preset->get("custom_package/use_custom_build"))) { //custom build //re-generate build.gradle and AndroidManifest.xml @@ -1855,7 +1865,9 @@ public: FileAccess *src_f = NULL; zlib_filefunc_def io = zipio_create_io_from_file(&src_f); - ep.step("Creating APK", 0); + if (ep.step("Creating APK", 0)) { + return ERR_SKIP; + } unzFile pkg = unzOpen2(src_apk.utf8().get_data(), &io); if (!pkg) { @@ -1997,7 +2009,9 @@ public: ret = unzGoToNextFile(pkg); } - ep.step("Adding Files...", 1); + if (ep.step("Adding Files...", 1)) { + return ERR_SKIP; + } Error err = OK; Vector<String> cl = cmdline.strip_edges().split(" "); for (int i = 0; i < cl.size(); i++) { @@ -2135,14 +2149,18 @@ public: user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user"); } - ep.step("Signing debug APK...", 103); + if (ep.step("Signing debug APK...", 103)) { + return ERR_SKIP; + } } else { keystore = release_keystore; password = release_password; user = release_username; - ep.step("Signing release APK...", 103); + if (ep.step("Signing release APK...", 103)) { + return ERR_SKIP; + } } if (!FileAccess::exists(keystore)) { @@ -2174,7 +2192,9 @@ public: return ERR_CANT_CREATE; } - ep.step("Verifying APK...", 104); + if (ep.step("Verifying APK...", 104)) { + return ERR_SKIP; + } args.clear(); args.push_back("-verify"); @@ -2194,7 +2214,9 @@ public: static const int ZIP_ALIGNMENT = 4; - ep.step("Aligning APK...", 105); + if (ep.step("Aligning APK...", 105)) { + return ERR_SKIP; + } unzFile tmp_unaligned = unzOpen2(unaligned_path.utf8().get_data(), &io); if (!tmp_unaligned) { diff --git a/platform/android/java/AndroidManifest.xml b/platform/android/java/AndroidManifest.xml index 613d24fbd2..9997950137 100644 --- a/platform/android/java/AndroidManifest.xml +++ b/platform/android/java/AndroidManifest.xml @@ -22,7 +22,7 @@ <!--Anything in this line after the icon will be erased when doing custom build. If you want to add tags manually, do before it.--> <application android:label="@string/godot_project_name_string" android:allowBackup="false" tools:ignore="GoogleAppIndexingWarning" android:icon="@drawable/icon"> -<!--The following values are replaced when Godot exports, modifying them here has no effect. Do theses changes in the--> +<!--The following values are replaced when Godot exports, modifying them here has no effect. Do these changes in the--> <!--export preset. Adding new ones is fine.--> <activity android:name="org.godotengine.godot.Godot" diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h index 3a03294b08..f99935bf7c 100644 --- a/platform/android/java_godot_lib_jni.h +++ b/platform/android/java_godot_lib_jni.h @@ -35,7 +35,7 @@ #include <jni.h> // These functions can be called from within JAVA and are the means by which our JAVA implementation calls back into our C++ code. -// See java/src/org/godotengine/godot/GodotLib.java for the JAVA side of this (yes thats why we have the long names) +// See java/src/org/godotengine/godot/GodotLib.java for the JAVA side of this (yes that's why we have the long names) extern "C" { JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jobject p_asset_manager, jboolean p_use_apk_expansion); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env); diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index e1083aeefc..ba405ab7ae 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -819,7 +819,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p String dest_dir = p_path.get_base_dir() + "/"; String binary_name = p_path.get_file().get_basename(); - EditorProgress ep("export", "Exporting for iOS", 5); + EditorProgress ep("export", "Exporting for iOS", 5, true); String team_id = p_preset->get("application/app_store_team_id"); ERR_EXPLAIN("App Store Team ID not specified - cannot configure the project."); @@ -868,14 +868,18 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p memdelete(da); } - ep.step("Making .pck", 0); + if (ep.step("Making .pck", 0)) { + return ERR_SKIP; + } String pack_path = dest_dir + binary_name + ".pck"; Vector<SharedObject> libraries; Error err = save_pack(p_preset, pack_path, &libraries); if (err) return err; - ep.step("Extracting and configuring Xcode project", 1); + if (ep.step("Extracting and configuring Xcode project", 1)) { + return ERR_SKIP; + } String library_to_use = "libgodot.iphone." + String(p_debug ? "debug" : "release") + ".fat.a"; @@ -1053,7 +1057,9 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p memdelete(f); #ifdef OSX_ENABLED - ep.step("Code-signing dylibs", 2); + if (ep.step("Code-signing dylibs", 2)) { + return ERR_SKIP; + } DirAccess *dylibs_dir = DirAccess::open(dest_dir + binary_name + "/dylibs"); ERR_FAIL_COND_V(!dylibs_dir, ERR_CANT_OPEN); CodesignData codesign_data(p_preset, p_debug); @@ -1061,7 +1067,9 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p memdelete(dylibs_dir); ERR_FAIL_COND_V(err, err); - ep.step("Making .xcarchive", 3); + if (ep.step("Making .xcarchive", 3)) { + return ERR_SKIP; + } String archive_path = p_path.get_basename() + ".xcarchive"; List<String> archive_args; archive_args.push_back("-project"); @@ -1080,7 +1088,9 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p err = OS::get_singleton()->execute("xcodebuild", archive_args, true); ERR_FAIL_COND_V(err, err); - ep.step("Making .ipa", 4); + if (ep.step("Making .ipa", 4)) { + return ERR_SKIP; + } List<String> export_args; export_args.push_back("-exportArchive"); export_args.push_back("-archivePath"); diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index d0e39d1638..9dabbb12fc 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -409,7 +409,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p String src_pkg_name; - EditorProgress ep("export", "Exporting for OSX", 3); + EditorProgress ep("export", "Exporting for OSX", 3, true); if (p_debug) src_pkg_name = p_preset->get("custom_package/debug"); @@ -432,7 +432,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p FileAccess *src_f = NULL; zlib_filefunc_def io = zipio_create_io_from_file(&src_f); - ep.step("Creating app", 0); + if (ep.step("Creating app", 0)) { + return ERR_SKIP; + } unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io); if (!src_pkg_zip) { @@ -626,7 +628,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } if (err == OK) { - ep.step("Making PKG", 1); + if (ep.step("Making PKG", 1)) { + return ERR_SKIP; + } if (export_format == "dmg") { String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck"; @@ -648,7 +652,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } if (err == OK && identity != "") { - ep.step("Code signing bundle", 2); + if (ep.step("Code signing bundle", 2)) { + return ERR_SKIP; + } // the order in which we code sign is important, this is a bit of a shame or we could do this in our loop that extracts the files from our ZIP @@ -673,7 +679,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p // and finally create a DMG if (err == OK) { - ep.step("Making DMG", 3); + if (ep.step("Making DMG", 3)) { + return ERR_SKIP; + } err = _create_dmg(p_path, pkg_name, tmp_app_path_name); } diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp index a0ab398f89..cdcad33f6d 100644 --- a/platform/uwp/export/export.cpp +++ b/platform/uwp/export/export.cpp @@ -187,7 +187,7 @@ class AppxPackager { public: void set_progress_task(String p_task) { progress_task = p_task; } void init(FileAccess *p_fa); - void add_file(String p_file_name, const uint8_t *p_buffer, size_t p_len, int p_file_no, int p_total_files, bool p_compress = false); + Error add_file(String p_file_name, const uint8_t *p_buffer, size_t p_len, int p_file_no, int p_total_files, bool p_compress = false); void finish(); AppxPackager(); @@ -468,10 +468,12 @@ void AppxPackager::init(FileAccess *p_fa) { tmp_content_types_file_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpcontenttypes.xml"); } -void AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t p_len, int p_file_no, int p_total_files, bool p_compress) { +Error AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t p_len, int p_file_no, int p_total_files, bool p_compress) { if (p_file_no >= 1 && p_total_files >= 1) { - EditorNode::progress_task_step(progress_task, "File: " + p_file_name, (p_file_no * 100) / p_total_files); + if (EditorNode::progress_task_step(progress_task, "File: " + p_file_name, (p_file_no * 100) / p_total_files)) { + return ERR_SKIP; + } } FileMeta meta; @@ -584,6 +586,8 @@ void AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t package->store_buffer(file_buffer.ptr(), file_buffer.size()); file_metadata.push_back(meta); + + return OK; } void AppxPackager::finish() { @@ -1008,9 +1012,7 @@ class EditorExportPlatformUWP : public EditorExportPlatform { AppxPackager *packager = (AppxPackager *)p_userdata; String dst_path = p_path.replace_first("res://", "game/"); - packager->add_file(dst_path, p_data.ptr(), p_data.size(), p_file, p_total, _should_compress_asset(p_path, p_data)); - - return OK; + return packager->add_file(dst_path, p_data.ptr(), p_data.size(), p_file, p_total, _should_compress_asset(p_path, p_data)); } public: @@ -1230,7 +1232,7 @@ public: String src_appx; - EditorProgress ep("export", "Exporting for Windows Universal", 7); + EditorProgress ep("export", "Exporting for Windows Universal", 7, true); if (p_debug) src_appx = p_preset->get("custom_template/debug"); @@ -1280,7 +1282,9 @@ public: FileAccess *src_f = NULL; zlib_filefunc_def io = zipio_create_io_from_file(&src_f); - ep.step("Creating package...", 0); + if (ep.step("Creating package...", 0)) { + return ERR_SKIP; + } unzFile pkg = unzOpen2(src_appx.utf8().get_data(), &io); @@ -1292,7 +1296,9 @@ public: int ret = unzGoToFirstFile(pkg); - ep.step("Copying template files...", 1); + if (ep.step("Copying template files...", 1)) { + return ERR_SKIP; + } EditorNode::progress_add_task("template_files", "Template files", 100); packager.set_progress_task("template_files"); @@ -1341,14 +1347,19 @@ public: print_line("ADDING: " + path); - packager.add_file(path, data.ptr(), data.size(), template_file_no++, template_files_amount, _should_compress_asset(path, data)); + err = packager.add_file(path, data.ptr(), data.size(), template_file_no++, template_files_amount, _should_compress_asset(path, data)); + if (err != OK) { + return err; + } ret = unzGoToNextFile(pkg); } EditorNode::progress_end_task("template_files"); - ep.step("Creating command line...", 2); + if (ep.step("Creating command line...", 2)) { + return ERR_SKIP; + } Vector<String> cl = ((String)p_preset->get("command_line/extra_args")).strip_edges().split(" "); for (int i = 0; i < cl.size(); i++) { @@ -1382,9 +1393,14 @@ public: print_line(itos(i) + " param: " + cl[i]); } - packager.add_file("__cl__.cl", clf.ptr(), clf.size(), -1, -1, false); + err = packager.add_file("__cl__.cl", clf.ptr(), clf.size(), -1, -1, false); + if (err != OK) { + return err; + } - ep.step("Adding project files...", 3); + if (ep.step("Adding project files...", 3)) { + return ERR_SKIP; + } EditorNode::progress_add_task("project_files", "Project Files", 100); packager.set_progress_task("project_files"); @@ -1393,7 +1409,9 @@ public: EditorNode::progress_end_task("project_files"); - ep.step("Closing package...", 7); + if (ep.step("Closing package...", 7)) { + return ERR_SKIP; + } unzClose(pkg); diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 0b61770d87..c386fed367 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -705,7 +705,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } } } else if (mouse_mode != MOUSE_MODE_CAPTURED) { - // for reasons unknown to mankind, wheel comes in screen cordinates + // for reasons unknown to mankind, wheel comes in screen coordinates POINT coords; coords.x = mb->get_position().x; coords.y = mb->get_position().y; diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 721b52edaa..ff27e0a29a 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -978,7 +978,7 @@ void CPUParticles2D::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { if (!redraw) - return; // dont add to render list + return; // don't add to render list RID texrid; if (texture.is_valid()) { diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index b321bcf3ce..3dc0f46676 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -491,7 +491,7 @@ void TileMap::update_dirty_quadrants() { shape_idx++; #ifdef DEBUG_ENABLED } else { - print_error("The TileSet asigned to the TileMap " + get_name() + " has an invalid convex shape."); + print_error("The TileSet assigned to the TileMap " + get_name() + " has an invalid convex shape."); #endif } } diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index 15c089ec10..e192e040f2 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -162,7 +162,7 @@ void Skeleton::_update_process_order() { //now check process order int pass_count = 0; while (pass_count < len * len) { - //using bubblesort because of simplicity, it wont run every frame though. + //using bubblesort because of simplicity, it won't run every frame though. //bublesort worst case is O(n^2), and this may be an infinite loop if cyclic bool swapped = false; for (int i = 0; i < len; i++) { diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index ead3516116..a5955d57f7 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -1200,7 +1200,7 @@ void AnimationPlayer::play(const StringName &p_name, float p_custom_blend, float // Animation reset BUT played backwards, set position to the end c.current.pos = c.current.from->animation->get_length(); } else if (!p_from_end && c.current.pos == c.current.from->animation->get_length()) { - // Animation resumed but already ended, set position to the beggining + // Animation resumed but already ended, set position to the beginning c.current.pos = 0; } } diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp index 4da3e6ee28..06d6806f03 100644 --- a/scene/animation/skeleton_ik.cpp +++ b/scene/animation/skeleton_ik.cpp @@ -37,20 +37,20 @@ #ifndef _3D_DISABLED FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::find_child(const BoneId p_bone_id) { - for (int i = childs.size() - 1; 0 <= i; --i) { - if (p_bone_id == childs[i].bone) { - return &childs.write[i]; + for (int i = children.size() - 1; 0 <= i; --i) { + if (p_bone_id == children[i].bone) { + return &children.write[i]; } } return NULL; } FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::add_child(const BoneId p_bone_id) { - const int infant_child_id = childs.size(); - childs.resize(infant_child_id + 1); - childs.write[infant_child_id].bone = p_bone_id; - childs.write[infant_child_id].parent_item = this; - return &childs.write[infant_child_id]; + const int infant_child_id = children.size(); + children.resize(infant_child_id + 1); + children.write[infant_child_id].bone = p_bone_id; + children.write[infant_child_id].parent_item = this; + return &children.write[infant_child_id]; } /// Build a chain that starts from the root to tip @@ -144,8 +144,8 @@ void FabrikInverseKinematic::update_chain(const Skeleton *p_sk, ChainItem *p_cha p_chain_item->initial_transform = p_sk->get_bone_global_pose(p_chain_item->bone); p_chain_item->current_pos = p_chain_item->initial_transform.origin; - for (int i = p_chain_item->childs.size() - 1; 0 <= i; --i) { - update_chain(p_sk, &p_chain_item->childs.write[i]); + for (int i = p_chain_item->children.size() - 1; 0 <= i; --i) { + update_chain(p_sk, &p_chain_item->children.write[i]); } } @@ -210,9 +210,9 @@ void FabrikInverseKinematic::solve_simple_forwards(Chain &r_chain, bool p_solve_ while (sub_chain_root) { // Reach the tip sub_chain_root->current_pos = origin; - if (!sub_chain_root->childs.empty()) { + if (!sub_chain_root->children.empty()) { - ChainItem &child(sub_chain_root->childs.write[0]); + ChainItem &child(sub_chain_root->children.write[0]); // Is not tip // So calculate next origin location @@ -302,10 +302,10 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove Transform new_bone_pose(ci->initial_transform); new_bone_pose.origin = ci->current_pos; - if (!ci->childs.empty()) { + if (!ci->children.empty()) { /// Rotate basis - const Vector3 initial_ori((ci->childs[0].initial_transform.origin - ci->initial_transform.origin).normalized()); + const Vector3 initial_ori((ci->children[0].initial_transform.origin - ci->initial_transform.origin).normalized()); const Vector3 rot_axis(initial_ori.cross(ci->current_ori).normalized()); if (rot_axis[0] != 0 && rot_axis[1] != 0 && rot_axis[2] != 0) { @@ -322,8 +322,8 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove p_task->skeleton->set_bone_global_pose(ci->bone, new_bone_pose); - if (!ci->childs.empty()) - ci = &ci->childs.write[0]; + if (!ci->children.empty()) + ci = &ci->children.write[0]; else ci = NULL; } diff --git a/scene/animation/skeleton_ik.h b/scene/animation/skeleton_ik.h index 228184a2df..5d48b7be33 100644 --- a/scene/animation/skeleton_ik.h +++ b/scene/animation/skeleton_ik.h @@ -49,7 +49,7 @@ class FabrikInverseKinematic { struct ChainItem { - Vector<ChainItem> childs; + Vector<ChainItem> children; ChainItem *parent_item; // Bone info diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp index 7f1ca58d58..1f9bfb9936 100644 --- a/scene/gui/container.cpp +++ b/scene/gui/container.cpp @@ -177,7 +177,7 @@ String Container::get_configuration_warning() const { if (warning != String()) { warning += "\n"; } - warning += TTR("Container by itself serves no purpose unless a script configures it's children placement behavior.\nIf you dont't intend to add a script, then please use a plain 'Control' node instead."); + warning += TTR("Container by itself serves no purpose unless a script configures it's children placement behavior.\nIf you don't intend to add a script, then please use a plain 'Control' node instead."); } return warning; } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 71e84e974f..8acd28a2f4 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -3603,7 +3603,7 @@ void TextEdit::_insert_text(int p_line, int p_char, const String &p_text, int *r op.chain_forward = false; op.chain_backward = false; - //see if it shold just be set as current op + //see if it should just be set as current op if (current_op.type != op.type) { op.prev_version = get_version(); _push_current_op(); @@ -3654,7 +3654,7 @@ void TextEdit::_remove_text(int p_from_line, int p_from_column, int p_to_line, i op.chain_forward = false; op.chain_backward = false; - //see if it shold just be set as current op + //see if it should just be set as current op if (current_op.type != op.type) { op.prev_version = get_version(); _push_current_op(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 47f5b152f0..8bfb50c68d 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -523,6 +523,7 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeCubeMapUniform>(); ClassDB::register_class<VisualShaderNodeIf>(); ClassDB::register_class<VisualShaderNodeSwitch>(); + ClassDB::register_class<VisualShaderNodeFresnel>(); ClassDB::register_class<ShaderMaterial>(); ClassDB::register_virtual_class<CanvasItem>(); diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 3ba43006a3..8c0497e91a 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -115,7 +115,7 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) { //ensure vertices are the expected amount ERR_FAIL_COND(vtx.weights.size() != vtx.bones.size()); if (vtx.weights.size() < expected_vertices) { - //less than requred, fill + //less than required, fill for (int i = vtx.weights.size(); i < expected_vertices; i++) { vtx.weights.push_back(0); vtx.bones.push_back(0); diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index 9b8037965b..a44471a365 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -1192,7 +1192,7 @@ String VisualShaderNodeScalarFunc::get_output_port_name(int p_port) const { String VisualShaderNodeScalarFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - static const char *scalar_func_id[FUNC_TRUNC + 1] = { + static const char *scalar_func_id[FUNC_ONEMINUS + 1] = { "sin($)", "cos($)", "tan($)", @@ -1223,7 +1223,8 @@ String VisualShaderNodeScalarFunc::generate_code(Shader::Mode p_mode, VisualShad "radians($)", "1.0/($)", "roundEven($)", - "trunc($)" + "trunc($)", + "1.0-$" }; return "\t" + p_output_vars[0] + " = " + String(scalar_func_id[func]).replace("$", p_input_vars[0]) + ";\n"; @@ -1251,7 +1252,7 @@ void VisualShaderNodeScalarFunc::_bind_methods() { ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeScalarFunc::set_function); ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeScalarFunc::get_function); - ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Frac,Saturate,Negate,ACosH,ASinH,ATanH,Degrees,Exp2,InverseSqrt,Log2,Radians,Reciprocal,RoundEven,Trunc"), "set_function", "get_function"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Frac,Saturate,Negate,ACosH,ASinH,ATanH,Degrees,Exp2,InverseSqrt,Log2,Radians,Reciprocal,RoundEven,Trunc,OneMinus"), "set_function", "get_function"); BIND_ENUM_CONSTANT(FUNC_SIN); BIND_ENUM_CONSTANT(FUNC_COS); @@ -1284,6 +1285,7 @@ void VisualShaderNodeScalarFunc::_bind_methods() { BIND_ENUM_CONSTANT(FUNC_RECIPROCAL); BIND_ENUM_CONSTANT(FUNC_ROUNDEVEN); BIND_ENUM_CONSTANT(FUNC_TRUNC); + BIND_ENUM_CONSTANT(FUNC_ONEMINUS); } VisualShaderNodeScalarFunc::VisualShaderNodeScalarFunc() { @@ -1319,7 +1321,7 @@ String VisualShaderNodeVectorFunc::get_output_port_name(int p_port) const { String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - static const char *vec_func_id[FUNC_TRUNC + 1] = { + static const char *vec_func_id[FUNC_ONEMINUS + 1] = { "normalize($)", "max(min($,vec3(1.0)),vec3(0.0))", "-($)", @@ -1353,7 +1355,8 @@ String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShad "sqrt($)", "tan($)", "tanh($)", - "trunc($)" + "trunc($)", + "vec3(1.0, 1.0, 1.0)-$" }; String code; @@ -1405,7 +1408,7 @@ void VisualShaderNodeVectorFunc::_bind_methods() { ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeVectorFunc::set_function); ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeVectorFunc::get_function); - ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,RGB2HSV,HSV2RGB,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Frac,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc"), "set_function", "get_function"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,RGB2HSV,HSV2RGB,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Frac,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc,OneMinus"), "set_function", "get_function"); BIND_ENUM_CONSTANT(FUNC_NORMALIZE); BIND_ENUM_CONSTANT(FUNC_SATURATE); @@ -1441,6 +1444,7 @@ void VisualShaderNodeVectorFunc::_bind_methods() { BIND_ENUM_CONSTANT(FUNC_TAN); BIND_ENUM_CONSTANT(FUNC_TANH); BIND_ENUM_CONSTANT(FUNC_TRUNC); + BIND_ENUM_CONSTANT(FUNC_ONEMINUS); } VisualShaderNodeVectorFunc::VisualShaderNodeVectorFunc() { @@ -3085,3 +3089,66 @@ VisualShaderNodeSwitch::VisualShaderNodeSwitch() { set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); } + +////////////// Fresnel + +String VisualShaderNodeFresnel::get_caption() const { + return "Fresnel"; +} + +int VisualShaderNodeFresnel::get_input_port_count() const { + return 4; +} + +VisualShaderNodeFresnel::PortType VisualShaderNodeFresnel::get_input_port_type(int p_port) const { + switch (p_port) { + case 0: + return PORT_TYPE_VECTOR; + case 1: + return PORT_TYPE_VECTOR; + case 2: + return PORT_TYPE_BOOLEAN; + case 3: + return PORT_TYPE_SCALAR; + default: + return PORT_TYPE_VECTOR; + } +} + +String VisualShaderNodeFresnel::get_input_port_name(int p_port) const { + switch (p_port) { + case 0: + return "normal"; + case 1: + return "view"; + case 2: + return "invert"; + case 3: + return "power"; + default: + return ""; + } +} + +int VisualShaderNodeFresnel::get_output_port_count() const { + return 1; +} + +VisualShaderNodeFresnel::PortType VisualShaderNodeFresnel::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeFresnel::get_output_port_name(int p_port) const { + return "result"; +} + +String VisualShaderNodeFresnel::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + return "\t" + p_output_vars[0] + " = " + p_input_vars[2] + " ? (pow(clamp(dot(" + p_input_vars[0] + ", " + p_input_vars[1] + "), 0.0, 1.0), " + p_input_vars[3] + ")) : (pow(1.0 - clamp(dot(" + p_input_vars[0] + ", " + p_input_vars[1] + "), 0.0, 1.0), " + p_input_vars[3] + "));"; +} + +VisualShaderNodeFresnel::VisualShaderNodeFresnel() { + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(2, false); + set_input_port_default_value(3, 1.0); +} diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 90c479bd48..852248b9b4 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -562,7 +562,8 @@ public: FUNC_RADIANS, FUNC_RECIPROCAL, FUNC_ROUNDEVEN, - FUNC_TRUNC + FUNC_TRUNC, + FUNC_ONEMINUS }; protected: @@ -635,7 +636,8 @@ public: FUNC_SQRT, FUNC_TAN, FUNC_TANH, - FUNC_TRUNC + FUNC_TRUNC, + FUNC_ONEMINUS }; protected: @@ -1484,4 +1486,26 @@ public: VisualShaderNodeSwitch(); }; +/////////////////////////////////////// +/// FRESNEL +/////////////////////////////////////// + +class VisualShaderNodeFresnel : public VisualShaderNode { + GDCLASS(VisualShaderNodeFresnel, VisualShaderNode) +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; + + VisualShaderNodeFresnel(); +}; + #endif // VISUAL_SHADER_NODES_H diff --git a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp index 46d92336f3..05cba416be 100644 --- a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp +++ b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp @@ -112,7 +112,7 @@ void AudioEffectSpectrumAnalyzerInstance::process(const AudioFrame *p_src_frames } //determine time of capture - double remainer_sec = (temporal_fft_pos / mix_rate); //substract remainder from mix time + double remainer_sec = (temporal_fft_pos / mix_rate); //subtract remainder from mix time last_fft_time = time - uint64_t(remainer_sec * 1000000.0); } diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index f5acadd71c..e2b1bb9da4 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -795,7 +795,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized(); float owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx); - cbk.valid_depth = MAX(owc_margin, p_margin); //user specified, but never less than actual margin or it wont work + cbk.valid_depth = MAX(owc_margin, p_margin); //user specified, but never less than actual margin or it won't work cbk.invalid_by_dir = 0; if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 33714a79b2..cb3a744730 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -616,7 +616,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { else tk.type = TK_INT_CONSTANT; - tk.constant = str.to_double(); //wont work with hex + tk.constant = str.to_double(); //won't work with hex tk.line = tk_line; return tk; |