mirror of
https://github.com/godotengine/godot
synced 2024-09-30 04:53:46 +00:00
Compare commits
20 commits
1ed549e64b
...
604493eb6e
Author | SHA1 | Date | |
---|---|---|---|
604493eb6e | |||
eb91e909a7 | |||
ecbf087324 | |||
c1cc8fd87f | |||
c09445de2a | |||
6144192bda | |||
7331750618 | |||
388e3eb8b7 | |||
3c81bff6c1 | |||
1ff2204cfe | |||
5a413894fc | |||
91dfd6484b | |||
c0a3129210 | |||
f3e8300b50 | |||
fb107e04d3 | |||
20fdfd466b | |||
ac96af1cc9 | |||
7403a3a11b | |||
b9d1462d2a | |||
e9a3e49086 |
|
@ -369,10 +369,6 @@ void ScriptServer::save_global_classes() {
|
|||
ProjectSettings::get_singleton()->store_global_class_list(gcarr);
|
||||
}
|
||||
|
||||
bool ScriptServer::has_global_classes() {
|
||||
return !global_classes.is_empty();
|
||||
}
|
||||
|
||||
String ScriptServer::get_global_class_cache_file_path() {
|
||||
return ProjectSettings::get_singleton()->get_global_class_list_path();
|
||||
}
|
||||
|
|
|
@ -91,7 +91,6 @@ public:
|
|||
static void get_global_class_list(List<StringName> *r_global_classes);
|
||||
static void get_inheriters_list(const StringName &p_base_type, List<StringName> *r_classes);
|
||||
static void save_global_classes();
|
||||
static bool has_global_classes();
|
||||
static String get_global_class_cache_file_path();
|
||||
|
||||
static void init_languages();
|
||||
|
|
|
@ -106,6 +106,45 @@
|
|||
<return type="PopupMenu" />
|
||||
<description>
|
||||
Returns the [PopupMenu] of this [RichTextLabel]. By default, this menu is displayed when right-clicking on the [RichTextLabel].
|
||||
You can add custom menu items or remove standard ones. Make sure your IDs don't conflict with the standard ones (see [enum MenuItems]). For example:
|
||||
[codeblocks]
|
||||
[gdscript]
|
||||
func _ready():
|
||||
var menu = get_menu()
|
||||
# Remove "Select All" item.
|
||||
menu.remove_item(MENU_SELECT_ALL)
|
||||
# Add custom items.
|
||||
menu.add_separator()
|
||||
menu.add_item("Duplicate Text", MENU_MAX + 1)
|
||||
# Connect callback.
|
||||
menu.id_pressed.connect(_on_item_pressed)
|
||||
|
||||
func _on_item_pressed(id):
|
||||
if id == MENU_MAX + 1:
|
||||
add_text("\n" + get_parsed_text())
|
||||
[/gdscript]
|
||||
[csharp]
|
||||
public override void _Ready()
|
||||
{
|
||||
var menu = GetMenu();
|
||||
// Remove "Select All" item.
|
||||
menu.RemoveItem(RichTextLabel.MenuItems.SelectAll);
|
||||
// Add custom items.
|
||||
menu.AddSeparator();
|
||||
menu.AddItem("Duplicate Text", RichTextLabel.MenuItems.Max + 1);
|
||||
// Add event handler.
|
||||
menu.IdPressed += OnItemPressed;
|
||||
}
|
||||
|
||||
public void OnItemPressed(int id)
|
||||
{
|
||||
if (id == TextEdit.MenuItems.Max + 1)
|
||||
{
|
||||
AddText("\n" + GetParsedText());
|
||||
}
|
||||
}
|
||||
[/csharp]
|
||||
[/codeblocks]
|
||||
[b]Warning:[/b] This is a required internal node, removing and freeing it may cause a crash. If you wish to hide it or any of its children, use their [member Window.visible] property.
|
||||
</description>
|
||||
</method>
|
||||
|
@ -193,6 +232,13 @@
|
|||
If [member threaded] is enabled, returns [code]true[/code] if the background thread has finished text processing, otherwise always return [code]true[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="menu_option">
|
||||
<return type="void" />
|
||||
<param index="0" name="option" type="int" />
|
||||
<description>
|
||||
Executes a given action as defined in the [enum MenuItems] enum.
|
||||
</description>
|
||||
</method>
|
||||
<method name="newline">
|
||||
<return type="void" />
|
||||
<description>
|
||||
|
@ -633,6 +679,15 @@
|
|||
</constant>
|
||||
<constant name="ITEM_CUSTOMFX" value="26" enum="ItemType">
|
||||
</constant>
|
||||
<constant name="MENU_COPY" value="0" enum="MenuItems">
|
||||
Copies the selected text.
|
||||
</constant>
|
||||
<constant name="MENU_SELECT_ALL" value="1" enum="MenuItems">
|
||||
Selects the whole [RichTextLabel] text.
|
||||
</constant>
|
||||
<constant name="MENU_MAX" value="2" enum="MenuItems">
|
||||
Represents the size of the [enum MenuItems] enum.
|
||||
</constant>
|
||||
</constants>
|
||||
<theme_items>
|
||||
<theme_item name="default_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
|
||||
|
|
|
@ -179,7 +179,7 @@ typedef void (*DEBUGPROCARB)(GLenum source,
|
|||
typedef void (*DebugMessageCallbackARB)(DEBUGPROCARB callback, const void *userParam);
|
||||
|
||||
void RasterizerGLES3::initialize() {
|
||||
print_line("OpenGL Renderer: " + RS::get_singleton()->get_video_adapter_name());
|
||||
print_line(vformat("OpenGL API %s - Compatibility - Using Device: %s - %s", RS::get_singleton()->get_video_adapter_api_version(), RS::get_singleton()->get_video_adapter_vendor(), RS::get_singleton()->get_video_adapter_name()));
|
||||
}
|
||||
|
||||
void RasterizerGLES3::finalize() {
|
||||
|
|
|
@ -1299,8 +1299,15 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
|
|||
// Get device version
|
||||
device_api_version = gpu_props.apiVersion;
|
||||
|
||||
String rendering_method;
|
||||
if (OS::get_singleton()->get_current_rendering_method() == "mobile") {
|
||||
rendering_method = "Forward Mobile";
|
||||
} else {
|
||||
rendering_method = "Forward+";
|
||||
}
|
||||
|
||||
// Output our device version
|
||||
print_line("Vulkan API " + get_device_api_version() + " - " + "Using Vulkan Device #" + itos(device_index) + ": " + device_vendor + " - " + device_name);
|
||||
print_line(vformat("Vulkan API %s - %s - Using Vulkan Device #%d: %s - %s", get_device_api_version(), rendering_method, device_index, device_vendor, device_name));
|
||||
|
||||
{
|
||||
Error _err = _initialize_device_extensions();
|
||||
|
|
|
@ -128,7 +128,7 @@ void VisualShaderGraphPlugin::set_connections(const List<VisualShader::Connectio
|
|||
connections = p_connections;
|
||||
}
|
||||
|
||||
void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id) {
|
||||
void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id, bool p_is_valid) {
|
||||
if (visual_shader->get_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].output_ports.has(p_port_id)) {
|
||||
Link &link = links[p_node_id];
|
||||
|
||||
|
@ -162,7 +162,7 @@ void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p
|
|||
vbox->add_child(offset);
|
||||
|
||||
VisualShaderNodePortPreview *port_preview = memnew(VisualShaderNodePortPreview);
|
||||
port_preview->setup(visual_shader, visual_shader->get_shader_type(), p_node_id, p_port_id);
|
||||
port_preview->setup(visual_shader, visual_shader->get_shader_type(), p_node_id, p_port_id, p_is_valid);
|
||||
port_preview->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
|
||||
vbox->add_child(port_preview);
|
||||
link.preview_visible = true;
|
||||
|
@ -351,6 +351,29 @@ void VisualShaderGraphPlugin::update_theme() {
|
|||
vector_expanded_color[3] = editor->get_theme_color(SNAME("axis_w_color"), SNAME("Editor")); // alpha
|
||||
}
|
||||
|
||||
bool VisualShaderGraphPlugin::is_node_has_parameter_instances_relatively(VisualShader::Type p_type, int p_node) const {
|
||||
bool result = false;
|
||||
|
||||
Ref<VisualShaderNodeParameter> parameter_node = Object::cast_to<VisualShaderNodeParameter>(visual_shader->get_node_unchecked(p_type, p_node).ptr());
|
||||
if (parameter_node.is_valid()) {
|
||||
if (parameter_node->get_qualifier() == VisualShaderNodeParameter::QUAL_INSTANCE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
LocalVector<int> prev_connected_nodes;
|
||||
visual_shader->get_prev_connected_nodes(p_type, p_node, prev_connected_nodes);
|
||||
|
||||
for (const int &E : prev_connected_nodes) {
|
||||
result = is_node_has_parameter_instances_relatively(p_type, E);
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool p_just_update) {
|
||||
if (!visual_shader.is_valid() || p_type != visual_shader->get_shader_type()) {
|
||||
return;
|
||||
|
@ -969,8 +992,10 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
|
|||
}
|
||||
}
|
||||
|
||||
bool has_relative_parameter_instances = false;
|
||||
if (vsnode->get_output_port_for_preview() >= 0) {
|
||||
show_port_preview(p_type, p_id, vsnode->get_output_port_for_preview());
|
||||
has_relative_parameter_instances = is_node_has_parameter_instances_relatively(p_type, p_id);
|
||||
show_port_preview(p_type, p_id, vsnode->get_output_port_for_preview(), !has_relative_parameter_instances);
|
||||
} else {
|
||||
offset = memnew(Control);
|
||||
offset->set_custom_minimum_size(Size2(0, 4 * EDSCALE));
|
||||
|
@ -978,6 +1003,9 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
|
|||
}
|
||||
|
||||
String error = vsnode->get_warning(mode, p_type);
|
||||
if (has_relative_parameter_instances) {
|
||||
error += "\n" + TTR("The 2D preview cannot correctly show the result retrieved from instance parameter.");
|
||||
}
|
||||
if (!error.is_empty()) {
|
||||
Label *error_label = memnew(Label);
|
||||
error_label->add_theme_color_override("font_color", editor->get_theme_color(SNAME("error_color"), SNAME("Editor")));
|
||||
|
@ -4970,6 +4998,29 @@ void VisualShaderEditor::_update_preview() {
|
|||
}
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_update_next_previews(int p_node_id) {
|
||||
VisualShader::Type type = get_current_shader_type();
|
||||
|
||||
LocalVector<int> nodes;
|
||||
_get_next_nodes_recursively(type, p_node_id, nodes);
|
||||
|
||||
for (int node_id : nodes) {
|
||||
if (graph_plugin->is_preview_visible(node_id)) {
|
||||
graph_plugin->update_node_deferred(type, node_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_get_next_nodes_recursively(VisualShader::Type p_type, int p_node_id, LocalVector<int> &r_nodes) const {
|
||||
LocalVector<int> next_connections;
|
||||
visual_shader->get_next_connected_nodes(p_type, p_node_id, next_connections);
|
||||
|
||||
for (int node_id : next_connections) {
|
||||
r_nodes.push_back(node_id);
|
||||
_get_next_nodes_recursively(p_type, node_id, r_nodes);
|
||||
}
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_visibility_changed() {
|
||||
if (!is_visible()) {
|
||||
if (preview_window->is_visible()) {
|
||||
|
@ -5002,6 +5053,7 @@ void VisualShaderEditor::_bind_methods() {
|
|||
ClassDB::bind_method("_update_options_menu_deferred", &VisualShaderEditor::_update_options_menu_deferred);
|
||||
ClassDB::bind_method("_rebuild_shader_deferred", &VisualShaderEditor::_rebuild_shader_deferred);
|
||||
ClassDB::bind_method("_resources_removed", &VisualShaderEditor::_resources_removed);
|
||||
ClassDB::bind_method("_update_next_previews", &VisualShaderEditor::_update_next_previews);
|
||||
|
||||
ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available);
|
||||
}
|
||||
|
@ -6292,6 +6344,8 @@ public:
|
|||
if (p_property != "constant") {
|
||||
VisualShaderGraphPlugin *graph_plugin = editor->get_graph_plugin();
|
||||
if (graph_plugin) {
|
||||
undo_redo->add_do_method(editor, "_update_next_previews", node_id);
|
||||
undo_redo->add_undo_method(editor, "_update_next_previews", node_id);
|
||||
undo_redo->add_do_method(graph_plugin, "update_node_deferred", shader_type, node_id);
|
||||
undo_redo->add_undo_method(graph_plugin, "update_node_deferred", shader_type, node_id);
|
||||
}
|
||||
|
@ -6586,7 +6640,7 @@ bool EditorInspectorVisualShaderModePlugin::parse_property(Object *p_object, con
|
|||
//////////////////////////////////
|
||||
|
||||
void VisualShaderNodePortPreview::_shader_changed() {
|
||||
if (shader.is_null()) {
|
||||
if (!is_valid || shader.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -6633,12 +6687,13 @@ void VisualShaderNodePortPreview::_shader_changed() {
|
|||
set_material(mat);
|
||||
}
|
||||
|
||||
void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, VisualShader::Type p_type, int p_node, int p_port) {
|
||||
void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, VisualShader::Type p_type, int p_node, int p_port, bool p_is_valid) {
|
||||
shader = p_shader;
|
||||
shader->connect("changed", callable_mp(this, &VisualShaderNodePortPreview::_shader_changed));
|
||||
shader->connect("changed", callable_mp(this, &VisualShaderNodePortPreview::_shader_changed), CONNECT_DEFERRED);
|
||||
type = p_type;
|
||||
port = p_port;
|
||||
node = p_node;
|
||||
is_valid = p_is_valid;
|
||||
queue_redraw();
|
||||
_shader_changed();
|
||||
}
|
||||
|
@ -6665,14 +6720,24 @@ void VisualShaderNodePortPreview::_notification(int p_what) {
|
|||
Vector2(0, 1)
|
||||
};
|
||||
|
||||
Vector<Color> colors = {
|
||||
Color(1, 1, 1, 1),
|
||||
Color(1, 1, 1, 1),
|
||||
Color(1, 1, 1, 1),
|
||||
Color(1, 1, 1, 1)
|
||||
};
|
||||
if (is_valid) {
|
||||
Vector<Color> colors = {
|
||||
Color(1, 1, 1, 1),
|
||||
Color(1, 1, 1, 1),
|
||||
Color(1, 1, 1, 1),
|
||||
Color(1, 1, 1, 1)
|
||||
};
|
||||
draw_primitive(points, colors, uvs);
|
||||
} else {
|
||||
Vector<Color> colors = {
|
||||
Color(0, 0, 0, 1),
|
||||
Color(0, 0, 0, 1),
|
||||
Color(0, 0, 0, 1),
|
||||
Color(0, 0, 0, 1)
|
||||
};
|
||||
draw_primitive(points, colors, uvs);
|
||||
}
|
||||
|
||||
draw_primitive(points, colors, uvs);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ public:
|
|||
void remove_node(VisualShader::Type p_type, int p_id, bool p_just_update);
|
||||
void connect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port);
|
||||
void disconnect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port);
|
||||
void show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id);
|
||||
void show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id, bool p_is_valid);
|
||||
void set_node_position(VisualShader::Type p_type, int p_id, const Vector2 &p_position);
|
||||
void refresh_node_ports(VisualShader::Type p_type, int p_node);
|
||||
void set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, Variant p_value);
|
||||
|
@ -133,6 +133,7 @@ public:
|
|||
Ref<Script> get_node_script(int p_node_id) const;
|
||||
void update_node_size(int p_node_id);
|
||||
void update_theme();
|
||||
bool is_node_has_parameter_instances_relatively(VisualShader::Type p_type, int p_node) const;
|
||||
VisualShader::Type get_shader_type() const;
|
||||
|
||||
VisualShaderGraphPlugin();
|
||||
|
@ -354,6 +355,8 @@ class VisualShaderEditor : public VBoxContainer {
|
|||
void _preview_close_requested();
|
||||
void _preview_size_changed();
|
||||
void _update_preview();
|
||||
void _update_next_previews(int p_node_id);
|
||||
void _get_next_nodes_recursively(VisualShader::Type p_type, int p_node_id, LocalVector<int> &r_nodes) const;
|
||||
String _get_description(int p_idx);
|
||||
|
||||
struct DragOp {
|
||||
|
@ -570,6 +573,7 @@ class VisualShaderNodePortPreview : public Control {
|
|||
VisualShader::Type type = VisualShader::Type::TYPE_MAX;
|
||||
int node = 0;
|
||||
int port = 0;
|
||||
bool is_valid = false;
|
||||
void _shader_changed(); //must regen
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
@ -577,7 +581,7 @@ protected:
|
|||
|
||||
public:
|
||||
virtual Size2 get_minimum_size() const override;
|
||||
void setup(const Ref<VisualShader> &p_shader, VisualShader::Type p_type, int p_node, int p_port);
|
||||
void setup(const Ref<VisualShader> &p_shader, VisualShader::Type p_type, int p_node, int p_port, bool p_is_valid);
|
||||
};
|
||||
|
||||
class VisualShaderConversionPlugin : public EditorResourceConversionPlugin {
|
||||
|
|
|
@ -1496,7 +1496,12 @@ GDScript::~GDScript() {
|
|||
// Order matters since clearing the stack may already cause
|
||||
// the GDScriptFunctionState to be destroyed and thus removed from the list.
|
||||
pending_func_states.remove(E);
|
||||
E->self()->_clear_stack();
|
||||
GDScriptFunctionState *state = E->self();
|
||||
ObjectID state_id = state->get_instance_id();
|
||||
state->_clear_connections();
|
||||
if (ObjectDB::get_instance(state_id)) {
|
||||
state->_clear_stack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1920,7 +1925,12 @@ GDScriptInstance::~GDScriptInstance() {
|
|||
// Order matters since clearing the stack may already cause
|
||||
// the GDSCriptFunctionState to be destroyed and thus removed from the list.
|
||||
pending_func_states.remove(E);
|
||||
E->self()->_clear_stack();
|
||||
GDScriptFunctionState *state = E->self();
|
||||
ObjectID state_id = state->get_instance_id();
|
||||
state->_clear_connections();
|
||||
if (ObjectDB::get_instance(state_id)) {
|
||||
state->_clear_stack();
|
||||
}
|
||||
}
|
||||
|
||||
if (script.is_valid() && owner) {
|
||||
|
|
|
@ -296,6 +296,15 @@ void GDScriptFunctionState::_clear_stack() {
|
|||
}
|
||||
}
|
||||
|
||||
void GDScriptFunctionState::_clear_connections() {
|
||||
List<Object::Connection> conns;
|
||||
get_signals_connected_to_this(&conns);
|
||||
|
||||
for (Object::Connection &c : conns) {
|
||||
c.signal.disconnect(c.callable);
|
||||
}
|
||||
}
|
||||
|
||||
void GDScriptFunctionState::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("resume", "arg"), &GDScriptFunctionState::resume, DEFVAL(Variant()));
|
||||
ClassDB::bind_method(D_METHOD("is_valid", "extended_check"), &GDScriptFunctionState::is_valid, DEFVAL(false));
|
||||
|
|
|
@ -628,6 +628,7 @@ public:
|
|||
Variant resume(const Variant &p_arg = Variant());
|
||||
|
||||
void _clear_stack();
|
||||
void _clear_connections();
|
||||
|
||||
GDScriptFunctionState();
|
||||
~GDScriptFunctionState();
|
||||
|
|
|
@ -21,6 +21,26 @@ namespace GodotPlugins
|
|||
_resolver = new AssemblyDependencyResolver(pluginPath);
|
||||
_sharedAssemblies = sharedAssemblies;
|
||||
_mainLoadContext = mainLoadContext;
|
||||
|
||||
if (string.IsNullOrEmpty(AppContext.BaseDirectory))
|
||||
{
|
||||
// See https://github.com/dotnet/runtime/blob/v6.0.0/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs#L17-L35
|
||||
// but Assembly.Location is unavailable, because we load assemblies from memory.
|
||||
string? baseDirectory = Path.GetDirectoryName(pluginPath);
|
||||
if (baseDirectory != null)
|
||||
{
|
||||
if (!Path.EndsInDirectorySeparator(baseDirectory))
|
||||
baseDirectory += Path.PathSeparator;
|
||||
// This SetData call effectively sets AppContext.BaseDirectory
|
||||
// See https://github.com/dotnet/runtime/blob/v6.0.0/src/libraries/System.Private.CoreLib/src/System/AppContext.cs#L21-L25
|
||||
AppDomain.CurrentDomain.SetData("APP_CONTEXT_BASE_DIRECTORY", baseDirectory);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: How to log from GodotPlugins? (delegate pointer?)
|
||||
Console.Error.WriteLine("Failed to set AppContext.BaseDirectory. Dynamic loading of libraries may fail.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override Assembly? Load(AssemblyName assemblyName)
|
||||
|
|
|
@ -459,6 +459,10 @@ namespace Godot.NativeInterop
|
|||
|
||||
public static partial godot_bool godotsharp_node_path_is_absolute(in godot_node_path p_self);
|
||||
|
||||
public static partial godot_bool godotsharp_node_path_equals(in godot_node_path p_self, in godot_node_path p_other);
|
||||
|
||||
public static partial int godotsharp_node_path_hash(in godot_node_path p_self);
|
||||
|
||||
// GD, etc
|
||||
|
||||
internal static partial void godotsharp_bytes_to_var(in godot_packed_byte_array p_bytes,
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace Godot
|
|||
/// new NodePath("/root/MyAutoload"); // If you have an autoloaded node or scene.
|
||||
/// </code>
|
||||
/// </example>
|
||||
public sealed class NodePath : IDisposable
|
||||
public sealed class NodePath : IDisposable, IEquatable<NodePath>
|
||||
{
|
||||
internal godot_node_path.movable NativeValue;
|
||||
|
||||
|
@ -288,5 +288,37 @@ namespace Godot
|
|||
/// </summary>
|
||||
/// <returns>If the <see cref="NodePath"/> is empty.</returns>
|
||||
public bool IsEmpty => NativeValue.DangerousSelfRef.IsEmpty;
|
||||
|
||||
public static bool operator ==(NodePath left, NodePath right)
|
||||
{
|
||||
if (left is null)
|
||||
return right is null;
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(NodePath left, NodePath right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
public bool Equals(NodePath other)
|
||||
{
|
||||
if (other is null)
|
||||
return false;
|
||||
var self = (godot_node_path)NativeValue;
|
||||
var otherNative = (godot_node_path)other.NativeValue;
|
||||
return NativeFuncs.godotsharp_node_path_equals(self, otherNative).ToBool();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return ReferenceEquals(this, obj) || (obj is NodePath other && Equals(other));
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var self = (godot_node_path)NativeValue;
|
||||
return NativeFuncs.godotsharp_node_path_hash(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Godot
|
|||
/// Comparing them is much faster than with regular strings, because only the pointers are compared,
|
||||
/// not the whole strings.
|
||||
/// </summary>
|
||||
public sealed class StringName : IDisposable
|
||||
public sealed class StringName : IDisposable, IEquatable<StringName>
|
||||
{
|
||||
internal godot_string_name.movable NativeValue;
|
||||
|
||||
|
|
|
@ -1141,6 +1141,14 @@ bool godotsharp_node_path_is_absolute(const NodePath *p_self) {
|
|||
return p_self->is_absolute();
|
||||
}
|
||||
|
||||
bool godotsharp_node_path_equals(const NodePath *p_self, const NodePath *p_other) {
|
||||
return *p_self == *p_other;
|
||||
}
|
||||
|
||||
int godotsharp_node_path_hash(const NodePath *p_self) {
|
||||
return p_self->hash();
|
||||
}
|
||||
|
||||
void godotsharp_randomize() {
|
||||
Math::randomize();
|
||||
}
|
||||
|
@ -1477,6 +1485,8 @@ static const void *unmanaged_callbacks[]{
|
|||
(void *)godotsharp_node_path_get_subname,
|
||||
(void *)godotsharp_node_path_get_subname_count,
|
||||
(void *)godotsharp_node_path_is_absolute,
|
||||
(void *)godotsharp_node_path_equals,
|
||||
(void *)godotsharp_node_path_hash,
|
||||
(void *)godotsharp_bytes_to_var,
|
||||
(void *)godotsharp_convert,
|
||||
(void *)godotsharp_hash,
|
||||
|
|
|
@ -168,6 +168,17 @@ void NavigationAgent2D::_notification(int p_what) {
|
|||
set_physics_process_internal(false);
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
set_agent_parent(nullptr);
|
||||
set_physics_process_internal(false);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (debug_path_instance.is_valid()) {
|
||||
RenderingServer::get_singleton()->canvas_item_set_visible(debug_path_instance, false);
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_PAUSED: {
|
||||
if (agent_parent && !agent_parent->can_process()) {
|
||||
map_before_pause = NavigationServer2D::get_singleton()->agent_get_map(get_rid());
|
||||
|
@ -188,17 +199,6 @@ void NavigationAgent2D::_notification(int p_what) {
|
|||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
agent_parent = nullptr;
|
||||
set_physics_process_internal(false);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (debug_path_instance.is_valid()) {
|
||||
RenderingServer::get_singleton()->canvas_item_set_visible(debug_path_instance, false);
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
|
||||
if (agent_parent && target_position_submitted) {
|
||||
if (avoidance_enabled) {
|
||||
|
@ -208,7 +208,6 @@ void NavigationAgent2D::_notification(int p_what) {
|
|||
}
|
||||
_check_distance_to_target();
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (debug_path_dirty) {
|
||||
_update_debug_path();
|
||||
|
@ -220,11 +219,11 @@ void NavigationAgent2D::_notification(int p_what) {
|
|||
|
||||
NavigationAgent2D::NavigationAgent2D() {
|
||||
agent = NavigationServer2D::get_singleton()->agent_create();
|
||||
set_neighbor_distance(neighbor_distance);
|
||||
set_max_neighbors(max_neighbors);
|
||||
set_time_horizon(time_horizon);
|
||||
set_radius(radius);
|
||||
set_max_speed(max_speed);
|
||||
NavigationServer2D::get_singleton()->agent_set_neighbor_distance(agent, neighbor_distance);
|
||||
NavigationServer2D::get_singleton()->agent_set_max_neighbors(agent, max_neighbors);
|
||||
NavigationServer2D::get_singleton()->agent_set_time_horizon(agent, time_horizon);
|
||||
NavigationServer2D::get_singleton()->agent_set_radius(agent, radius);
|
||||
NavigationServer2D::get_singleton()->agent_set_max_speed(agent, max_speed);
|
||||
|
||||
// Preallocate query and result objects to improve performance.
|
||||
navigation_query = Ref<NavigationPathQueryParameters2D>();
|
||||
|
@ -254,7 +253,12 @@ NavigationAgent2D::~NavigationAgent2D() {
|
|||
}
|
||||
|
||||
void NavigationAgent2D::set_avoidance_enabled(bool p_enabled) {
|
||||
if (avoidance_enabled == p_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
avoidance_enabled = p_enabled;
|
||||
|
||||
if (avoidance_enabled) {
|
||||
NavigationServer2D::get_singleton()->agent_set_callback(agent, callable_mp(this, &NavigationAgent2D::_avoidance_done));
|
||||
} else {
|
||||
|
@ -267,6 +271,10 @@ bool NavigationAgent2D::get_avoidance_enabled() const {
|
|||
}
|
||||
|
||||
void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) {
|
||||
if (agent_parent == p_agent_parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map
|
||||
NavigationServer2D::get_singleton()->agent_set_callback(agent, Callable());
|
||||
|
||||
|
@ -280,7 +288,9 @@ void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) {
|
|||
}
|
||||
|
||||
// create new avoidance callback if enabled
|
||||
set_avoidance_enabled(avoidance_enabled);
|
||||
if (avoidance_enabled) {
|
||||
NavigationServer2D::get_singleton()->agent_set_callback(agent, callable_mp(this, &NavigationAgent2D::_avoidance_done));
|
||||
}
|
||||
} else {
|
||||
agent_parent = nullptr;
|
||||
NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID());
|
||||
|
@ -288,11 +298,13 @@ void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) {
|
|||
}
|
||||
|
||||
void NavigationAgent2D::set_navigation_layers(uint32_t p_navigation_layers) {
|
||||
bool navigation_layers_changed = navigation_layers != p_navigation_layers;
|
||||
navigation_layers = p_navigation_layers;
|
||||
if (navigation_layers_changed) {
|
||||
_request_repath();
|
||||
if (navigation_layers == p_navigation_layers) {
|
||||
return;
|
||||
}
|
||||
|
||||
navigation_layers = p_navigation_layers;
|
||||
|
||||
_request_repath();
|
||||
}
|
||||
|
||||
uint32_t NavigationAgent2D::get_navigation_layers() const {
|
||||
|
@ -326,7 +338,12 @@ void NavigationAgent2D::set_path_metadata_flags(BitField<NavigationPathQueryPara
|
|||
}
|
||||
|
||||
void NavigationAgent2D::set_navigation_map(RID p_navigation_map) {
|
||||
if (map_override == p_navigation_map) {
|
||||
return;
|
||||
}
|
||||
|
||||
map_override = p_navigation_map;
|
||||
|
||||
NavigationServer2D::get_singleton()->agent_set_map(agent, map_override);
|
||||
_request_repath();
|
||||
}
|
||||
|
@ -340,41 +357,78 @@ RID NavigationAgent2D::get_navigation_map() const {
|
|||
return RID();
|
||||
}
|
||||
|
||||
void NavigationAgent2D::set_path_desired_distance(real_t p_dd) {
|
||||
path_desired_distance = p_dd;
|
||||
void NavigationAgent2D::set_path_desired_distance(real_t p_path_desired_distance) {
|
||||
if (Math::is_equal_approx(path_desired_distance, p_path_desired_distance)) {
|
||||
return;
|
||||
}
|
||||
|
||||
path_desired_distance = p_path_desired_distance;
|
||||
}
|
||||
|
||||
void NavigationAgent2D::set_target_desired_distance(real_t p_dd) {
|
||||
target_desired_distance = p_dd;
|
||||
void NavigationAgent2D::set_target_desired_distance(real_t p_target_desired_distance) {
|
||||
if (Math::is_equal_approx(target_desired_distance, p_target_desired_distance)) {
|
||||
return;
|
||||
}
|
||||
|
||||
target_desired_distance = p_target_desired_distance;
|
||||
}
|
||||
|
||||
void NavigationAgent2D::set_radius(real_t p_radius) {
|
||||
if (Math::is_equal_approx(radius, p_radius)) {
|
||||
return;
|
||||
}
|
||||
|
||||
radius = p_radius;
|
||||
|
||||
NavigationServer2D::get_singleton()->agent_set_radius(agent, radius);
|
||||
}
|
||||
|
||||
void NavigationAgent2D::set_neighbor_distance(real_t p_distance) {
|
||||
if (Math::is_equal_approx(neighbor_distance, p_distance)) {
|
||||
return;
|
||||
}
|
||||
|
||||
neighbor_distance = p_distance;
|
||||
|
||||
NavigationServer2D::get_singleton()->agent_set_neighbor_distance(agent, neighbor_distance);
|
||||
}
|
||||
|
||||
void NavigationAgent2D::set_max_neighbors(int p_count) {
|
||||
if (max_neighbors == p_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
max_neighbors = p_count;
|
||||
|
||||
NavigationServer2D::get_singleton()->agent_set_max_neighbors(agent, max_neighbors);
|
||||
}
|
||||
|
||||
void NavigationAgent2D::set_time_horizon(real_t p_time) {
|
||||
if (Math::is_equal_approx(time_horizon, p_time)) {
|
||||
return;
|
||||
}
|
||||
|
||||
time_horizon = p_time;
|
||||
|
||||
NavigationServer2D::get_singleton()->agent_set_time_horizon(agent, time_horizon);
|
||||
}
|
||||
|
||||
void NavigationAgent2D::set_max_speed(real_t p_max_speed) {
|
||||
if (Math::is_equal_approx(max_speed, p_max_speed)) {
|
||||
return;
|
||||
}
|
||||
|
||||
max_speed = p_max_speed;
|
||||
|
||||
NavigationServer2D::get_singleton()->agent_set_max_speed(agent, max_speed);
|
||||
}
|
||||
|
||||
void NavigationAgent2D::set_path_max_distance(real_t p_pmd) {
|
||||
path_max_distance = p_pmd;
|
||||
void NavigationAgent2D::set_path_max_distance(real_t p_path_max_distance) {
|
||||
if (Math::is_equal_approx(path_max_distance, p_path_max_distance)) {
|
||||
return;
|
||||
}
|
||||
|
||||
path_max_distance = p_path_max_distance;
|
||||
}
|
||||
|
||||
real_t NavigationAgent2D::get_path_max_distance() {
|
||||
|
@ -382,8 +436,13 @@ real_t NavigationAgent2D::get_path_max_distance() {
|
|||
}
|
||||
|
||||
void NavigationAgent2D::set_target_position(Vector2 p_position) {
|
||||
if (target_position.is_equal_approx(p_position)) {
|
||||
return;
|
||||
}
|
||||
|
||||
target_position = p_position;
|
||||
target_position_submitted = true;
|
||||
|
||||
_request_repath();
|
||||
}
|
||||
|
||||
|
@ -432,10 +491,15 @@ Vector2 NavigationAgent2D::get_final_position() {
|
|||
}
|
||||
|
||||
void NavigationAgent2D::set_velocity(Vector2 p_velocity) {
|
||||
if (target_velocity.is_equal_approx(p_velocity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
target_velocity = p_velocity;
|
||||
velocity_submitted = true;
|
||||
|
||||
NavigationServer2D::get_singleton()->agent_set_target_velocity(agent, target_velocity);
|
||||
NavigationServer2D::get_singleton()->agent_set_velocity(agent, prev_safe_velocity);
|
||||
velocity_submitted = true;
|
||||
}
|
||||
|
||||
void NavigationAgent2D::_avoidance_done(Vector3 p_new_velocity) {
|
||||
|
@ -608,6 +672,10 @@ void NavigationAgent2D::_check_distance_to_target() {
|
|||
|
||||
#ifdef DEBUG_ENABLED
|
||||
void NavigationAgent2D::set_debug_enabled(bool p_enabled) {
|
||||
if (debug_enabled == p_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug_enabled = p_enabled;
|
||||
debug_path_dirty = true;
|
||||
}
|
||||
|
@ -617,6 +685,10 @@ bool NavigationAgent2D::get_debug_enabled() const {
|
|||
}
|
||||
|
||||
void NavigationAgent2D::set_debug_use_custom(bool p_enabled) {
|
||||
if (debug_use_custom == p_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug_use_custom = p_enabled;
|
||||
debug_path_dirty = true;
|
||||
}
|
||||
|
@ -626,6 +698,10 @@ bool NavigationAgent2D::get_debug_use_custom() const {
|
|||
}
|
||||
|
||||
void NavigationAgent2D::set_debug_path_custom_color(Color p_color) {
|
||||
if (debug_path_custom_color == p_color) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug_path_custom_color = p_color;
|
||||
debug_path_dirty = true;
|
||||
}
|
||||
|
@ -635,6 +711,10 @@ Color NavigationAgent2D::get_debug_path_custom_color() const {
|
|||
}
|
||||
|
||||
void NavigationAgent2D::set_debug_path_custom_point_size(float p_point_size) {
|
||||
if (Math::is_equal_approx(debug_path_custom_point_size, p_point_size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug_path_custom_point_size = MAX(0.1, p_point_size);
|
||||
debug_path_dirty = true;
|
||||
}
|
||||
|
@ -644,6 +724,10 @@ float NavigationAgent2D::get_debug_path_custom_point_size() const {
|
|||
}
|
||||
|
||||
void NavigationAgent2D::set_debug_path_custom_line_width(float p_line_width) {
|
||||
if (Math::is_equal_approx(debug_path_custom_line_width, p_line_width)) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug_path_custom_line_width = p_line_width;
|
||||
debug_path_dirty = true;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,6 @@ class NavigationAgent2D : public Node {
|
|||
int max_neighbors = 10;
|
||||
real_t time_horizon = 1.0;
|
||||
real_t max_speed = 100.0;
|
||||
|
||||
real_t path_max_distance = 100.0;
|
||||
|
||||
Vector2 target_position;
|
||||
|
|
|
@ -185,6 +185,10 @@ real_t NavigationObstacle2D::estimate_agent_radius() const {
|
|||
}
|
||||
|
||||
void NavigationObstacle2D::set_agent_parent(Node *p_agent_parent) {
|
||||
if (parent_node2d == p_agent_parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Object::cast_to<Node2D>(p_agent_parent) != nullptr) {
|
||||
parent_node2d = Object::cast_to<Node2D>(p_agent_parent);
|
||||
if (map_override.is_valid()) {
|
||||
|
@ -200,7 +204,12 @@ void NavigationObstacle2D::set_agent_parent(Node *p_agent_parent) {
|
|||
}
|
||||
|
||||
void NavigationObstacle2D::set_navigation_map(RID p_navigation_map) {
|
||||
if (map_override == p_navigation_map) {
|
||||
return;
|
||||
}
|
||||
|
||||
map_override = p_navigation_map;
|
||||
|
||||
NavigationServer2D::get_singleton()->agent_set_map(agent, map_override);
|
||||
}
|
||||
|
||||
|
@ -214,13 +223,23 @@ RID NavigationObstacle2D::get_navigation_map() const {
|
|||
}
|
||||
|
||||
void NavigationObstacle2D::set_estimate_radius(bool p_estimate_radius) {
|
||||
if (estimate_radius == p_estimate_radius) {
|
||||
return;
|
||||
}
|
||||
|
||||
estimate_radius = p_estimate_radius;
|
||||
|
||||
notify_property_list_changed();
|
||||
reevaluate_agent_radius();
|
||||
}
|
||||
|
||||
void NavigationObstacle2D::set_radius(real_t p_radius) {
|
||||
ERR_FAIL_COND_MSG(p_radius <= 0.0, "Radius must be greater than 0.");
|
||||
if (Math::is_equal_approx(radius, p_radius)) {
|
||||
return;
|
||||
}
|
||||
|
||||
radius = p_radius;
|
||||
|
||||
reevaluate_agent_radius();
|
||||
}
|
||||
|
|
|
@ -207,7 +207,7 @@ void NavigationAgent3D::_notification(int p_what) {
|
|||
if (avoidance_enabled) {
|
||||
// agent_position on NavigationServer is avoidance only and has nothing to do with pathfinding
|
||||
// no point in flooding NavigationServer queue with agent position updates that get send to the void if avoidance is not used
|
||||
NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin);
|
||||
NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position());
|
||||
}
|
||||
_check_distance_to_target();
|
||||
}
|
||||
|
@ -222,12 +222,12 @@ void NavigationAgent3D::_notification(int p_what) {
|
|||
|
||||
NavigationAgent3D::NavigationAgent3D() {
|
||||
agent = NavigationServer3D::get_singleton()->agent_create();
|
||||
set_neighbor_distance(50.0);
|
||||
set_max_neighbors(10);
|
||||
set_time_horizon(5.0);
|
||||
set_radius(1.0);
|
||||
set_max_speed(10.0);
|
||||
set_ignore_y(true);
|
||||
NavigationServer3D::get_singleton()->agent_set_neighbor_distance(agent, neighbor_distance);
|
||||
NavigationServer3D::get_singleton()->agent_set_max_neighbors(agent, max_neighbors);
|
||||
NavigationServer3D::get_singleton()->agent_set_time_horizon(agent, time_horizon);
|
||||
NavigationServer3D::get_singleton()->agent_set_radius(agent, radius);
|
||||
NavigationServer3D::get_singleton()->agent_set_max_speed(agent, max_speed);
|
||||
NavigationServer3D::get_singleton()->agent_set_ignore_y(agent, ignore_y);
|
||||
|
||||
// Preallocate query and result objects to improve performance.
|
||||
navigation_query = Ref<NavigationPathQueryParameters3D>();
|
||||
|
@ -260,7 +260,12 @@ NavigationAgent3D::~NavigationAgent3D() {
|
|||
}
|
||||
|
||||
void NavigationAgent3D::set_avoidance_enabled(bool p_enabled) {
|
||||
if (avoidance_enabled == p_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
avoidance_enabled = p_enabled;
|
||||
|
||||
if (avoidance_enabled) {
|
||||
NavigationServer3D::get_singleton()->agent_set_callback(agent, callable_mp(this, &NavigationAgent3D::_avoidance_done));
|
||||
} else {
|
||||
|
@ -273,6 +278,10 @@ bool NavigationAgent3D::get_avoidance_enabled() const {
|
|||
}
|
||||
|
||||
void NavigationAgent3D::set_agent_parent(Node *p_agent_parent) {
|
||||
if (agent_parent == p_agent_parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map
|
||||
NavigationServer3D::get_singleton()->agent_set_callback(agent, Callable());
|
||||
|
||||
|
@ -286,7 +295,9 @@ void NavigationAgent3D::set_agent_parent(Node *p_agent_parent) {
|
|||
}
|
||||
|
||||
// create new avoidance callback if enabled
|
||||
set_avoidance_enabled(avoidance_enabled);
|
||||
if (avoidance_enabled) {
|
||||
NavigationServer3D::get_singleton()->agent_set_callback(agent, callable_mp(this, &NavigationAgent3D::_avoidance_done));
|
||||
}
|
||||
} else {
|
||||
agent_parent = nullptr;
|
||||
NavigationServer3D::get_singleton()->agent_set_map(get_rid(), RID());
|
||||
|
@ -294,11 +305,13 @@ void NavigationAgent3D::set_agent_parent(Node *p_agent_parent) {
|
|||
}
|
||||
|
||||
void NavigationAgent3D::set_navigation_layers(uint32_t p_navigation_layers) {
|
||||
bool navigation_layers_changed = navigation_layers != p_navigation_layers;
|
||||
navigation_layers = p_navigation_layers;
|
||||
if (navigation_layers_changed) {
|
||||
_request_repath();
|
||||
if (navigation_layers == p_navigation_layers) {
|
||||
return;
|
||||
}
|
||||
|
||||
navigation_layers = p_navigation_layers;
|
||||
|
||||
_request_repath();
|
||||
}
|
||||
|
||||
uint32_t NavigationAgent3D::get_navigation_layers() const {
|
||||
|
@ -332,7 +345,12 @@ void NavigationAgent3D::set_path_metadata_flags(BitField<NavigationPathQueryPara
|
|||
}
|
||||
|
||||
void NavigationAgent3D::set_navigation_map(RID p_navigation_map) {
|
||||
if (map_override == p_navigation_map) {
|
||||
return;
|
||||
}
|
||||
|
||||
map_override = p_navigation_map;
|
||||
|
||||
NavigationServer3D::get_singleton()->agent_set_map(agent, map_override);
|
||||
_request_repath();
|
||||
}
|
||||
|
@ -346,50 +364,96 @@ RID NavigationAgent3D::get_navigation_map() const {
|
|||
return RID();
|
||||
}
|
||||
|
||||
void NavigationAgent3D::set_path_desired_distance(real_t p_dd) {
|
||||
path_desired_distance = p_dd;
|
||||
void NavigationAgent3D::set_path_desired_distance(real_t p_path_desired_distance) {
|
||||
if (Math::is_equal_approx(path_desired_distance, p_path_desired_distance)) {
|
||||
return;
|
||||
}
|
||||
|
||||
path_desired_distance = p_path_desired_distance;
|
||||
}
|
||||
|
||||
void NavigationAgent3D::set_target_desired_distance(real_t p_dd) {
|
||||
target_desired_distance = p_dd;
|
||||
void NavigationAgent3D::set_target_desired_distance(real_t p_target_desired_distance) {
|
||||
if (Math::is_equal_approx(target_desired_distance, p_target_desired_distance)) {
|
||||
return;
|
||||
}
|
||||
|
||||
target_desired_distance = p_target_desired_distance;
|
||||
}
|
||||
|
||||
void NavigationAgent3D::set_radius(real_t p_radius) {
|
||||
if (Math::is_equal_approx(radius, p_radius)) {
|
||||
return;
|
||||
}
|
||||
|
||||
radius = p_radius;
|
||||
|
||||
NavigationServer3D::get_singleton()->agent_set_radius(agent, radius);
|
||||
}
|
||||
|
||||
void NavigationAgent3D::set_agent_height_offset(real_t p_hh) {
|
||||
navigation_height_offset = p_hh;
|
||||
void NavigationAgent3D::set_agent_height_offset(real_t p_agent_height_offset) {
|
||||
if (Math::is_equal_approx(navigation_height_offset, p_agent_height_offset)) {
|
||||
return;
|
||||
}
|
||||
|
||||
navigation_height_offset = p_agent_height_offset;
|
||||
}
|
||||
|
||||
void NavigationAgent3D::set_ignore_y(bool p_ignore_y) {
|
||||
if (ignore_y == p_ignore_y) {
|
||||
return;
|
||||
}
|
||||
|
||||
ignore_y = p_ignore_y;
|
||||
|
||||
NavigationServer3D::get_singleton()->agent_set_ignore_y(agent, ignore_y);
|
||||
}
|
||||
|
||||
void NavigationAgent3D::set_neighbor_distance(real_t p_distance) {
|
||||
if (Math::is_equal_approx(neighbor_distance, p_distance)) {
|
||||
return;
|
||||
}
|
||||
|
||||
neighbor_distance = p_distance;
|
||||
|
||||
NavigationServer3D::get_singleton()->agent_set_neighbor_distance(agent, neighbor_distance);
|
||||
}
|
||||
|
||||
void NavigationAgent3D::set_max_neighbors(int p_count) {
|
||||
if (max_neighbors == p_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
max_neighbors = p_count;
|
||||
|
||||
NavigationServer3D::get_singleton()->agent_set_max_neighbors(agent, max_neighbors);
|
||||
}
|
||||
|
||||
void NavigationAgent3D::set_time_horizon(real_t p_time) {
|
||||
if (Math::is_equal_approx(time_horizon, p_time)) {
|
||||
return;
|
||||
}
|
||||
|
||||
time_horizon = p_time;
|
||||
|
||||
NavigationServer3D::get_singleton()->agent_set_time_horizon(agent, time_horizon);
|
||||
}
|
||||
|
||||
void NavigationAgent3D::set_max_speed(real_t p_max_speed) {
|
||||
if (Math::is_equal_approx(max_speed, p_max_speed)) {
|
||||
return;
|
||||
}
|
||||
|
||||
max_speed = p_max_speed;
|
||||
|
||||
NavigationServer3D::get_singleton()->agent_set_max_speed(agent, max_speed);
|
||||
}
|
||||
|
||||
void NavigationAgent3D::set_path_max_distance(real_t p_pmd) {
|
||||
path_max_distance = p_pmd;
|
||||
void NavigationAgent3D::set_path_max_distance(real_t p_path_max_distance) {
|
||||
if (Math::is_equal_approx(path_max_distance, p_path_max_distance)) {
|
||||
return;
|
||||
}
|
||||
|
||||
path_max_distance = p_path_max_distance;
|
||||
}
|
||||
|
||||
real_t NavigationAgent3D::get_path_max_distance() {
|
||||
|
@ -397,8 +461,13 @@ real_t NavigationAgent3D::get_path_max_distance() {
|
|||
}
|
||||
|
||||
void NavigationAgent3D::set_target_position(Vector3 p_position) {
|
||||
if (target_position.is_equal_approx(p_position)) {
|
||||
return;
|
||||
}
|
||||
|
||||
target_position = p_position;
|
||||
target_position_submitted = true;
|
||||
|
||||
_request_repath();
|
||||
}
|
||||
|
||||
|
@ -412,7 +481,7 @@ Vector3 NavigationAgent3D::get_next_path_position() {
|
|||
const Vector<Vector3> &navigation_path = navigation_result->get_path();
|
||||
if (navigation_path.size() == 0) {
|
||||
ERR_FAIL_COND_V_MSG(agent_parent == nullptr, Vector3(), "The agent has no parent.");
|
||||
return agent_parent->get_global_transform().origin;
|
||||
return agent_parent->get_global_position();
|
||||
} else {
|
||||
return navigation_path[navigation_path_index] - Vector3(0, navigation_height_offset, 0);
|
||||
}
|
||||
|
@ -420,7 +489,7 @@ Vector3 NavigationAgent3D::get_next_path_position() {
|
|||
|
||||
real_t NavigationAgent3D::distance_to_target() const {
|
||||
ERR_FAIL_COND_V_MSG(agent_parent == nullptr, 0.0, "The agent has no parent.");
|
||||
return agent_parent->get_global_transform().origin.distance_to(target_position);
|
||||
return agent_parent->get_global_position().distance_to(target_position);
|
||||
}
|
||||
|
||||
bool NavigationAgent3D::is_target_reached() const {
|
||||
|
@ -447,10 +516,15 @@ Vector3 NavigationAgent3D::get_final_position() {
|
|||
}
|
||||
|
||||
void NavigationAgent3D::set_velocity(Vector3 p_velocity) {
|
||||
if (target_velocity.is_equal_approx(p_velocity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
target_velocity = p_velocity;
|
||||
velocity_submitted = true;
|
||||
|
||||
NavigationServer3D::get_singleton()->agent_set_target_velocity(agent, target_velocity);
|
||||
NavigationServer3D::get_singleton()->agent_set_velocity(agent, prev_safe_velocity);
|
||||
velocity_submitted = true;
|
||||
}
|
||||
|
||||
void NavigationAgent3D::_avoidance_done(Vector3 p_new_velocity) {
|
||||
|
@ -491,7 +565,7 @@ void NavigationAgent3D::update_navigation() {
|
|||
|
||||
update_frame_id = Engine::get_singleton()->get_physics_frames();
|
||||
|
||||
Vector3 origin = agent_parent->get_global_transform().origin;
|
||||
Vector3 origin = agent_parent->get_global_position();
|
||||
|
||||
bool reload_path = false;
|
||||
|
||||
|
@ -624,6 +698,10 @@ void NavigationAgent3D::_check_distance_to_target() {
|
|||
|
||||
#ifdef DEBUG_ENABLED
|
||||
void NavigationAgent3D::set_debug_enabled(bool p_enabled) {
|
||||
if (debug_enabled == p_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug_enabled = p_enabled;
|
||||
debug_path_dirty = true;
|
||||
}
|
||||
|
@ -633,6 +711,10 @@ bool NavigationAgent3D::get_debug_enabled() const {
|
|||
}
|
||||
|
||||
void NavigationAgent3D::set_debug_use_custom(bool p_enabled) {
|
||||
if (debug_use_custom == p_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug_use_custom = p_enabled;
|
||||
debug_path_dirty = true;
|
||||
}
|
||||
|
@ -642,6 +724,10 @@ bool NavigationAgent3D::get_debug_use_custom() const {
|
|||
}
|
||||
|
||||
void NavigationAgent3D::set_debug_path_custom_color(Color p_color) {
|
||||
if (debug_path_custom_color == p_color) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug_path_custom_color = p_color;
|
||||
debug_path_dirty = true;
|
||||
}
|
||||
|
@ -651,6 +737,10 @@ Color NavigationAgent3D::get_debug_path_custom_color() const {
|
|||
}
|
||||
|
||||
void NavigationAgent3D::set_debug_path_custom_point_size(float p_point_size) {
|
||||
if (Math::is_equal_approx(debug_path_custom_point_size, p_point_size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug_path_custom_point_size = p_point_size;
|
||||
debug_path_dirty = true;
|
||||
}
|
||||
|
|
|
@ -52,14 +52,13 @@ class NavigationAgent3D : public Node {
|
|||
|
||||
real_t path_desired_distance = 1.0;
|
||||
real_t target_desired_distance = 1.0;
|
||||
real_t radius = 0.0;
|
||||
real_t radius = 1.0;
|
||||
real_t navigation_height_offset = 0.0;
|
||||
bool ignore_y = false;
|
||||
real_t neighbor_distance = 0.0;
|
||||
int max_neighbors = 0;
|
||||
real_t time_horizon = 0.0;
|
||||
real_t max_speed = 0.0;
|
||||
|
||||
bool ignore_y = true;
|
||||
real_t neighbor_distance = 50.0;
|
||||
int max_neighbors = 10;
|
||||
real_t time_horizon = 5.0;
|
||||
real_t max_speed = 10.0;
|
||||
real_t path_max_distance = 3.0;
|
||||
|
||||
Vector3 target_position;
|
||||
|
|
|
@ -192,6 +192,10 @@ real_t NavigationObstacle3D::estimate_agent_radius() const {
|
|||
}
|
||||
|
||||
void NavigationObstacle3D::set_agent_parent(Node *p_agent_parent) {
|
||||
if (parent_node3d == p_agent_parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Object::cast_to<Node3D>(p_agent_parent) != nullptr) {
|
||||
parent_node3d = Object::cast_to<Node3D>(p_agent_parent);
|
||||
if (map_override.is_valid()) {
|
||||
|
@ -207,7 +211,12 @@ void NavigationObstacle3D::set_agent_parent(Node *p_agent_parent) {
|
|||
}
|
||||
|
||||
void NavigationObstacle3D::set_navigation_map(RID p_navigation_map) {
|
||||
if (map_override == p_navigation_map) {
|
||||
return;
|
||||
}
|
||||
|
||||
map_override = p_navigation_map;
|
||||
|
||||
NavigationServer3D::get_singleton()->agent_set_map(agent, map_override);
|
||||
}
|
||||
|
||||
|
@ -221,13 +230,23 @@ RID NavigationObstacle3D::get_navigation_map() const {
|
|||
}
|
||||
|
||||
void NavigationObstacle3D::set_estimate_radius(bool p_estimate_radius) {
|
||||
if (estimate_radius == p_estimate_radius) {
|
||||
return;
|
||||
}
|
||||
|
||||
estimate_radius = p_estimate_radius;
|
||||
|
||||
notify_property_list_changed();
|
||||
reevaluate_agent_radius();
|
||||
}
|
||||
|
||||
void NavigationObstacle3D::set_radius(real_t p_radius) {
|
||||
ERR_FAIL_COND_MSG(p_radius <= 0.0, "Radius must be greater than 0.");
|
||||
if (Math::is_equal_approx(radius, p_radius)) {
|
||||
return;
|
||||
}
|
||||
|
||||
radius = p_radius;
|
||||
|
||||
reevaluate_agent_radius();
|
||||
}
|
||||
|
|
|
@ -2031,7 +2031,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
|
|||
}
|
||||
}
|
||||
if (b->get_button_index() == MouseButton::RIGHT && context_menu_enabled) {
|
||||
_generate_context_menu();
|
||||
_update_context_menu();
|
||||
menu->set_position(get_screen_position() + b->get_position());
|
||||
menu->reset_size();
|
||||
menu->popup();
|
||||
|
@ -2090,7 +2090,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
|
|||
}
|
||||
if (k->is_action("ui_menu", true)) {
|
||||
if (context_menu_enabled) {
|
||||
_generate_context_menu();
|
||||
_update_context_menu();
|
||||
menu->set_position(get_screen_position());
|
||||
menu->reset_size();
|
||||
menu->popup();
|
||||
|
@ -4992,7 +4992,9 @@ bool RichTextLabel::is_shortcut_keys_enabled() const {
|
|||
|
||||
// Context menu.
|
||||
PopupMenu *RichTextLabel::get_menu() const {
|
||||
const_cast<RichTextLabel *>(this)->_generate_context_menu();
|
||||
if (!menu) {
|
||||
const_cast<RichTextLabel *>(this)->_generate_context_menu();
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
|
||||
|
@ -5466,6 +5468,7 @@ void RichTextLabel::_bind_methods() {
|
|||
|
||||
ClassDB::bind_method(D_METHOD("get_menu"), &RichTextLabel::get_menu);
|
||||
ClassDB::bind_method(D_METHOD("is_menu_visible"), &RichTextLabel::is_menu_visible);
|
||||
ClassDB::bind_method(D_METHOD("menu_option", "option"), &RichTextLabel::menu_option);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_thread_end"), &RichTextLabel::_thread_end);
|
||||
|
||||
|
@ -5544,6 +5547,10 @@ void RichTextLabel::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(ITEM_HINT);
|
||||
BIND_ENUM_CONSTANT(ITEM_DROPCAP);
|
||||
BIND_ENUM_CONSTANT(ITEM_CUSTOMFX);
|
||||
|
||||
BIND_ENUM_CONSTANT(MENU_COPY);
|
||||
BIND_ENUM_CONSTANT(MENU_SELECT_ALL);
|
||||
BIND_ENUM_CONSTANT(MENU_MAX);
|
||||
}
|
||||
|
||||
TextServer::VisibleCharactersBehavior RichTextLabel::get_visible_characters_behavior() const {
|
||||
|
@ -5675,19 +5682,32 @@ Size2 RichTextLabel::get_minimum_size() const {
|
|||
|
||||
// Context menu.
|
||||
void RichTextLabel::_generate_context_menu() {
|
||||
menu = memnew(PopupMenu);
|
||||
add_child(menu, false, INTERNAL_MODE_FRONT);
|
||||
menu->connect("id_pressed", callable_mp(this, &RichTextLabel::menu_option));
|
||||
|
||||
menu->add_item(RTR("Copy"), MENU_COPY);
|
||||
menu->add_item(RTR("Select All"), MENU_SELECT_ALL);
|
||||
}
|
||||
|
||||
void RichTextLabel::_update_context_menu() {
|
||||
if (!menu) {
|
||||
menu = memnew(PopupMenu);
|
||||
add_child(menu, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
menu->connect("id_pressed", callable_mp(this, &RichTextLabel::_menu_option));
|
||||
_generate_context_menu();
|
||||
}
|
||||
|
||||
// Reorganize context menu.
|
||||
menu->clear();
|
||||
if (selection.enabled) {
|
||||
menu->add_item(RTR("Copy"), MENU_COPY, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_copy") : Key::NONE);
|
||||
menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_text_select_all") : Key::NONE);
|
||||
int idx = -1;
|
||||
|
||||
#define MENU_ITEM_ACTION_DISABLED(m_menu, m_id, m_action, m_disabled) \
|
||||
idx = m_menu->get_item_index(m_id); \
|
||||
if (idx >= 0) { \
|
||||
m_menu->set_item_accelerator(idx, shortcut_keys_enabled ? _get_menu_action_accelerator(m_action) : Key::NONE); \
|
||||
m_menu->set_item_disabled(idx, m_disabled); \
|
||||
}
|
||||
|
||||
MENU_ITEM_ACTION_DISABLED(menu, MENU_COPY, "ui_copy", !selection.enabled)
|
||||
MENU_ITEM_ACTION_DISABLED(menu, MENU_SELECT_ALL, "ui_text_select_all", !selection.enabled)
|
||||
|
||||
#undef MENU_ITEM_ACTION_DISABLED
|
||||
}
|
||||
|
||||
Key RichTextLabel::_get_menu_action_accelerator(const String &p_action) {
|
||||
|
@ -5715,7 +5735,7 @@ Key RichTextLabel::_get_menu_action_accelerator(const String &p_action) {
|
|||
}
|
||||
}
|
||||
|
||||
void RichTextLabel::_menu_option(int p_option) {
|
||||
void RichTextLabel::menu_option(int p_option) {
|
||||
switch (p_option) {
|
||||
case MENU_COPY: {
|
||||
selection_copy();
|
||||
|
|
|
@ -81,6 +81,7 @@ public:
|
|||
enum MenuItems {
|
||||
MENU_COPY,
|
||||
MENU_SELECT_ALL,
|
||||
MENU_MAX
|
||||
};
|
||||
|
||||
enum DefaultFont {
|
||||
|
@ -454,8 +455,8 @@ private:
|
|||
// Context menu.
|
||||
PopupMenu *menu = nullptr;
|
||||
void _generate_context_menu();
|
||||
void _update_context_menu();
|
||||
Key _get_menu_action_accelerator(const String &p_action);
|
||||
void _menu_option(int p_option);
|
||||
|
||||
int visible_characters = -1;
|
||||
float visible_ratio = 1.0;
|
||||
|
@ -688,6 +689,7 @@ public:
|
|||
// Context menu.
|
||||
PopupMenu *get_menu() const;
|
||||
bool is_menu_visible() const;
|
||||
void menu_option(int p_option);
|
||||
|
||||
void parse_bbcode(const String &p_bbcode);
|
||||
void append_text(const String &p_bbcode);
|
||||
|
@ -739,5 +741,6 @@ public:
|
|||
|
||||
VARIANT_ENUM_CAST(RichTextLabel::ListType);
|
||||
VARIANT_ENUM_CAST(RichTextLabel::ItemType);
|
||||
VARIANT_ENUM_CAST(RichTextLabel::MenuItems);
|
||||
|
||||
#endif // RICH_TEXT_LABEL_H
|
||||
|
|
|
@ -1062,6 +1062,10 @@ void Viewport::assign_next_enabled_camera_2d(const StringName &p_camera_group) {
|
|||
Camera2D *new_camera = nullptr;
|
||||
for (Node *E : camera_list) {
|
||||
Camera2D *cam = Object::cast_to<Camera2D>(E);
|
||||
if (!cam) {
|
||||
continue; // Non-camera node (e.g. ParallaxBackground).
|
||||
}
|
||||
|
||||
if (cam->is_enabled()) {
|
||||
new_camera = cam;
|
||||
break;
|
||||
|
|
|
@ -815,6 +815,8 @@ void VisualShader::remove_node(Type p_type, int p_id) {
|
|||
if (E->get().from_node == p_id) {
|
||||
g->nodes[E->get().to_node].prev_connected_nodes.erase(p_id);
|
||||
g->nodes[E->get().to_node].node->set_input_port_connected(E->get().to_port, false);
|
||||
} else if (E->get().to_node == p_id) {
|
||||
g->nodes[E->get().from_node].next_connected_nodes.erase(p_id);
|
||||
}
|
||||
}
|
||||
E = N;
|
||||
|
@ -981,6 +983,7 @@ void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from
|
|||
c.to_node = p_to_node;
|
||||
c.to_port = p_to_port;
|
||||
g->connections.push_back(c);
|
||||
g->nodes[p_from_node].next_connected_nodes.push_back(p_to_node);
|
||||
g->nodes[p_to_node].prev_connected_nodes.push_back(p_from_node);
|
||||
g->nodes[p_from_node].node->set_output_port_connected(p_from_port, true);
|
||||
g->nodes[p_to_node].node->set_input_port_connected(p_to_port, true);
|
||||
|
@ -1014,6 +1017,7 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port,
|
|||
c.to_node = p_to_node;
|
||||
c.to_port = p_to_port;
|
||||
g->connections.push_back(c);
|
||||
g->nodes[p_from_node].next_connected_nodes.push_back(p_to_node);
|
||||
g->nodes[p_to_node].prev_connected_nodes.push_back(p_from_node);
|
||||
g->nodes[p_from_node].node->set_output_port_connected(p_from_port, true);
|
||||
g->nodes[p_to_node].node->set_input_port_connected(p_to_port, true);
|
||||
|
@ -1029,6 +1033,7 @@ void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_por
|
|||
for (const List<Connection>::Element *E = g->connections.front(); E; E = E->next()) {
|
||||
if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) {
|
||||
g->connections.erase(E);
|
||||
g->nodes[p_from_node].next_connected_nodes.erase(p_to_node);
|
||||
g->nodes[p_to_node].prev_connected_nodes.erase(p_from_node);
|
||||
g->nodes[p_from_node].node->set_output_port_connected(p_from_port, false);
|
||||
g->nodes[p_to_node].node->set_input_port_connected(p_to_port, false);
|
||||
|
|
|
@ -122,7 +122,8 @@ private:
|
|||
struct Node {
|
||||
Ref<VisualShaderNode> node;
|
||||
Vector2 position;
|
||||
List<int> prev_connected_nodes;
|
||||
LocalVector<int> prev_connected_nodes;
|
||||
LocalVector<int> next_connected_nodes;
|
||||
};
|
||||
|
||||
struct Graph {
|
||||
|
@ -199,6 +200,16 @@ public: // internal methods
|
|||
Vector2 get_node_position(Type p_type, int p_id) const;
|
||||
Ref<VisualShaderNode> get_node(Type p_type, int p_id) const;
|
||||
|
||||
_FORCE_INLINE_ Ref<VisualShaderNode> get_node_unchecked(Type p_type, int p_id) const {
|
||||
return graph[p_type].nodes[p_id].node;
|
||||
}
|
||||
_FORCE_INLINE_ void get_next_connected_nodes(Type p_type, int p_id, LocalVector<int> &r_list) const {
|
||||
r_list = graph[p_type].nodes[p_id].next_connected_nodes;
|
||||
}
|
||||
_FORCE_INLINE_ void get_prev_connected_nodes(Type p_type, int p_id, LocalVector<int> &r_list) const {
|
||||
r_list = graph[p_type].nodes[p_id].prev_connected_nodes;
|
||||
}
|
||||
|
||||
Vector<int> get_node_list(Type p_type) const;
|
||||
int get_valid_node_id(Type p_type) const;
|
||||
|
||||
|
|
Loading…
Reference in a new issue