summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/input/input.cpp10
-rw-r--r--core/input/input.h3
-rw-r--r--core/input/input_event.cpp12
-rw-r--r--core/input/input_event.h4
-rw-r--r--core/input/input_map.cpp7
-rw-r--r--doc/classes/InputEventAction.xml3
-rw-r--r--editor/editor_node.cpp155
-rw-r--r--editor/import/resource_importer_shader_file.cpp1
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp2
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp2
-rw-r--r--main/main.cpp6
-rw-r--r--scene/animation/animation_tree.cpp4
-rw-r--r--scene/resources/animation.h2
-rw-r--r--scene/scene_string_names.cpp1
-rw-r--r--scene/scene_string_names.h1
15 files changed, 144 insertions, 69 deletions
diff --git a/core/input/input.cpp b/core/input/input.cpp
index a8409cc06d..aa4b47934e 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -1029,6 +1029,14 @@ void Input::parse_input_event(const Ref<InputEvent> &p_event) {
}
}
+#ifdef DEBUG_ENABLED
+void Input::flush_frame_parsed_events() {
+ _THREAD_SAFE_METHOD_
+
+ frame_parsed_events.clear();
+}
+#endif
+
void Input::flush_buffered_events() {
_THREAD_SAFE_METHOD_
@@ -1244,7 +1252,7 @@ void Input::_update_action_cache(const StringName &p_action_name, ActionState &r
r_action_state.cache.strength = 0.0;
r_action_state.cache.raw_strength = 0.0;
- int max_event = InputMap::get_singleton()->action_get_events(p_action_name)->size();
+ int max_event = InputMap::get_singleton()->action_get_events(p_action_name)->size() + 1; // +1 comes from InputEventAction.
for (const KeyValue<int, ActionState::DeviceState> &kv : r_action_state.device_states) {
const ActionState::DeviceState &device_state = kv.value;
for (int i = 0; i < max_event; i++) {
diff --git a/core/input/input.h b/core/input/input.h
index 6e7ab43082..4daea0c9e8 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -363,6 +363,9 @@ public:
Dictionary get_joy_info(int p_device) const;
void set_fallback_mapping(const String &p_guid);
+#ifdef DEBUG_ENABLED
+ void flush_frame_parsed_events();
+#endif
void flush_buffered_events();
bool is_using_input_buffering();
void set_use_input_buffering(bool p_enable);
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index bf1de8d3b2..de3efa7a3a 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -1585,6 +1585,14 @@ float InputEventAction::get_strength() const {
return strength;
}
+void InputEventAction::set_event_index(int p_index) {
+ event_index = p_index;
+}
+
+int InputEventAction::get_event_index() const {
+ return event_index;
+}
+
bool InputEventAction::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) const {
if (p_event.is_null()) {
return false;
@@ -1649,9 +1657,13 @@ void InputEventAction::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_strength", "strength"), &InputEventAction::set_strength);
ClassDB::bind_method(D_METHOD("get_strength"), &InputEventAction::get_strength);
+ ClassDB::bind_method(D_METHOD("set_event_index", "index"), &InputEventAction::set_event_index);
+ ClassDB::bind_method(D_METHOD("get_event_index"), &InputEventAction::get_event_index);
+
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "action"), "set_action", "get_action");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_strength", "get_strength");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "event_index", PROPERTY_HINT_RANGE, "-1,31,1"), "set_event_index", "get_event_index"); // The max value equals to Input::MAX_EVENT - 1.
}
///////////////////////////////////
diff --git a/core/input/input_event.h b/core/input/input_event.h
index 21b61f3bc2..19176f748e 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -453,6 +453,7 @@ class InputEventAction : public InputEvent {
StringName action;
float strength = 1.0f;
+ int event_index = -1;
protected:
static void _bind_methods();
@@ -466,6 +467,9 @@ public:
void set_strength(float p_strength);
float get_strength() const;
+ void set_event_index(int p_index);
+ int get_event_index() const;
+
virtual bool is_action(const StringName &p_action) const;
virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index 7fd1806b31..178d02b987 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -274,6 +274,13 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str
if (r_raw_strength != nullptr) {
*r_raw_strength = strength;
}
+ if (r_event_index) {
+ if (input_event_action->get_event_index() >= 0) {
+ *r_event_index = input_event_action->get_event_index();
+ } else {
+ *r_event_index = E->value.inputs.size();
+ }
+ }
return input_event_action->get_action() == p_action;
}
diff --git a/doc/classes/InputEventAction.xml b/doc/classes/InputEventAction.xml
index 4715f9fe95..e082adeca0 100644
--- a/doc/classes/InputEventAction.xml
+++ b/doc/classes/InputEventAction.xml
@@ -16,6 +16,9 @@
<member name="action" type="StringName" setter="set_action" getter="get_action" default="&amp;&quot;&quot;">
The action's name. Actions are accessed via this [String].
</member>
+ <member name="event_index" type="int" setter="set_event_index" getter="get_event_index" default="-1">
+ The real event index in action this event corresponds to (from events defined for this action in the [InputMap]). If [code]-1[/code], a unique ID will be used and actions pressed with this ID will need to be released with another [InputEventAction].
+ </member>
<member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" default="false">
If [code]true[/code], the action's state is pressed. If [code]false[/code], the action's state is released.
</member>
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 0df4df36bc..af06ccb885 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -1067,7 +1067,7 @@ void EditorNode::_resources_reimported(const Vector<String> &p_resources) {
reload_instances_with_path_in_edited_scenes(E);
}
- scene_tabs->set_current_tab(current_tab);
+ _set_current_scene_nocheck(current_tab);
}
void EditorNode::_sources_changed(bool p_exist) {
@@ -5719,8 +5719,14 @@ void EditorNode::reload_scene(const String &p_path) {
if (scene_idx == -1) {
if (get_edited_scene()) {
+ int current_history_id = editor_data.get_current_edited_scene_history_id();
+ bool is_unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(current_history_id);
+
// Scene is not open, so at it might be instantiated. We'll refresh the whole scene later.
- EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_current_edited_scene_history_id());
+ EditorUndoRedoManager::get_singleton()->clear_history(false, current_history_id);
+ if (is_unsaved) {
+ EditorUndoRedoManager::get_singleton()->set_history_as_unsaved(current_history_id);
+ }
}
return;
}
@@ -5770,7 +5776,6 @@ void EditorNode::find_all_instances_inheriting_path_in_node(Node *p_root, Node *
}
void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_instance_path) {
- int original_edited_scene_idx = editor_data.get_edited_scene();
HashMap<int, List<Node *>> edited_scene_map;
Array replaced_nodes;
@@ -5801,14 +5806,34 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
HashMap<String, Ref<PackedScene>> local_scene_cache;
local_scene_cache[p_instance_path] = instance_scene_packed_scene;
+ // Save the current scene state/selection in case of lost.
+ Dictionary editor_state = _get_main_scene_state();
+ editor_data.save_edited_scene_state(editor_selection, &editor_history, editor_state);
+ editor_selection->clear();
+
+ int original_edited_scene_idx = editor_data.get_edited_scene();
+ Node *original_edited_scene_root = editor_data.get_edited_scene_root();
+
+ // Prevent scene roots with the same name from being in the tree at the same time.
+ scene_root->remove_child(original_edited_scene_root);
+
for (const KeyValue<int, List<Node *>> &edited_scene_map_elem : edited_scene_map) {
// Set the current scene.
int current_scene_idx = edited_scene_map_elem.key;
editor_data.set_edited_scene(current_scene_idx);
Node *current_edited_scene = editor_data.get_edited_scene_root(current_scene_idx);
- // Clear the history for this tab (should we allow history to be retained?).
- EditorUndoRedoManager::get_singleton()->clear_history();
+ // Make sure the node is in the tree so that editor_selection can add node smoothly.
+ scene_root->add_child(current_edited_scene);
+
+ // Restore the state so that the selection can be updated.
+ editor_state = editor_data.restore_edited_scene_state(editor_selection, &editor_history);
+
+ int current_history_id = editor_data.get_current_edited_scene_history_id();
+ bool is_unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(current_history_id);
+
+ // Clear the history for this affected tab.
+ EditorUndoRedoManager::get_singleton()->clear_history(false, current_history_id);
// Update the version
editor_data.is_scene_changed(current_scene_idx);
@@ -5818,6 +5843,52 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
update_node_reference_modification_table_for_node(current_edited_scene, current_edited_scene, edited_scene_map_elem.value, edited_scene_global_modification_table);
for (Node *original_node : edited_scene_map_elem.value) {
+ String original_node_file_path = original_node->get_scene_file_path();
+
+ // Load a replacement scene for the node.
+ Ref<PackedScene> current_packed_scene;
+ if (original_node_file_path == p_instance_path) {
+ // If the node file name directly matches the scene we're replacing,
+ // just load it since we already cached it.
+ current_packed_scene = instance_scene_packed_scene;
+ } else {
+ // Otherwise, check the inheritance chain, reloading and caching any scenes
+ // we require along the way.
+ List<String> required_load_paths;
+
+ // Do we need to check if the paths are empty?
+ if (!original_node_file_path.is_empty()) {
+ required_load_paths.push_front(original_node_file_path);
+ }
+ Ref<SceneState> inherited_state = original_node->get_scene_inherited_state();
+ while (inherited_state.is_valid()) {
+ String inherited_path = inherited_state->get_path();
+ // Do we need to check if the paths are empty?
+ if (!inherited_path.is_empty()) {
+ required_load_paths.push_front(inherited_path);
+ }
+ inherited_state = inherited_state->get_base_scene_state();
+ }
+
+ // Ensure the inheritance chain is loaded in the correct order so that cache can
+ // be properly updated.
+ for (String path : required_load_paths) {
+ if (!local_scene_cache.find(path)) {
+ current_packed_scene = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REPLACE_DEEP, &err);
+ local_scene_cache[path] = current_packed_scene;
+ } else {
+ current_packed_scene = local_scene_cache[path];
+ }
+ }
+ }
+
+ ERR_FAIL_COND(current_packed_scene.is_null());
+
+ // Instantiate early so that caches cleared on load in SceneState can be rebuilt early.
+ Node *instantiated_node = current_packed_scene->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
+
+ ERR_FAIL_NULL(instantiated_node);
+
// Walk the tree for the current node and extract relevant diff data, storing it in the modification table.
// For additional nodes which are part of the current scene, they get added to the addition table.
HashMap<NodePath, ModificationNodeEntry> modification_table;
@@ -5875,53 +5946,6 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
is_editable = owner->is_editable_instance(original_node);
}
- // Load a replacement scene for the node.
- Ref<PackedScene> current_packed_scene;
- if (original_node->get_scene_file_path() == p_instance_path) {
- // If the node file name directly matches the scene we're replacing,
- // just load it since we already cached it.
- current_packed_scene = instance_scene_packed_scene;
- } else {
- // Otherwise, check the inheritance chain, reloading and caching any scenes
- // we require along the way.
- List<String> required_load_paths;
- String scene_path = original_node->get_scene_file_path();
- // Do we need to check if the paths are empty?
- if (!scene_path.is_empty()) {
- required_load_paths.push_front(scene_path);
- }
- Ref<SceneState> inherited_state = original_node->get_scene_inherited_state();
- while (inherited_state.is_valid()) {
- String inherited_path = inherited_state->get_path();
- // Do we need to check if the paths are empty?
- if (!inherited_path.is_empty()) {
- required_load_paths.push_front(inherited_path);
- }
- inherited_state = inherited_state->get_base_scene_state();
- }
-
- // Ensure the inheritance chain is loaded in the correct order so that cache can
- // be properly updated.
- for (String path : required_load_paths) {
- if (!local_scene_cache.find(path)) {
- current_packed_scene = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REPLACE_DEEP, &err);
- local_scene_cache[path] = current_packed_scene;
- } else {
- current_packed_scene = local_scene_cache[path];
- }
- }
- }
-
- ERR_FAIL_COND(current_packed_scene.is_null());
-
- // Instantiate the node.
- Node *instantiated_node = nullptr;
- if (current_packed_scene.is_valid()) {
- instantiated_node = current_packed_scene->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
- }
-
- ERR_FAIL_NULL(instantiated_node);
-
// For clear instance state for path recaching.
instantiated_node->set_scene_instance_state(Ref<SceneState>());
@@ -5932,7 +5956,6 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
instantiated_node->set_name(original_node->get_name());
// Is this replacing the edited root node?
- String original_node_file_path = original_node->get_scene_file_path();
if (current_edited_scene == original_node) {
instantiated_node->set_scene_instance_state(original_node->get_scene_instance_state());
@@ -5943,13 +5966,7 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
instantiated_node->set_scene_inherited_state(state);
instantiated_node->set_scene_file_path(String());
}
- editor_data.set_edited_scene_root(instantiated_node);
current_edited_scene = instantiated_node;
-
- if (original_node->is_inside_tree()) {
- SceneTreeDock::get_singleton()->set_edited_scene(current_edited_scene);
- original_node->get_tree()->set_edited_scene_root(instantiated_node);
- }
}
// Replace the original node with the instantiated version.
@@ -6046,8 +6063,18 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
}
}
+ if (is_unsaved) {
+ EditorUndoRedoManager::get_singleton()->set_history_as_unsaved(current_history_id);
+ }
+
+ // Save the current handled scene state.
+ editor_data.save_edited_scene_state(editor_selection, &editor_history, editor_state);
+ editor_selection->clear();
+
// Cleanup the history of the changes.
editor_history.cleanup_history();
+
+ scene_root->remove_child(current_edited_scene);
}
// For the whole editor, call the _notify_nodes_scene_reimported with a list of replaced nodes.
@@ -6055,10 +6082,14 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
_notify_nodes_scene_reimported(this, replaced_nodes);
edited_scene_map.clear();
- }
- editor_data.set_edited_scene(original_edited_scene_idx);
- _edit_current();
+ editor_data.set_edited_scene(original_edited_scene_idx);
+
+ original_edited_scene_root = editor_data.get_edited_scene_root();
+ scene_root->add_child(original_edited_scene_root);
+
+ editor_data.restore_edited_scene_state(editor_selection, &editor_history);
+ }
}
int EditorNode::plugin_init_callback_count = 0;
diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp
index 6b20a8c9d5..b7508e7644 100644
--- a/editor/import/resource_importer_shader_file.cpp
+++ b/editor/import/resource_importer_shader_file.cpp
@@ -92,6 +92,7 @@ static String _include_function(const String &p_path, void *userpointer) {
Error ResourceImporterShaderFile::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
/* STEP 1, Read shader code */
ERR_FAIL_COND_V_EDMSG((OS::get_singleton()->get_current_rendering_method() == "gl_compatibility"), ERR_UNAVAILABLE, "Cannot import custom .glsl shaders when using the gl_compatibility rendering_method. Please switch to the forward_plus or mobile rendering methods to use custom shaders.");
+ ERR_FAIL_COND_V_EDMSG((DisplayServer::get_singleton()->get_name() == "headless"), ERR_UNAVAILABLE, "Cannot import custom .glsl shaders when running in headless mode.");
Error err;
Ref<FileAccess> file = FileAccess::open(p_source_file, FileAccess::READ, &err);
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index b6d81ce461..449e99d692 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -118,7 +118,7 @@ String AnimationNodeStateMachineEditor::_get_root_playback_path(String &r_node_d
if (node_directory_path.size()) {
r_node_directory += "/";
}
- base_path = !edited_path.size() ? String(SceneStringName(parameters_base_path)) + "playback" : String(SceneStringName(parameters_base_path)) + base_path + "/playback";
+ base_path = !edited_path.size() ? Animation::PARAMETERS_BASE_PATH + "playback" : Animation::PARAMETERS_BASE_PATH + base_path + "/playback";
} else {
// Hmmm, we have to return Grouped state machine playback...
// It will give the user the error that Root/Nested state machine should be retrieved, that would be kind :-)
diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp
index cc1f51348d..757d410b78 100644
--- a/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_editor_plugin.cpp
@@ -220,7 +220,7 @@ void AnimationTreeEditor::remove_plugin(AnimationTreeNodeEditorPlugin *p_editor)
}
String AnimationTreeEditor::get_base_path() {
- String path = SceneStringName(parameters_base_path);
+ String path = Animation::PARAMETERS_BASE_PATH;
for (int i = 0; i < edited_path.size(); i++) {
path += edited_path[i] + "/";
}
diff --git a/main/main.cpp b/main/main.cpp
index 2bd421e5af..6b17c55efc 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -4182,6 +4182,12 @@ void Main::cleanup(bool p_force) {
ERR_FAIL_COND(!_start_success);
}
+#ifdef DEBUG_ENABLED
+ if (input) {
+ input->flush_frame_parsed_events();
+ }
+#endif
+
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
TextServerManager::get_singleton()->get_interface(i)->cleanup();
}
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index d4061ab167..69287478db 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -626,7 +626,7 @@ bool AnimationTree::_blend_pre_process(double p_delta, int p_track_count, const
for (int i = 0; i < p_track_count; i++) {
src_blendsw[i] = 1.0; // By default all go to 1 for the root input.
}
- root_animation_node->node_state.base_path = SceneStringName(parameters_base_path);
+ root_animation_node->node_state.base_path = SNAME(Animation::PARAMETERS_BASE_PATH.ascii().get_data());
root_animation_node->node_state.parent = nullptr;
}
@@ -787,7 +787,7 @@ void AnimationTree::_update_properties() {
input_activity_map_get.clear();
if (root_animation_node.is_valid()) {
- _update_properties_for_node(SceneStringName(parameters_base_path), root_animation_node);
+ _update_properties_for_node(Animation::PARAMETERS_BASE_PATH, root_animation_node);
}
properties_dirty = false;
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index cc7bbae8a3..604bce497a 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -43,6 +43,8 @@ class Animation : public Resource {
public:
typedef uint32_t TypeHash;
+ static inline String PARAMETERS_BASE_PATH = "parameters/";
+
enum TrackType {
TYPE_VALUE, // Set a value in a property, can be interpolated.
TYPE_POSITION_3D, // Position 3D track, can be compressed.
diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp
index 2ee27c95e1..ac3ff7f38c 100644
--- a/scene/scene_string_names.cpp
+++ b/scene/scene_string_names.cpp
@@ -123,7 +123,6 @@ SceneStringNames::SceneStringNames() {
window_input = StaticCString::create("window_input");
theme_changed = StaticCString::create("theme_changed");
- parameters_base_path = "parameters/";
shader_overrides_group = StaticCString::create("_shader_overrides_group_");
shader_overrides_group_active = StaticCString::create("_shader_overrides_group_active_");
diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h
index 7ed86cde46..5f68e5180c 100644
--- a/scene/scene_string_names.h
+++ b/scene/scene_string_names.h
@@ -134,7 +134,6 @@ public:
StringName Master;
- StringName parameters_base_path;
StringName window_input;
StringName theme_changed;