summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml16
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp5
-rw-r--r--modules/gdscript/gdscript_editor.cpp8
-rw-r--r--modules/gdscript/gdscript_parser.cpp53
-rw-r--r--modules/gltf/gltf_document.cpp368
-rw-r--r--modules/gltf/gltf_document.h3
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs3
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs60
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs22
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs16
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs50
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs7
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/VerbosityLevelId.cs11
15 files changed, 485 insertions, 147 deletions
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index e05b17168d..923b2fe30d 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -304,7 +304,7 @@
<return type="void" />
<param index="0" name="names" type="String" />
<description>
- Export an [int] or [String] property as an enumerated list of options. If the property is an [int], then the index of the value is stored, in the same order the values are provided. You can add specific identifiers for allowed values using a colon. If the property is a [String], then the value is stored.
+ Export an [int] or [String] property as an enumerated list of options. If the property is an [int], then the index of the value is stored, in the same order the values are provided. You can add explicit values using a colon. If the property is a [String], then the value is stored.
See also [constant PROPERTY_HINT_ENUM].
[codeblock]
@export_enum("Warrior", "Magician", "Thief") var character_class: int
@@ -357,6 +357,20 @@
[codeblock]
@export_flags("Fire", "Water", "Earth", "Wind") var spell_elements = 0
[/codeblock]
+ You can add explicit values using a colon:
+ [codeblock]
+ @export_flags("Self:4", "Allies:8", "Foes:16") var spell_targets = 0
+ [/codeblock]
+ You can also combine several flags:
+ [codeblock]
+ @export_flags("Self:4", "Allies:8", "Self and Allies:12", "Foes:16")
+ var spell_targets = 0
+ [/codeblock]
+ [b]Note:[/b] A flag value must be at least [code]1[/code] and at most [code]2 ** 32 - 1[/code].
+ [b]Note:[/b] Unlike [annotation @export_enum], the previous explicit value is not taken into account. In the following example, A is 16, B is 2, C is 4.
+ [codeblock]
+ @export_flags("A:16", "B", "C") var x
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_flags_2d_navigation">
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index cd1dcf9a78..602d07d9a7 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -1576,11 +1576,8 @@ void GDScriptAnalyzer::resolve_function_body(GDScriptParser::FunctionNode *p_fun
resolve_suite(p_function->body);
- GDScriptParser::DataType return_type = p_function->body->get_datatype();
-
- if (!p_function->get_datatype().is_hard_type() && return_type.is_set()) {
+ if (!p_function->get_datatype().is_hard_type() && p_function->body->get_datatype().is_set()) {
// Use the suite inferred type if return isn't explicitly set.
- return_type.type_source = GDScriptParser::DataType::INFERRED;
p_function->set_datatype(p_function->body->get_datatype());
} else if (p_function->get_datatype().is_hard_type() && (p_function->get_datatype().kind != GDScriptParser::DataType::BUILTIN || p_function->get_datatype().builtin_type != Variant::NIL)) {
if (!p_function->body->has_return && (p_is_lambda || p_function->identifier->name != GDScriptLanguage::get_singleton()->strings._init)) {
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 8cfd48b52b..3543c0a79f 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -3491,6 +3491,14 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
break;
}
+ if (context.current_class) {
+ if (context.type != GDScriptParser::COMPLETION_SUPER_METHOD) {
+ base.type = context.current_class->get_datatype();
+ } else {
+ base.type = context.current_class->base_type;
+ }
+ }
+
if (_lookup_symbol_from_base(base.type, p_symbol, is_function, r_result) == OK) {
return OK;
}
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 0a1a64cb59..c6e4222213 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -3637,15 +3637,6 @@ template <PropertyHint t_hint, Variant::Type t_type>
bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node *p_node) {
ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name));
- {
- const int max_flags = 32;
-
- if (t_hint == PropertyHint::PROPERTY_HINT_FLAGS && p_annotation->resolved_arguments.size() > max_flags) {
- push_error(vformat(R"(The argument count limit for "@export_flags" is exceeded (%d/%d).)", p_annotation->resolved_arguments.size(), max_flags), p_annotation);
- return false;
- }
- }
-
VariableNode *variable = static_cast<VariableNode *>(p_node);
if (variable->exported) {
push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation);
@@ -3659,14 +3650,50 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
String hint_string;
for (int i = 0; i < p_annotation->resolved_arguments.size(); i++) {
- if (p_annotation->name != SNAME("@export_placeholder") && String(p_annotation->resolved_arguments[i]).contains(",")) {
- push_error(vformat(R"(Argument %d of annotation "%s" contains a comma. Use separate arguments instead.)", i + 1, p_annotation->name), p_annotation->arguments[i]);
- return false;
+ String arg_string = String(p_annotation->resolved_arguments[i]);
+
+ if (p_annotation->name != SNAME("@export_placeholder")) {
+ if (arg_string.is_empty()) {
+ push_error(vformat(R"(Argument %d of annotation "%s" is empty.)", i + 1, p_annotation->name), p_annotation->arguments[i]);
+ return false;
+ }
+ if (arg_string.contains(",")) {
+ push_error(vformat(R"(Argument %d of annotation "%s" contains a comma. Use separate arguments instead.)", i + 1, p_annotation->name), p_annotation->arguments[i]);
+ return false;
+ }
+ }
+
+ if (p_annotation->name == SNAME("@export_flags")) {
+ const int64_t max_flags = 32;
+ Vector<String> t = arg_string.split(":", true, 1);
+ if (t[0].is_empty()) {
+ push_error(vformat(R"(Invalid argument %d of annotation "@export_flags": Expected flag name.)", i + 1), p_annotation->arguments[i]);
+ return false;
+ }
+ if (t.size() == 2) {
+ if (t[1].is_empty()) {
+ push_error(vformat(R"(Invalid argument %d of annotation "@export_flags": Expected flag value.)", i + 1), p_annotation->arguments[i]);
+ return false;
+ }
+ if (!t[1].is_valid_int()) {
+ push_error(vformat(R"(Invalid argument %d of annotation "@export_flags": The flag value must be a valid integer.)", i + 1), p_annotation->arguments[i]);
+ return false;
+ }
+ int64_t value = t[1].to_int();
+ if (value < 1 || value >= (1LL << max_flags)) {
+ push_error(vformat(R"(Invalid argument %d of annotation "@export_flags": The flag value must be at least 1 and at most 2 ** %d - 1.)", i + 1, max_flags), p_annotation->arguments[i]);
+ return false;
+ }
+ } else if (i >= max_flags) {
+ push_error(vformat(R"(Invalid argument %d of annotation "@export_flags": Starting from argument %d, the flag value must be specified explicitly.)", i + 1, max_flags + 1), p_annotation->arguments[i]);
+ return false;
+ }
}
+
if (i > 0) {
hint_string += ",";
}
- hint_string += String(p_annotation->resolved_arguments[i]);
+ hint_string += arg_string;
}
variable->export_info.hint_string = hint_string;
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index bd3ee1881f..028028a103 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -4894,13 +4894,11 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> p_state) {
return OK;
}
for (int32_t player_i = 0; player_i < p_state->animation_players.size(); player_i++) {
- List<StringName> animation_names;
AnimationPlayer *animation_player = p_state->animation_players[player_i];
- animation_player->get_animation_list(&animation_names);
- if (animation_names.size()) {
- for (int animation_name_i = 0; animation_name_i < animation_names.size(); animation_name_i++) {
- _convert_animation(p_state, animation_player, animation_names[animation_name_i]);
- }
+ List<StringName> animations;
+ animation_player->get_animation_list(&animations);
+ for (StringName animation_name : animations) {
+ _convert_animation(p_state, animation_player, animation_name);
}
}
Array animations;
@@ -6028,7 +6026,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_
Node *root = p_animation_player->get_parent();
ERR_FAIL_COND(root == nullptr);
HashMap<GLTFNodeIndex, Node *>::Iterator node_element = p_state->scene_nodes.find(node_index);
- ERR_CONTINUE_MSG(!node_element, vformat("Unable to find node %d for animation", node_index));
+ ERR_CONTINUE_MSG(!node_element, vformat("Unable to find node %d for animation.", node_index));
node_path = root->get_path_to(node_element->value);
HashMap<GLTFNodeIndex, ImporterMeshInstance3D *>::Iterator mesh_instance_element = p_state->scene_mesh_instances.find(node_index);
if (mesh_instance_element) {
@@ -6450,58 +6448,179 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> p_sta
for (int32_t key_i = 0; key_i < key_count; key_i++) {
times.write[key_i] = p_animation->track_get_key_time(p_track_i, key_i);
}
+ double anim_end = p_animation->get_length();
if (track_type == Animation::TYPE_SCALE_3D) {
- p_track.scale_track.times = times;
- p_track.scale_track.interpolation = gltf_interpolation;
- p_track.scale_track.values.resize(key_count);
- for (int32_t key_i = 0; key_i < key_count; key_i++) {
- Vector3 scale;
- Error err = p_animation->scale_track_get_key(p_track_i, key_i, &scale);
- ERR_CONTINUE(err != OK);
- p_track.scale_track.values.write[key_i] = scale;
+ if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) {
+ gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
+ p_track.scale_track.times.clear();
+ p_track.scale_track.values.clear();
+ // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies.
+ const double increment = 1.0 / BAKE_FPS;
+ double time = 0.0;
+ bool last = false;
+ while (true) {
+ Vector3 scale;
+ Error err = p_animation->scale_track_interpolate(p_track_i, time, &scale);
+ ERR_CONTINUE(err != OK);
+ p_track.scale_track.values.push_back(scale);
+ p_track.scale_track.times.push_back(time);
+ if (last) {
+ break;
+ }
+ time += increment;
+ if (time >= anim_end) {
+ last = true;
+ time = anim_end;
+ }
+ }
+ } else {
+ p_track.scale_track.times = times;
+ p_track.scale_track.interpolation = gltf_interpolation;
+ p_track.scale_track.values.resize(key_count);
+ for (int32_t key_i = 0; key_i < key_count; key_i++) {
+ Vector3 scale;
+ Error err = p_animation->scale_track_get_key(p_track_i, key_i, &scale);
+ ERR_CONTINUE(err != OK);
+ p_track.scale_track.values.write[key_i] = scale;
+ }
}
} else if (track_type == Animation::TYPE_POSITION_3D) {
- p_track.position_track.times = times;
- p_track.position_track.values.resize(key_count);
- p_track.position_track.interpolation = gltf_interpolation;
- for (int32_t key_i = 0; key_i < key_count; key_i++) {
- Vector3 position;
- Error err = p_animation->position_track_get_key(p_track_i, key_i, &position);
- ERR_CONTINUE(err != OK);
- p_track.position_track.values.write[key_i] = position;
+ if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) {
+ gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
+ p_track.position_track.times.clear();
+ p_track.position_track.values.clear();
+ // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies.
+ const double increment = 1.0 / BAKE_FPS;
+ double time = 0.0;
+ bool last = false;
+ while (true) {
+ Vector3 scale;
+ Error err = p_animation->position_track_interpolate(p_track_i, time, &scale);
+ ERR_CONTINUE(err != OK);
+ p_track.position_track.values.push_back(scale);
+ p_track.position_track.times.push_back(time);
+ if (last) {
+ break;
+ }
+ time += increment;
+ if (time >= anim_end) {
+ last = true;
+ time = anim_end;
+ }
+ }
+ } else {
+ p_track.position_track.times = times;
+ p_track.position_track.values.resize(key_count);
+ p_track.position_track.interpolation = gltf_interpolation;
+ for (int32_t key_i = 0; key_i < key_count; key_i++) {
+ Vector3 position;
+ Error err = p_animation->position_track_get_key(p_track_i, key_i, &position);
+ ERR_CONTINUE(err != OK);
+ p_track.position_track.values.write[key_i] = position;
+ }
}
} else if (track_type == Animation::TYPE_ROTATION_3D) {
- p_track.rotation_track.times = times;
- p_track.rotation_track.interpolation = gltf_interpolation;
- p_track.rotation_track.values.resize(key_count);
- for (int32_t key_i = 0; key_i < key_count; key_i++) {
- Quaternion rotation;
- Error err = p_animation->rotation_track_get_key(p_track_i, key_i, &rotation);
- ERR_CONTINUE(err != OK);
- p_track.rotation_track.values.write[key_i] = rotation;
+ if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) {
+ gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
+ p_track.rotation_track.times.clear();
+ p_track.rotation_track.values.clear();
+ // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies.
+ const double increment = 1.0 / BAKE_FPS;
+ double time = 0.0;
+ bool last = false;
+ while (true) {
+ Quaternion rotation;
+ Error err = p_animation->rotation_track_interpolate(p_track_i, time, &rotation);
+ ERR_CONTINUE(err != OK);
+ p_track.rotation_track.values.push_back(rotation);
+ p_track.rotation_track.times.push_back(time);
+ if (last) {
+ break;
+ }
+ time += increment;
+ if (time >= anim_end) {
+ last = true;
+ time = anim_end;
+ }
+ }
+ } else {
+ p_track.rotation_track.times = times;
+ p_track.rotation_track.values.resize(key_count);
+ p_track.rotation_track.interpolation = gltf_interpolation;
+ for (int32_t key_i = 0; key_i < key_count; key_i++) {
+ Quaternion rotation;
+ Error err = p_animation->rotation_track_get_key(p_track_i, key_i, &rotation);
+ ERR_CONTINUE(err != OK);
+ p_track.rotation_track.values.write[key_i] = rotation;
+ }
}
} else if (track_type == Animation::TYPE_VALUE) {
if (path.contains(":position")) {
- p_track.position_track.times = times;
p_track.position_track.interpolation = gltf_interpolation;
-
+ p_track.position_track.times = times;
p_track.position_track.values.resize(key_count);
- p_track.position_track.interpolation = gltf_interpolation;
- for (int32_t key_i = 0; key_i < key_count; key_i++) {
- Vector3 position = p_animation->track_get_key_value(p_track_i, key_i);
- p_track.position_track.values.write[key_i] = position;
+ if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) {
+ gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
+ p_track.position_track.times.clear();
+ p_track.position_track.values.clear();
+ // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies.
+ const double increment = 1.0 / BAKE_FPS;
+ double time = 0.0;
+ bool last = false;
+ while (true) {
+ Vector3 position;
+ Error err = p_animation->position_track_interpolate(p_track_i, time, &position);
+ ERR_CONTINUE(err != OK);
+ p_track.position_track.values.push_back(position);
+ p_track.position_track.times.push_back(time);
+ if (last) {
+ break;
+ }
+ time += increment;
+ if (time >= anim_end) {
+ last = true;
+ time = anim_end;
+ }
+ }
+ } else {
+ for (int32_t key_i = 0; key_i < key_count; key_i++) {
+ Vector3 position = p_animation->track_get_key_value(p_track_i, key_i);
+ p_track.position_track.values.write[key_i] = position;
+ }
}
} else if (path.contains(":rotation")) {
- p_track.rotation_track.times = times;
p_track.rotation_track.interpolation = gltf_interpolation;
-
+ p_track.rotation_track.times = times;
p_track.rotation_track.values.resize(key_count);
- p_track.rotation_track.interpolation = gltf_interpolation;
-
- for (int32_t key_i = 0; key_i < key_count; key_i++) {
- Vector3 rotation_radian = p_animation->track_get_key_value(p_track_i, key_i);
- p_track.rotation_track.values.write[key_i] = Quaternion::from_euler(rotation_radian);
+ if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) {
+ gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
+ p_track.rotation_track.times.clear();
+ p_track.rotation_track.values.clear();
+ // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies.
+ const double increment = 1.0 / BAKE_FPS;
+ double time = 0.0;
+ bool last = false;
+ while (true) {
+ Quaternion rotation;
+ Error err = p_animation->rotation_track_interpolate(p_track_i, time, &rotation);
+ ERR_CONTINUE(err != OK);
+ p_track.rotation_track.values.push_back(rotation);
+ p_track.rotation_track.times.push_back(time);
+ if (last) {
+ break;
+ }
+ time += increment;
+ if (time >= anim_end) {
+ last = true;
+ time = anim_end;
+ }
+ }
+ } else {
+ for (int32_t key_i = 0; key_i < key_count; key_i++) {
+ Vector3 rotation_radian = p_animation->track_get_key_value(p_track_i, key_i);
+ p_track.rotation_track.values.write[key_i] = Quaternion::from_euler(rotation_radian);
+ }
}
} else if (path.contains(":scale")) {
p_track.scale_track.times = times;
@@ -6510,68 +6629,115 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> p_sta
p_track.scale_track.values.resize(key_count);
p_track.scale_track.interpolation = gltf_interpolation;
- for (int32_t key_i = 0; key_i < key_count; key_i++) {
- Vector3 scale_track = p_animation->track_get_key_value(p_track_i, key_i);
- p_track.scale_track.values.write[key_i] = scale_track;
+ if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) {
+ gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
+ p_track.scale_track.times.clear();
+ p_track.scale_track.values.clear();
+ // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies.
+ const double increment = 1.0 / BAKE_FPS;
+ double time = 0.0;
+ bool last = false;
+ while (true) {
+ Vector3 scale;
+ Error err = p_animation->scale_track_interpolate(p_track_i, time, &scale);
+ ERR_CONTINUE(err != OK);
+ p_track.scale_track.values.push_back(scale);
+ p_track.scale_track.times.push_back(time);
+ if (last) {
+ break;
+ }
+ time += increment;
+ if (time >= anim_end) {
+ last = true;
+ time = anim_end;
+ }
+ }
+ } else {
+ for (int32_t key_i = 0; key_i < key_count; key_i++) {
+ Vector3 scale_track = p_animation->track_get_key_value(p_track_i, key_i);
+ p_track.scale_track.values.write[key_i] = scale_track;
+ }
}
}
} else if (track_type == Animation::TYPE_BEZIER) {
- if (path.contains("/scale")) {
- const int32_t keys = p_animation->track_get_key_time(p_track_i, key_count - 1) * BAKE_FPS;
+ const int32_t keys = anim_end * BAKE_FPS;
+ if (path.contains(":scale")) {
if (!p_track.scale_track.times.size()) {
+ p_track.scale_track.interpolation = gltf_interpolation;
Vector<real_t> new_times;
new_times.resize(keys);
for (int32_t key_i = 0; key_i < keys; key_i++) {
new_times.write[key_i] = key_i / BAKE_FPS;
}
p_track.scale_track.times = new_times;
- p_track.scale_track.interpolation = gltf_interpolation;
p_track.scale_track.values.resize(keys);
for (int32_t key_i = 0; key_i < keys; key_i++) {
p_track.scale_track.values.write[key_i] = Vector3(1.0f, 1.0f, 1.0f);
}
- p_track.scale_track.interpolation = gltf_interpolation;
- }
- for (int32_t key_i = 0; key_i < keys; key_i++) {
- Vector3 bezier_track = p_track.scale_track.values[key_i];
- if (path.contains("/scale:x")) {
- bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
- } else if (path.contains("/scale:y")) {
- bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
- } else if (path.contains("/scale:z")) {
- bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
+ for (int32_t key_i = 0; key_i < keys; key_i++) {
+ Vector3 bezier_track = p_track.scale_track.values[key_i];
+ if (path.contains(":scale:x")) {
+ bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
+ } else if (path.contains(":scale:y")) {
+ bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
+ } else if (path.contains(":scale:z")) {
+ bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
+ }
+ p_track.scale_track.values.write[key_i] = bezier_track;
}
- p_track.scale_track.values.write[key_i] = bezier_track;
}
- } else if (path.contains("/position")) {
- const int32_t keys = p_animation->track_get_key_time(p_track_i, key_count - 1) * BAKE_FPS;
+ } else if (path.contains(":position")) {
if (!p_track.position_track.times.size()) {
+ p_track.position_track.interpolation = gltf_interpolation;
Vector<real_t> new_times;
new_times.resize(keys);
for (int32_t key_i = 0; key_i < keys; key_i++) {
new_times.write[key_i] = key_i / BAKE_FPS;
}
p_track.position_track.times = new_times;
- p_track.position_track.interpolation = gltf_interpolation;
p_track.position_track.values.resize(keys);
- p_track.position_track.interpolation = gltf_interpolation;
}
for (int32_t key_i = 0; key_i < keys; key_i++) {
Vector3 bezier_track = p_track.position_track.values[key_i];
- if (path.contains("/position:x")) {
+ if (path.contains(":position:x")) {
bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
- } else if (path.contains("/position:y")) {
+ } else if (path.contains(":position:y")) {
bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
- } else if (path.contains("/position:z")) {
+ } else if (path.contains(":position:z")) {
bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
}
p_track.position_track.values.write[key_i] = bezier_track;
}
+ } else if (path.contains(":rotation")) {
+ if (!p_track.rotation_track.times.size()) {
+ p_track.rotation_track.interpolation = gltf_interpolation;
+ Vector<real_t> new_times;
+ new_times.resize(keys);
+ for (int32_t key_i = 0; key_i < keys; key_i++) {
+ new_times.write[key_i] = key_i / BAKE_FPS;
+ }
+ p_track.rotation_track.times = new_times;
+
+ p_track.rotation_track.values.resize(keys);
+ }
+ for (int32_t key_i = 0; key_i < keys; key_i++) {
+ Quaternion bezier_track = p_track.rotation_track.values[key_i];
+ if (path.contains(":rotation:x")) {
+ bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
+ } else if (path.contains(":rotation:y")) {
+ bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
+ } else if (path.contains(":rotation:z")) {
+ bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
+ } else if (path.contains(":rotation:w")) {
+ bezier_track.w = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
+ }
+ p_track.rotation_track.values.write[key_i] = bezier_track;
+ }
}
}
return p_track;
@@ -6582,16 +6748,18 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p
Ref<GLTFAnimation> gltf_animation;
gltf_animation.instantiate();
gltf_animation->set_name(_gen_unique_name(p_state, p_animation_track_name));
-
for (int32_t track_i = 0; track_i < animation->get_track_count(); track_i++) {
if (!animation->track_is_enabled(track_i)) {
continue;
}
- String orig_track_path = animation->track_get_path(track_i);
- if (String(orig_track_path).contains(":position")) {
- const Vector<String> node_suffix = String(orig_track_path).split(":position");
+ String final_track_path = animation->track_get_path(track_i);
+ Node *animation_base_node = p_animation_player->get_parent();
+ ERR_CONTINUE_MSG(!animation_base_node, "Cannot get the parent of the animation player.");
+ if (String(final_track_path).contains(":position")) {
+ const Vector<String> node_suffix = String(final_track_path).split(":position");
const NodePath path = node_suffix[0];
- const Node *node = p_animation_player->get_parent()->get_node_or_null(path);
+ const Node *node = animation_base_node->get_node_or_null(path);
+ ERR_CONTINUE_MSG(!node, "Cannot get the node from a position path.");
for (const KeyValue<GLTFNodeIndex, Node *> &position_scene_node_i : p_state->scene_nodes) {
if (position_scene_node_i.value == node) {
GLTFNodeIndex node_index = position_scene_node_i.key;
@@ -6604,10 +6772,11 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p
gltf_animation->get_tracks().insert(node_index, track);
}
}
- } else if (String(orig_track_path).contains(":rotation_degrees")) {
- const Vector<String> node_suffix = String(orig_track_path).split(":rotation_degrees");
+ } else if (String(final_track_path).contains(":rotation_degrees")) {
+ const Vector<String> node_suffix = String(final_track_path).split(":rotation_degrees");
const NodePath path = node_suffix[0];
- const Node *node = p_animation_player->get_parent()->get_node_or_null(path);
+ const Node *node = animation_base_node->get_node_or_null(path);
+ ERR_CONTINUE_MSG(!node, "Cannot get the node from a rotation degrees path.");
for (const KeyValue<GLTFNodeIndex, Node *> &rotation_degree_scene_node_i : p_state->scene_nodes) {
if (rotation_degree_scene_node_i.value == node) {
GLTFNodeIndex node_index = rotation_degree_scene_node_i.key;
@@ -6620,10 +6789,11 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p
gltf_animation->get_tracks().insert(node_index, track);
}
}
- } else if (String(orig_track_path).contains(":scale")) {
- const Vector<String> node_suffix = String(orig_track_path).split(":scale");
+ } else if (String(final_track_path).contains(":scale")) {
+ const Vector<String> node_suffix = String(final_track_path).split(":scale");
const NodePath path = node_suffix[0];
- const Node *node = p_animation_player->get_parent()->get_node_or_null(path);
+ const Node *node = animation_base_node->get_node_or_null(path);
+ ERR_CONTINUE_MSG(!node, "Cannot get the node from a scale path.");
for (const KeyValue<GLTFNodeIndex, Node *> &scale_scene_node_i : p_state->scene_nodes) {
if (scale_scene_node_i.value == node) {
GLTFNodeIndex node_index = scale_scene_node_i.key;
@@ -6636,10 +6806,11 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p
gltf_animation->get_tracks().insert(node_index, track);
}
}
- } else if (String(orig_track_path).contains(":transform")) {
- const Vector<String> node_suffix = String(orig_track_path).split(":transform");
+ } else if (String(final_track_path).contains(":transform")) {
+ const Vector<String> node_suffix = String(final_track_path).split(":transform");
const NodePath path = node_suffix[0];
- const Node *node = p_animation_player->get_parent()->get_node_or_null(path);
+ const Node *node = animation_base_node->get_node_or_null(path);
+ ERR_CONTINUE_MSG(!node, "Cannot get the node from a transform path.");
for (const KeyValue<GLTFNodeIndex, Node *> &transform_track_i : p_state->scene_nodes) {
if (transform_track_i.value == node) {
GLTFAnimation::Track track;
@@ -6647,12 +6818,16 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p
gltf_animation->get_tracks().insert(transform_track_i.key, track);
}
}
- } else if (String(orig_track_path).contains(":") && animation->track_get_type(track_i) == Animation::TYPE_BLEND_SHAPE) {
- const Vector<String> node_suffix = String(orig_track_path).split(":");
+ } else if (String(final_track_path).contains(":") && animation->track_get_type(track_i) == Animation::TYPE_BLEND_SHAPE) {
+ const Vector<String> node_suffix = String(final_track_path).split(":");
const NodePath path = node_suffix[0];
const String suffix = node_suffix[1];
- Node *node = p_animation_player->get_parent()->get_node_or_null(path);
+ Node *node = animation_base_node->get_node_or_null(path);
+ ERR_CONTINUE_MSG(!node, "Cannot get the node from a blend shape path.");
MeshInstance3D *mi = cast_to<MeshInstance3D>(node);
+ if (!mi) {
+ continue;
+ }
Ref<Mesh> mesh = mi->get_mesh();
ERR_CONTINUE(mesh.is_null());
int32_t mesh_index = -1;
@@ -6703,14 +6878,20 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p
}
tracks[mesh_index] = track;
}
- } else if (String(orig_track_path).contains(":")) {
+ } else if (String(final_track_path).contains(":")) {
//Process skeleton
- const Vector<String> node_suffix = String(orig_track_path).split(":");
+ const Vector<String> node_suffix = String(final_track_path).split(":");
const String node = node_suffix[0];
const NodePath node_path = node;
const String suffix = node_suffix[1];
- Node *godot_node = p_animation_player->get_parent()->get_node_or_null(node_path);
- Skeleton3D *skeleton = nullptr;
+ Node *godot_node = animation_base_node->get_node_or_null(node_path);
+ if (!godot_node) {
+ continue;
+ }
+ Skeleton3D *skeleton = cast_to<Skeleton3D>(animation_base_node->get_node_or_null(node));
+ if (!skeleton) {
+ continue;
+ }
GLTFSkeletonIndex skeleton_gltf_i = -1;
for (GLTFSkeletonIndex skeleton_i = 0; skeleton_i < p_state->skeletons.size(); skeleton_i++) {
if (p_state->skeletons[skeleton_i]->godot_skeleton == cast_to<Skeleton3D>(godot_node)) {
@@ -6719,7 +6900,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p
ERR_CONTINUE(!skeleton);
Ref<GLTFSkeleton> skeleton_gltf = p_state->skeletons[skeleton_gltf_i];
int32_t bone = skeleton->find_bone(suffix);
- ERR_CONTINUE(bone == -1);
+ ERR_CONTINUE_MSG(bone == -1, vformat("Cannot find the bone %s.", suffix));
if (!skeleton_gltf->godot_bone_node.has(bone)) {
continue;
}
@@ -6733,9 +6914,10 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p
gltf_animation->get_tracks()[node_i] = track;
}
}
- } else if (!String(orig_track_path).contains(":")) {
- ERR_CONTINUE(!p_animation_player->get_parent());
- Node *godot_node = p_animation_player->get_parent()->get_node_or_null(orig_track_path);
+ } else if (!String(final_track_path).contains(":")) {
+ ERR_CONTINUE(!animation_base_node);
+ Node *godot_node = animation_base_node->get_node_or_null(final_track_path);
+ ERR_CONTINUE_MSG(!godot_node, vformat("Cannot get the node from a skeleton path %s.", final_track_path));
for (const KeyValue<GLTFNodeIndex, Node *> &scene_node_i : p_state->scene_nodes) {
if (scene_node_i.value == godot_node) {
GLTFNodeIndex node_i = scene_node_i.key;
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index b8b989bf89..ae19f67390 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -364,8 +364,7 @@ public:
Ref<GLTFNode> p_gltf_node);
GLTFMeshIndex _convert_mesh_to_gltf(Ref<GLTFState> p_state,
MeshInstance3D *p_mesh_instance);
- void _convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player,
- String p_animation_track_name);
+ void _convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player, String p_animation_track_name);
Error _serialize(Ref<GLTFState> p_state, const String &p_path);
Error _parse(Ref<GLTFState> p_state, String p_path, Ref<FileAccess> p_file);
};
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs
index a4d5e1a569..1e4fd2f09a 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs
@@ -22,8 +22,7 @@ namespace GodotTools.Build
// TODO Use List once we have proper serialization
public Godot.Collections.Array CustomProperties { get; private set; } = new();
- public string LogsDirPath =>
- Path.Combine(GodotSharpDirs.BuildLogsDirs, $"{Solution.Md5Text()}_{Configuration}");
+ public string LogsDirPath => GodotSharpDirs.LogsDirPathFor(Solution, Configuration);
public override bool Equals(object? obj)
{
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
index ae0ffaf4cb..d6549c1b70 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
@@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using Godot;
using GodotTools.BuildLogger;
using GodotTools.Utils;
@@ -22,9 +23,11 @@ namespace GodotTools.Build
if (dotnetPath == null)
throw new FileNotFoundException("Cannot find the dotnet executable.");
+ var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
+
var startInfo = new ProcessStartInfo(dotnetPath);
- BuildArguments(buildInfo, startInfo.ArgumentList);
+ BuildArguments(buildInfo, startInfo.ArgumentList, editorSettings);
string launchMessage = startInfo.GetCommandLineDisplay(new StringBuilder("Running: ")).ToString();
stdOutHandler?.Invoke(launchMessage);
@@ -35,6 +38,8 @@ namespace GodotTools.Build
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
+ startInfo.EnvironmentVariables["DOTNET_CLI_UI_LANGUAGE"]
+ = ((string)editorSettings.GetSetting("interface/editor/editor_language")).Replace('_', '-');
// Needed when running from Developer Command Prompt for VS
RemovePlatformVariable(startInfo.EnvironmentVariables);
@@ -83,9 +88,11 @@ namespace GodotTools.Build
if (dotnetPath == null)
throw new FileNotFoundException("Cannot find the dotnet executable.");
+ var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
+
var startInfo = new ProcessStartInfo(dotnetPath);
- BuildPublishArguments(buildInfo, startInfo.ArgumentList);
+ BuildPublishArguments(buildInfo, startInfo.ArgumentList, editorSettings);
string launchMessage = startInfo.GetCommandLineDisplay(new StringBuilder("Running: ")).ToString();
stdOutHandler?.Invoke(launchMessage);
@@ -95,6 +102,8 @@ namespace GodotTools.Build
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
+ startInfo.EnvironmentVariables["DOTNET_CLI_UI_LANGUAGE"]
+ = ((string)editorSettings.GetSetting("interface/editor/editor_language")).Replace('_', '-');
// Needed when running from Developer Command Prompt for VS
RemovePlatformVariable(startInfo.EnvironmentVariables);
@@ -124,7 +133,8 @@ namespace GodotTools.Build
}
}
- private static void BuildArguments(BuildInfo buildInfo, Collection<string> arguments)
+ private static void BuildArguments(BuildInfo buildInfo, Collection<string> arguments,
+ EditorSettings editorSettings)
{
// `dotnet clean` / `dotnet build` commands
arguments.Add(buildInfo.OnlyClean ? "clean" : "build");
@@ -150,12 +160,14 @@ namespace GodotTools.Build
arguments.Add(buildInfo.Configuration);
// Verbosity
- arguments.Add("-v");
- arguments.Add("normal");
+ AddVerbosityArguments(buildInfo, arguments, editorSettings);
// Logger
AddLoggerArgument(buildInfo, arguments);
+ // Binary log
+ AddBinaryLogArgument(buildInfo, arguments, editorSettings);
+
// Custom properties
foreach (var customProperty in buildInfo.CustomProperties)
{
@@ -163,7 +175,8 @@ namespace GodotTools.Build
}
}
- private static void BuildPublishArguments(BuildInfo buildInfo, Collection<string> arguments)
+ private static void BuildPublishArguments(BuildInfo buildInfo, Collection<string> arguments,
+ EditorSettings editorSettings)
{
arguments.Add("publish"); // `dotnet publish` command
@@ -193,12 +206,14 @@ namespace GodotTools.Build
arguments.Add("true");
// Verbosity
- arguments.Add("-v");
- arguments.Add("normal");
+ AddVerbosityArguments(buildInfo, arguments, editorSettings);
// Logger
AddLoggerArgument(buildInfo, arguments);
+ // Binary log
+ AddBinaryLogArgument(buildInfo, arguments, editorSettings);
+
// Custom properties
foreach (var customProperty in buildInfo.CustomProperties)
{
@@ -213,6 +228,25 @@ namespace GodotTools.Build
}
}
+ private static void AddVerbosityArguments(BuildInfo buildInfo, Collection<string> arguments,
+ EditorSettings editorSettings)
+ {
+ var verbosityLevel =
+ editorSettings.GetSetting(GodotSharpEditor.Settings.VerbosityLevel).As<VerbosityLevelId>();
+ arguments.Add("-v");
+ arguments.Add(verbosityLevel switch
+ {
+ VerbosityLevelId.Quiet => "quiet",
+ VerbosityLevelId.Minimal => "minimal",
+ VerbosityLevelId.Detailed => "detailed",
+ VerbosityLevelId.Diagnostic => "diagnostic",
+ _ => "normal",
+ });
+
+ if ((bool)editorSettings.GetSetting(GodotSharpEditor.Settings.NoConsoleLogging))
+ arguments.Add("-noconlog");
+ }
+
private static void AddLoggerArgument(BuildInfo buildInfo, Collection<string> arguments)
{
string buildLoggerPath = Path.Combine(Internals.GodotSharpDirs.DataEditorToolsDir,
@@ -222,6 +256,16 @@ namespace GodotTools.Build
$"-l:{typeof(GodotBuildLogger).FullName},{buildLoggerPath};{buildInfo.LogsDirPath}");
}
+ private static void AddBinaryLogArgument(BuildInfo buildInfo, Collection<string> arguments,
+ EditorSettings editorSettings)
+ {
+ if (!(bool)editorSettings.GetSetting(GodotSharpEditor.Settings.CreateBinaryLog))
+ return;
+
+ arguments.Add($"-bl:{Path.Combine(buildInfo.LogsDirPath, "msbuild.binlog")}");
+ arguments.Add("-ds:False"); // Honestly never understood why -bl also switches -ds on.
+ }
+
private static void RemovePlatformVariable(StringDictionary environmentVariables)
{
// EnvironmentVariables is case sensitive? Seriously?
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
index 262de024ca..cf1b84e37f 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
@@ -1,4 +1,5 @@
using System;
+using System.IO;
using Godot;
using GodotTools.Internals;
using static GodotTools.Internals.Globals;
@@ -14,6 +15,7 @@ namespace GodotTools.Build
private Button _errorsBtn;
private Button _warningsBtn;
private Button _viewLogBtn;
+ private Button _openLogsFolderBtn;
private void WarningsToggled(bool pressed)
{
@@ -93,6 +95,10 @@ namespace GodotTools.Build
private void ViewLogToggled(bool pressed) => BuildOutputView.LogVisible = pressed;
+ private void OpenLogsFolderPressed() => OS.ShellOpen(
+ $"file://{GodotSharpDirs.LogsDirPathFor("Debug")}"
+ );
+
private void BuildMenuOptionPressed(long id)
{
switch ((BuildMenuOptions)id)
@@ -171,6 +177,22 @@ namespace GodotTools.Build
_viewLogBtn.Toggled += ViewLogToggled;
toolBarHBox.AddChild(_viewLogBtn);
+ // Horizontal spacer, push everything to the right.
+ toolBarHBox.AddChild(new Control
+ {
+ SizeFlagsHorizontal = SizeFlags.ExpandFill,
+ });
+
+ _openLogsFolderBtn = new Button
+ {
+ Text = "Show Logs in File Manager".TTR(),
+ Icon = GetThemeIcon("Filesystem", "EditorIcons"),
+ ExpandIcon = false,
+ FocusMode = FocusModeEnum.None,
+ };
+ _openLogsFolderBtn.Pressed += OpenLogsFolderPressed;
+ toolBarHBox.AddChild(_openLogsFolderBtn);
+
BuildOutputView = new BuildOutputView();
AddChild(BuildOutputView);
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index 70b48b0e3a..a284451a35 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -24,19 +24,7 @@ namespace GodotTools.Export
public void RegisterExportSettings()
{
// TODO: These would be better as export preset options, but that doesn't seem to be supported yet
-
- GlobalDef("mono/export/include_scripts_content", false);
-
- GlobalDef("mono/export/aot/enabled", false);
- GlobalDef("mono/export/aot/full_aot", false);
- GlobalDef("mono/export/aot/use_interpreter", true);
-
- // --aot or --aot=opt1,opt2 (use 'mono --aot=help AuxAssembly.dll' to list AOT options)
- GlobalDef("mono/export/aot/extra_aot_options", Array.Empty<string>());
- // --optimize/-O=opt1,opt2 (use 'mono --list-opt'' to list optimize options)
- GlobalDef("mono/export/aot/extra_optimizer_options", Array.Empty<string>());
-
- GlobalDef("mono/export/aot/android_toolchain_path", "");
+ GlobalDef("dotnet/export/include_scripts_content", false);
}
private string _maybeLastExportError;
@@ -56,7 +44,7 @@ namespace GodotTools.Export
// TODO What if the source file is not part of the game's C# project
- bool includeScriptsContent = (bool)ProjectSettings.GetSetting("mono/export/include_scripts_content");
+ bool includeScriptsContent = (bool)ProjectSettings.GetSetting("dotnet/export/include_scripts_content");
if (!includeScriptsContent)
{
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index 5abbe8752c..43ead4af69 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -22,6 +22,14 @@ namespace GodotTools
{
public partial class GodotSharpEditor : EditorPlugin, ISerializationListener
{
+ public static class Settings
+ {
+ public const string ExternalEditor = "dotnet/editor/external_editor";
+ public const string VerbosityLevel = "dotnet/build/verbosity_level";
+ public const string NoConsoleLogging = "dotnet/build/no_console_logging";
+ public const string CreateBinaryLog = "dotnet/build/create_binary_log";
+ }
+
private EditorSettings _editorSettings;
private PopupMenu _menuPopup;
@@ -171,7 +179,7 @@ namespace GodotTools
[UsedImplicitly]
public Error OpenInExternalEditor(Script script, int line, int col)
{
- var editorId = (ExternalEditorId)(int)_editorSettings.GetSetting("mono/editor/external_editor");
+ var editorId = _editorSettings.GetSetting(Settings.ExternalEditor).As<ExternalEditorId>();
switch (editorId)
{
@@ -323,8 +331,7 @@ namespace GodotTools
[UsedImplicitly]
public bool OverridesExternalEditor()
{
- return (ExternalEditorId)(int)_editorSettings.GetSetting("mono/editor/external_editor") !=
- ExternalEditorId.None;
+ return _editorSettings.GetSetting(Settings.ExternalEditor).As<ExternalEditorId>() != ExternalEditorId.None;
}
public override bool _Build()
@@ -453,7 +460,10 @@ namespace GodotTools
_menuPopup.IdPressed += _MenuOptionPressed;
// External editor settings
- EditorDef("mono/editor/external_editor", Variant.From(ExternalEditorId.None));
+ EditorDef(Settings.ExternalEditor, Variant.From(ExternalEditorId.None));
+ EditorDef(Settings.VerbosityLevel, Variant.From(VerbosityLevelId.Normal));
+ EditorDef(Settings.NoConsoleLogging, false);
+ EditorDef(Settings.CreateBinaryLog, false);
string settingsHintStr = "Disabled";
@@ -481,11 +491,23 @@ namespace GodotTools
_editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
{
["type"] = (int)Variant.Type.Int,
- ["name"] = "mono/editor/external_editor",
+ ["name"] = Settings.ExternalEditor,
["hint"] = (int)PropertyHint.Enum,
["hint_string"] = settingsHintStr
});
+ var verbosityLevels = Enum.GetValues<VerbosityLevelId>().Select(level => $"{Enum.GetName(level)}:{(int)level}");
+ _editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
+ {
+ ["type"] = (int)Variant.Type.Int,
+ ["name"] = Settings.VerbosityLevel,
+ ["hint"] = (int)PropertyHint.Enum,
+ ["hint_string"] = string.Join(",", verbosityLevels),
+ });
+
+ OnSettingsChanged();
+ _editorSettings.SettingsChanged += OnSettingsChanged;
+
// Export plugin
var exportPlugin = new ExportPlugin();
AddExportPlugin(exportPlugin);
@@ -510,6 +532,24 @@ namespace GodotTools
AddChild(GodotIdeManager);
}
+ public override void _DisablePlugin()
+ {
+ base._DisablePlugin();
+
+ _editorSettings.SettingsChanged -= OnSettingsChanged;
+ }
+
+ private void OnSettingsChanged()
+ {
+ // We want to force NoConsoleLogging to true when the VerbosityLevel is at Detailed or above.
+ // At that point, there's so much info logged that it doesn't make sense to display it in
+ // the tiny editor window, and it'd make the editor hang or crash anyway.
+ var verbosityLevel = _editorSettings.GetSetting(Settings.VerbosityLevel).As<VerbosityLevelId>();
+ var hideConsoleLog = (bool)_editorSettings.GetSetting(Settings.NoConsoleLogging);
+ if (verbosityLevel >= VerbosityLevelId.Detailed && !hideConsoleLog)
+ _editorSettings.SetSetting(Settings.NoConsoleLogging, Variant.From(true));
+ }
+
protected override void Dispose(bool disposing)
{
if (disposing)
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
index 5de2c9833b..83621ce5af 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
@@ -21,7 +21,8 @@ namespace GodotTools.Ides
return _messagingServer;
_messagingServer?.Dispose();
- _messagingServer = new MessagingServer(OS.GetExecutablePath(), ProjectSettings.GlobalizePath(GodotSharpDirs.ResMetadataDir), new GodotLogger());
+ _messagingServer = new MessagingServer(OS.GetExecutablePath(),
+ ProjectSettings.GlobalizePath(GodotSharpDirs.ResMetadataDir), new GodotLogger());
_ = _messagingServer.Listen();
@@ -76,8 +77,8 @@ namespace GodotTools.Ides
public async Task<EditorPick?> LaunchIdeAsync(int millisecondsTimeout = 10000)
{
- var editorId = (ExternalEditorId)(int)GodotSharpEditor.Instance.GetEditorInterface()
- .GetEditorSettings().GetSetting("mono/editor/external_editor");
+ var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
+ var editorId = editorSettings.GetSetting(GodotSharpEditor.Settings.ExternalEditor).As<ExternalEditorId>();
string editorIdentity = GetExternalEditorIdentity(editorId);
var runningServer = GetRunningOrNewServer();
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
index 60602a5847..f55ca4c7d7 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
@@ -9,7 +9,7 @@ namespace GodotTools.Ides.Rider
{
public static class RiderPathManager
{
- public static readonly string EditorPathSettingName = "mono/editor/editor_path_optional";
+ public static readonly string EditorPathSettingName = "dotnet/editor/editor_path_optional";
private static string GetRiderPathFromSettings()
{
@@ -22,7 +22,7 @@ namespace GodotTools.Ides.Rider
public static void Initialize()
{
var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
- var editor = (ExternalEditorId)(int)editorSettings.GetSetting("mono/editor/external_editor");
+ var editor = editorSettings.GetSetting(GodotSharpEditor.Settings.ExternalEditor).As<ExternalEditorId>();
if (editor == ExternalEditorId.Rider)
{
if (!editorSettings.HasSetting(EditorPathSettingName))
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
index 7624989092..fb68fcbae6 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
@@ -115,5 +115,11 @@ namespace GodotTools.Internals
return _projectCsProjPath;
}
}
+
+ public static string LogsDirPathFor(string solution, string configuration)
+ => Path.Combine(BuildLogsDirs, $"{solution.Md5Text()}_{configuration}");
+
+ public static string LogsDirPathFor(string configuration)
+ => LogsDirPathFor(ProjectSlnPath, configuration);
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/VerbosityLevelId.cs b/modules/mono/editor/GodotTools/GodotTools/VerbosityLevelId.cs
new file mode 100644
index 0000000000..0e1afe6bbf
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/VerbosityLevelId.cs
@@ -0,0 +1,11 @@
+namespace GodotTools
+{
+ public enum VerbosityLevelId : long
+ {
+ Quiet,
+ Minimal,
+ Normal,
+ Detailed,
+ Diagnostic,
+ }
+}