mirror of
https://github.com/Redot-Engine/redot-engine.git
synced 2025-12-06 07:17:42 -05:00
Merge commit godotengine/godot@1bbfe637c6
This commit is contained in:
@@ -178,21 +178,21 @@ Comment: Temporal Anti-Aliasing resolve implementation
|
|||||||
Copyright: 2016, Panos Karabelas
|
Copyright: 2016, Panos Karabelas
|
||||||
License: Expat
|
License: Expat
|
||||||
|
|
||||||
Files: thirdparty/accesskit/*
|
|
||||||
Comment: AccessKit
|
|
||||||
Copyright: 2023, The AccessKit Authors.
|
|
||||||
License: Expat
|
|
||||||
|
|
||||||
Files: servers/rendering/renderer_rd/shaders/smaa_blending.glsl
|
Files: servers/rendering/renderer_rd/shaders/smaa_blending.glsl
|
||||||
servers/rendering/renderer_rd/shaders/smaa_weight_calculation.glsl
|
servers/rendering/renderer_rd/shaders/smaa_weight_calculation.glsl
|
||||||
servers/rendering/renderer_rd/shaders/smaa_edge_detection.glsl
|
servers/rendering/renderer_rd/shaders/smaa_edge_detection.glsl
|
||||||
thirdparty/smaa/*
|
thirdparty/smaa/*
|
||||||
Comment: Subpixel Morphological Antialiasing
|
Comment: Subpixel Morphological Antialiasing
|
||||||
Copyright: 2013 Jorge Jimenez (jorge@iryoku.com)
|
Copyright: 2013, Jorge Jimenez
|
||||||
2013 Jose I. Echevarria (joseignacioechevarria@gmail.com)
|
2013, Jose I. Echevarria
|
||||||
2013 Belen Masia (bmasia@unizar.es)
|
2013, Belen Masia
|
||||||
2013 Fernando Navarro (fernandn@microsoft.com)
|
2013, Fernando Navarro
|
||||||
2013 Diego Gutierrez (diegog@unizar.es)
|
2013, Diego Gutierrez
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: thirdparty/accesskit/*
|
||||||
|
Comment: AccessKit
|
||||||
|
Copyright: 2023, The AccessKit Authors.
|
||||||
License: Expat
|
License: Expat
|
||||||
|
|
||||||
Files: thirdparty/amd-fsr/*
|
Files: thirdparty/amd-fsr/*
|
||||||
@@ -319,7 +319,7 @@ Comment: Graphite engine
|
|||||||
Copyright: 2010, SIL International
|
Copyright: 2010, SIL International
|
||||||
License: Expat
|
License: Expat
|
||||||
|
|
||||||
Files: thirdparty/grisu2/grisu2.h
|
Files: thirdparty/grisu2/*
|
||||||
Comment: Grisu2 float serialization algorithm
|
Comment: Grisu2 float serialization algorithm
|
||||||
Copyright: 2009, Florian Loitsch
|
Copyright: 2009, Florian Loitsch
|
||||||
2018-2023, The simdjson authors
|
2018-2023, The simdjson authors
|
||||||
@@ -531,7 +531,7 @@ License: BSD-2-clause
|
|||||||
|
|
||||||
Files: thirdparty/msdfgen/*
|
Files: thirdparty/msdfgen/*
|
||||||
Comment: Multi-channel signed distance field generator
|
Comment: Multi-channel signed distance field generator
|
||||||
Copyright: 2014-2024, Viktor Chlumsky
|
Copyright: 2014-2025, Viktor Chlumsky
|
||||||
License: Expat
|
License: Expat
|
||||||
|
|
||||||
Files: thirdparty/openxr/*
|
Files: thirdparty/openxr/*
|
||||||
@@ -565,6 +565,11 @@ Comment: SPIRV-Reflect
|
|||||||
Copyright: 2017-2022, Google Inc.
|
Copyright: 2017-2022, Google Inc.
|
||||||
License: Apache-2.0
|
License: Apache-2.0
|
||||||
|
|
||||||
|
Files: thirdparty/swappy-frame-pacing/*
|
||||||
|
Comment: Swappy
|
||||||
|
Copyright: 2019, The Android Open Source Project
|
||||||
|
License: Apache-2.0
|
||||||
|
|
||||||
Files: thirdparty/thorvg/*
|
Files: thirdparty/thorvg/*
|
||||||
Comment: ThorVG
|
Comment: ThorVG
|
||||||
Copyright: 2020-2024, The ThorVG Project
|
Copyright: 2020-2024, The ThorVG Project
|
||||||
@@ -613,15 +618,15 @@ Copyright: 2008-2012, Kristian Høgsberg
|
|||||||
License: Expat
|
License: Expat
|
||||||
|
|
||||||
Files: thirdparty/wayland-protocols/*
|
Files: thirdparty/wayland-protocols/*
|
||||||
Comment: Wayland protocols that add functionality not available in the core protocol
|
Comment: Wayland protocols
|
||||||
Copyright: 2008-2013, Kristian Høgsberg
|
Copyright: 2008-2013, Kristian Høgsberg
|
||||||
2010-2013, Intel Corporation
|
2010-2013, Intel Corporation
|
||||||
2013, Rafael Antognolli
|
2013, Rafael Antognolli
|
||||||
2013, Jasper St. Pierre
|
2013, Jasper St. Pierre
|
||||||
2014, Jonas Ådahl
|
2014, Jonas Ådahl
|
||||||
2014, Jason Ekstrand
|
2014, Jason Ekstrand
|
||||||
2014-2015, Collabora, Ltd.
|
2014-2015, Collabora, Ltd.
|
||||||
2015, Red Hat Inc.
|
2015, Red Hat Inc.
|
||||||
License: Expat
|
License: Expat
|
||||||
|
|
||||||
Files: thirdparty/wslay/*
|
Files: thirdparty/wslay/*
|
||||||
|
|||||||
@@ -185,9 +185,15 @@ gen_hash = env.CommandNoCache(
|
|||||||
env.add_source_files(env.core_sources, gen_hash)
|
env.add_source_files(env.core_sources, gen_hash)
|
||||||
|
|
||||||
# Generate AES256 script encryption key
|
# Generate AES256 script encryption key
|
||||||
|
encryption_key = os.environ.get("SCRIPT_AES256_ENCRYPTION_KEY")
|
||||||
|
if encryption_key:
|
||||||
|
print(
|
||||||
|
"\n*** IMPORTANT: Compiling Godot with custom `SCRIPT_AES256_ENCRYPTION_KEY` set as environment variable."
|
||||||
|
"\n*** Make sure to use templates compiled with this key when exporting a project with encryption.\n"
|
||||||
|
)
|
||||||
gen_encrypt = env.CommandNoCache(
|
gen_encrypt = env.CommandNoCache(
|
||||||
"script_encryption_key.gen.cpp",
|
"script_encryption_key.gen.cpp",
|
||||||
env.Value(os.environ.get("SCRIPT_AES256_ENCRYPTION_KEY")),
|
env.Value(encryption_key),
|
||||||
env.Run(core_builders.encryption_key_builder),
|
env.Run(core_builders.encryption_key_builder),
|
||||||
)
|
)
|
||||||
env.add_source_files(env.core_sources, gen_encrypt)
|
env.add_source_files(env.core_sources, gen_encrypt)
|
||||||
|
|||||||
@@ -1710,6 +1710,7 @@ ProjectSettings::ProjectSettings() {
|
|||||||
|
|
||||||
#if !defined(NAVIGATION_2D_DISABLED) || !defined(NAVIGATION_3D_DISABLED)
|
#if !defined(NAVIGATION_2D_DISABLED) || !defined(NAVIGATION_3D_DISABLED)
|
||||||
GLOBAL_DEF("navigation/world/map_use_async_iterations", true);
|
GLOBAL_DEF("navigation/world/map_use_async_iterations", true);
|
||||||
|
GLOBAL_DEF("navigation/world/region_use_async_iterations", true);
|
||||||
|
|
||||||
GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_multiple_threads", true);
|
GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_multiple_threads", true);
|
||||||
GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_high_priority_threads", true);
|
GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_high_priority_threads", true);
|
||||||
|
|||||||
@@ -364,7 +364,7 @@ void LocalDebugger::send_message(const String &p_message, const Array &p_args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LocalDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type) {
|
void LocalDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type) {
|
||||||
print_line("ERROR: '" + (p_descr.is_empty() ? p_err : p_descr) + "'");
|
_err_print_error(p_func.utf8().get_data(), p_file.utf8().get_data(), p_line, p_err, p_descr, p_editor_notify, p_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalDebugger::LocalDebugger() {
|
LocalDebugger::LocalDebugger() {
|
||||||
|
|||||||
@@ -546,25 +546,60 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PackedStringArray input_names;
|
||||||
|
Array input_vals;
|
||||||
|
|
||||||
List<String> locals;
|
List<String> locals;
|
||||||
List<Variant> local_vals;
|
List<Variant> local_vals;
|
||||||
|
|
||||||
script_debugger->get_break_language()->debug_get_stack_level_locals(frame, &locals, &local_vals);
|
script_debugger->get_break_language()->debug_get_stack_level_locals(frame, &locals, &local_vals);
|
||||||
ERR_FAIL_COND(locals.size() != local_vals.size());
|
ERR_FAIL_COND(locals.size() != local_vals.size());
|
||||||
|
|
||||||
PackedStringArray locals_vector;
|
|
||||||
for (const String &S : locals) {
|
for (const String &S : locals) {
|
||||||
locals_vector.append(S);
|
input_names.append(S);
|
||||||
}
|
}
|
||||||
|
|
||||||
Array local_vals_array;
|
|
||||||
for (const Variant &V : local_vals) {
|
for (const Variant &V : local_vals) {
|
||||||
local_vals_array.append(V);
|
input_vals.append(V);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> globals;
|
||||||
|
List<Variant> globals_vals;
|
||||||
|
script_debugger->get_break_language()->debug_get_globals(&globals, &globals_vals);
|
||||||
|
ERR_FAIL_COND(globals.size() != globals_vals.size());
|
||||||
|
|
||||||
|
for (const String &S : globals) {
|
||||||
|
input_names.append(S);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const Variant &V : globals_vals) {
|
||||||
|
input_vals.append(V);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<StringName> native_types;
|
||||||
|
ClassDB::get_class_list(&native_types);
|
||||||
|
for (const StringName &E : native_types) {
|
||||||
|
if (!ClassDB::is_class_exposed(E) || !Engine::get_singleton()->has_singleton(E) || Engine::get_singleton()->is_singleton_editor_only(E)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
input_names.append(E);
|
||||||
|
input_vals.append(Engine::get_singleton()->get_singleton_object(E));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<StringName> user_types;
|
||||||
|
ScriptServer::get_global_class_list(&user_types);
|
||||||
|
for (const StringName &S : user_types) {
|
||||||
|
String scr_path = ScriptServer::get_global_class_path(S);
|
||||||
|
Ref<Script> scr = ResourceLoader::load(scr_path, "Script");
|
||||||
|
ERR_CONTINUE_MSG(scr.is_null(), vformat(R"(Could not load the global class %s from resource path: "%s".)", S, scr_path));
|
||||||
|
|
||||||
|
input_names.append(S);
|
||||||
|
input_vals.append(scr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression expression;
|
Expression expression;
|
||||||
expression.parse(expression_str, locals_vector);
|
expression.parse(expression_str, input_names);
|
||||||
const Variant return_val = expression.execute(local_vals_array, breaked_instance->get_owner());
|
const Variant return_val = expression.execute(input_vals, breaked_instance->get_owner());
|
||||||
|
|
||||||
DebuggerMarshalls::ScriptStackVariable stvar;
|
DebuggerMarshalls::ScriptStackVariable stvar;
|
||||||
stvar.name = expression_str;
|
stvar.name = expression_str;
|
||||||
|
|||||||
@@ -109,6 +109,8 @@ public:
|
|||||||
bool is_experimental = false;
|
bool is_experimental = false;
|
||||||
String experimental_message;
|
String experimental_message;
|
||||||
Vector<ArgumentDoc> arguments;
|
Vector<ArgumentDoc> arguments;
|
||||||
|
// NOTE: Only for GDScript for now. The rest argument is not saved to the XML file.
|
||||||
|
ArgumentDoc rest_argument;
|
||||||
Vector<int> errors_returned;
|
Vector<int> errors_returned;
|
||||||
String keywords;
|
String keywords;
|
||||||
bool operator<(const MethodDoc &p_method) const {
|
bool operator<(const MethodDoc &p_method) const {
|
||||||
|
|||||||
@@ -98,10 +98,11 @@ void _err_print_error(const char *p_function, const char *p_file, int p_line, co
|
|||||||
} else {
|
} else {
|
||||||
// Fallback if errors happen before OS init or after it's destroyed.
|
// Fallback if errors happen before OS init or after it's destroyed.
|
||||||
const char *err_details = (p_message && *p_message) ? p_message : p_error;
|
const char *err_details = (p_message && *p_message) ? p_message : p_error;
|
||||||
fprintf(stderr, "ERROR: %s\n at: %s (%s:%i)\n", err_details, p_function, p_file, p_line);
|
fprintf(stderr, "%s: %s\n at: %s (%s:%i)\n", _error_handler_type_string(p_type), err_details, p_function, p_file, p_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
_global_lock();
|
_global_lock();
|
||||||
|
|
||||||
ErrorHandlerList *l = error_handler_list;
|
ErrorHandlerList *l = error_handler_list;
|
||||||
while (l) {
|
while (l) {
|
||||||
l->errfunc(l->userdata, p_function, p_file, p_line, p_error, p_message, p_editor_notify, p_type);
|
l->errfunc(l->userdata, p_function, p_file, p_line, p_error, p_message, p_editor_notify, p_type);
|
||||||
@@ -115,18 +116,20 @@ void _err_print_error(const char *p_function, const char *p_file, int p_line, co
|
|||||||
// but we don't want to make it noisy by printing lots of file & line info (because it's already
|
// but we don't want to make it noisy by printing lots of file & line info (because it's already
|
||||||
// been printing by a preceding _err_print_error).
|
// been printing by a preceding _err_print_error).
|
||||||
void _err_print_error_asap(const String &p_error, ErrorHandlerType p_type) {
|
void _err_print_error_asap(const String &p_error, ErrorHandlerType p_type) {
|
||||||
|
const char *err_details = p_error.utf8().get_data();
|
||||||
|
|
||||||
if (OS::get_singleton()) {
|
if (OS::get_singleton()) {
|
||||||
OS::get_singleton()->printerr("ERROR: %s\n", p_error.utf8().get_data());
|
OS::get_singleton()->printerr("%s: %s\n", _error_handler_type_string(p_type), err_details);
|
||||||
} else {
|
} else {
|
||||||
// Fallback if errors happen before OS init or after it's destroyed.
|
// Fallback if errors happen before OS init or after it's destroyed.
|
||||||
const char *err_details = p_error.utf8().get_data();
|
fprintf(stderr, "%s: %s\n", _error_handler_type_string(p_type), err_details);
|
||||||
fprintf(stderr, "ERROR: %s\n", err_details);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_global_lock();
|
_global_lock();
|
||||||
|
|
||||||
ErrorHandlerList *l = error_handler_list;
|
ErrorHandlerList *l = error_handler_list;
|
||||||
while (l) {
|
while (l) {
|
||||||
l->errfunc(l->userdata, "", "", 0, p_error.utf8().get_data(), "", false, p_type);
|
l->errfunc(l->userdata, "", "", 0, err_details, "", false, p_type);
|
||||||
l = l->next;
|
l = l->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,20 @@ enum ErrorHandlerType {
|
|||||||
ERR_HANDLER_SHADER,
|
ERR_HANDLER_SHADER,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr const char *_error_handler_type_string(ErrorHandlerType p_type) {
|
||||||
|
switch (p_type) {
|
||||||
|
case ERR_HANDLER_ERROR:
|
||||||
|
return "ERROR";
|
||||||
|
case ERR_HANDLER_WARNING:
|
||||||
|
return "WARNING";
|
||||||
|
case ERR_HANDLER_SCRIPT:
|
||||||
|
return "SCRIPT ERROR";
|
||||||
|
case ERR_HANDLER_SHADER:
|
||||||
|
return "SHADER ERROR";
|
||||||
|
}
|
||||||
|
return "UNKNOWN ERROR";
|
||||||
|
}
|
||||||
|
|
||||||
// Pointer to the error handler printing function. Reassign to any function to have errors printed.
|
// Pointer to the error handler printing function. Reassign to any function to have errors printed.
|
||||||
// Parameters: userdata, function, file, line, error, explanation, type.
|
// Parameters: userdata, function, file, line, error, explanation, type.
|
||||||
typedef void (*ErrorHandlerFunc)(void *, const char *, const char *, int p_line, const char *, const char *, bool p_editor_notify, ErrorHandlerType p_type);
|
typedef void (*ErrorHandlerFunc)(void *, const char *, const char *, int p_line, const char *, const char *, bool p_editor_notify, ErrorHandlerType p_type);
|
||||||
|
|||||||
@@ -412,8 +412,16 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (self->reloadable && p_extension_funcs->recreate_instance_func == nullptr) {
|
if (self->reloadable && p_extension_funcs->recreate_instance_func == nullptr) {
|
||||||
ERR_PRINT(vformat("Extension marked as reloadable, but attempted to register class '%s' which doesn't support reloading. Perhaps your language binding don't support it? Reloading disabled for this extension.", class_name));
|
bool can_create_class = (bool)p_extension_funcs->create_instance_func;
|
||||||
self->reloadable = false;
|
#ifndef DISABLE_DEPRECATED
|
||||||
|
if (!can_create_class && p_deprecated_funcs) {
|
||||||
|
can_create_class = (bool)p_deprecated_funcs->create_instance_func;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (can_create_class) {
|
||||||
|
ERR_PRINT(vformat("Extension marked as reloadable, but attempted to register class '%s' which doesn't support reloading. Perhaps your language binding don't support it? Reloading disabled for this extension.", class_name));
|
||||||
|
self->reloadable = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension->gdextension.library = self;
|
extension->gdextension.library = self;
|
||||||
@@ -688,6 +696,13 @@ void GDExtension::_register_get_classes_used_callback(GDExtensionClassLibraryPtr
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GDExtension::_register_main_loop_callbacks(GDExtensionClassLibraryPtr p_library, const GDExtensionMainLoopCallbacks *p_callbacks) {
|
||||||
|
GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
|
||||||
|
self->startup_callback = p_callbacks->startup_func;
|
||||||
|
self->shutdown_callback = p_callbacks->shutdown_func;
|
||||||
|
self->frame_callback = p_callbacks->frame_func;
|
||||||
|
}
|
||||||
|
|
||||||
void GDExtension::register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) {
|
void GDExtension::register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) {
|
||||||
ERR_FAIL_COND_MSG(gdextension_interface_functions.has(p_function_name), vformat("Attempt to register interface function '%s', which appears to be already registered.", p_function_name));
|
ERR_FAIL_COND_MSG(gdextension_interface_functions.has(p_function_name), vformat("Attempt to register interface function '%s', which appears to be already registered.", p_function_name));
|
||||||
gdextension_interface_functions.insert(p_function_name, p_function_pointer);
|
gdextension_interface_functions.insert(p_function_name, p_function_pointer);
|
||||||
@@ -807,6 +822,7 @@ void GDExtension::initialize_gdextensions() {
|
|||||||
register_interface_function("classdb_unregister_extension_class", (GDExtensionInterfaceFunctionPtr)&GDExtension::_unregister_extension_class);
|
register_interface_function("classdb_unregister_extension_class", (GDExtensionInterfaceFunctionPtr)&GDExtension::_unregister_extension_class);
|
||||||
register_interface_function("get_library_path", (GDExtensionInterfaceFunctionPtr)&GDExtension::_get_library_path);
|
register_interface_function("get_library_path", (GDExtensionInterfaceFunctionPtr)&GDExtension::_get_library_path);
|
||||||
register_interface_function("editor_register_get_classes_used_callback", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_get_classes_used_callback);
|
register_interface_function("editor_register_get_classes_used_callback", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_get_classes_used_callback);
|
||||||
|
register_interface_function("register_main_loop_callbacks", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_main_loop_callbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GDExtension::finalize_gdextensions() {
|
void GDExtension::finalize_gdextensions() {
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ class GDExtension : public Resource {
|
|||||||
static void _unregister_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name);
|
static void _unregister_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name);
|
||||||
static void _get_library_path(GDExtensionClassLibraryPtr p_library, GDExtensionStringPtr r_path);
|
static void _get_library_path(GDExtensionClassLibraryPtr p_library, GDExtensionStringPtr r_path);
|
||||||
static void _register_get_classes_used_callback(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback);
|
static void _register_get_classes_used_callback(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback);
|
||||||
|
static void _register_main_loop_callbacks(GDExtensionClassLibraryPtr p_library, const GDExtensionMainLoopCallbacks *p_callbacks);
|
||||||
|
|
||||||
GDExtensionInitialization initialization;
|
GDExtensionInitialization initialization;
|
||||||
int32_t level_initialized = -1;
|
int32_t level_initialized = -1;
|
||||||
@@ -117,6 +118,10 @@ class GDExtension : public Resource {
|
|||||||
void clear_instance_bindings();
|
void clear_instance_bindings();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
GDExtensionMainLoopStartupCallback startup_callback = nullptr;
|
||||||
|
GDExtensionMainLoopShutdownCallback shutdown_callback = nullptr;
|
||||||
|
GDExtensionMainLoopFrameCallback frame_callback = nullptr;
|
||||||
|
|
||||||
static inline HashMap<StringName, GDExtensionInterfaceFunctionPtr> gdextension_interface_functions;
|
static inline HashMap<StringName, GDExtensionInterfaceFunctionPtr> gdextension_interface_functions;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -820,6 +820,21 @@ typedef struct {
|
|||||||
const char *string; // (e.g. "Redot v3.1.4.stable.official.mono")
|
const char *string; // (e.g. "Redot v3.1.4.stable.official.mono")
|
||||||
} GDExtensionRedotVersion;
|
} GDExtensionRedotVersion;
|
||||||
|
|
||||||
|
/* Called when starting the main loop. */
|
||||||
|
typedef void (*GDExtensionMainLoopStartupCallback)();
|
||||||
|
|
||||||
|
/* Called when shutting down the main loop. */
|
||||||
|
typedef void (*GDExtensionMainLoopShutdownCallback)();
|
||||||
|
|
||||||
|
/* Called for every frame iteration of the main loop. */
|
||||||
|
typedef void (*GDExtensionMainLoopFrameCallback)();
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GDExtensionMainLoopStartupCallback startup_func;
|
||||||
|
GDExtensionMainLoopShutdownCallback shutdown_func;
|
||||||
|
GDExtensionMainLoopFrameCallback frame_func;
|
||||||
|
} GDExtensionMainLoopCallbacks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name get_godot_version
|
* @name get_godot_version
|
||||||
* @since 4.1
|
* @since 4.1
|
||||||
@@ -3157,6 +3172,17 @@ typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen)(const
|
|||||||
*/
|
*/
|
||||||
typedef void (*GDExtensionInterfaceEditorRegisterGetClassesUsedCallback)(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback);
|
typedef void (*GDExtensionInterfaceEditorRegisterGetClassesUsedCallback)(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name register_main_loop_callbacks
|
||||||
|
* @since 4.5
|
||||||
|
*
|
||||||
|
* Registers callbacks to be called at different phases of the main loop.
|
||||||
|
*
|
||||||
|
* @param p_library A pointer the library received by the GDExtension's entry point function.
|
||||||
|
* @param p_callback A pointer to the structure that contains the callbacks.
|
||||||
|
*/
|
||||||
|
typedef void (*GDExtensionInterfaceRegisterMainLoopCallbacks)(GDExtensionClassLibraryPtr p_library, const GDExtensionMainLoopCallbacks *p_callbacks);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -62,6 +62,14 @@ GDExtensionManager::LoadStatus GDExtensionManager::_load_extension_internal(cons
|
|||||||
emit_signal("extension_loaded", p_extension);
|
emit_signal("extension_loaded", p_extension);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (startup_callback_called) {
|
||||||
|
// Extension is loading after the startup callback has already been called,
|
||||||
|
// so we call it now for this extension to make sure it doesn't miss it.
|
||||||
|
if (p_extension->startup_callback) {
|
||||||
|
p_extension->startup_callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return LOAD_STATUS_OK;
|
return LOAD_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,10 +86,24 @@ GDExtensionManager::LoadStatus GDExtensionManager::_unload_extension_internal(co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!shutdown_callback_called) {
|
||||||
|
// Extension is unloading before the shutdown callback has been called,
|
||||||
|
// which means the engine hasn't shutdown yet but we want to make sure
|
||||||
|
// to call the shutdown callback so it doesn't miss it.
|
||||||
|
if (p_extension->shutdown_callback) {
|
||||||
|
p_extension->shutdown_callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const KeyValue<String, String> &kv : p_extension->class_icon_paths) {
|
for (const KeyValue<String, String> &kv : p_extension->class_icon_paths) {
|
||||||
gdextension_class_icon_paths.erase(kv.key);
|
gdextension_class_icon_paths.erase(kv.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear main loop callbacks.
|
||||||
|
p_extension->startup_callback = nullptr;
|
||||||
|
p_extension->shutdown_callback = nullptr;
|
||||||
|
p_extension->frame_callback = nullptr;
|
||||||
|
|
||||||
return LOAD_STATUS_OK;
|
return LOAD_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,6 +411,37 @@ bool GDExtensionManager::ensure_extensions_loaded(const HashSet<String> &p_exten
|
|||||||
return needs_restart;
|
return needs_restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GDExtensionManager::startup() {
|
||||||
|
startup_callback_called = true;
|
||||||
|
|
||||||
|
for (const KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
|
||||||
|
const Ref<GDExtension> &extension = E.value;
|
||||||
|
if (extension->startup_callback) {
|
||||||
|
extension->startup_callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GDExtensionManager::shutdown() {
|
||||||
|
shutdown_callback_called = true;
|
||||||
|
|
||||||
|
for (const KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
|
||||||
|
const Ref<GDExtension> &extension = E.value;
|
||||||
|
if (extension->shutdown_callback) {
|
||||||
|
extension->shutdown_callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GDExtensionManager::frame() {
|
||||||
|
for (const KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
|
||||||
|
const Ref<GDExtension> &extension = E.value;
|
||||||
|
if (extension->frame_callback) {
|
||||||
|
extension->frame_callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GDExtensionManager *GDExtensionManager::get_singleton() {
|
GDExtensionManager *GDExtensionManager::get_singleton() {
|
||||||
return singleton;
|
return singleton;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ class GDExtensionManager : public Object {
|
|||||||
HashMap<String, Ref<GDExtension>> gdextension_map;
|
HashMap<String, Ref<GDExtension>> gdextension_map;
|
||||||
HashMap<String, String> gdextension_class_icon_paths;
|
HashMap<String, String> gdextension_class_icon_paths;
|
||||||
|
|
||||||
|
bool startup_callback_called = false;
|
||||||
|
bool shutdown_callback_called = false;
|
||||||
|
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
static inline GDExtensionManager *singleton = nullptr;
|
static inline GDExtensionManager *singleton = nullptr;
|
||||||
@@ -88,6 +91,10 @@ public:
|
|||||||
void reload_extensions();
|
void reload_extensions();
|
||||||
bool ensure_extensions_loaded(const HashSet<String> &p_extensions);
|
bool ensure_extensions_loaded(const HashSet<String> &p_extensions);
|
||||||
|
|
||||||
|
void startup();
|
||||||
|
void shutdown();
|
||||||
|
void frame();
|
||||||
|
|
||||||
GDExtensionManager();
|
GDExtensionManager();
|
||||||
~GDExtensionManager();
|
~GDExtensionManager();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -333,86 +333,86 @@ struct _BuiltinActionDisplayName {
|
|||||||
|
|
||||||
static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
|
static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
{ "ui_accept", TTRC("Accept") },
|
{ "ui_accept", TTRC("Accept") },
|
||||||
{ "ui_select", TTRC("Select") },
|
{ "ui_select", TTRC("Select") },
|
||||||
{ "ui_cancel", TTRC("Cancel") },
|
{ "ui_cancel", TTRC("Cancel") },
|
||||||
{ "ui_focus_next", TTRC("Focus Next") },
|
{ "ui_focus_next", TTRC("Focus Next") },
|
||||||
{ "ui_focus_prev", TTRC("Focus Prev") },
|
{ "ui_focus_prev", TTRC("Focus Prev") },
|
||||||
{ "ui_left", TTRC("Left") },
|
{ "ui_left", TTRC("Left") },
|
||||||
{ "ui_right", TTRC("Right") },
|
{ "ui_right", TTRC("Right") },
|
||||||
{ "ui_up", TTRC("Up") },
|
{ "ui_up", TTRC("Up") },
|
||||||
{ "ui_down", TTRC("Down") },
|
{ "ui_down", TTRC("Down") },
|
||||||
{ "ui_page_up", TTRC("Page Up") },
|
{ "ui_page_up", TTRC("Page Up") },
|
||||||
{ "ui_page_down", TTRC("Page Down") },
|
{ "ui_page_down", TTRC("Page Down") },
|
||||||
{ "ui_home", TTRC("Home") },
|
{ "ui_home", TTRC("Home") },
|
||||||
{ "ui_end", TTRC("End") },
|
{ "ui_end", TTRC("End") },
|
||||||
{ "ui_cut", TTRC("Cut") },
|
{ "ui_cut", TTRC("Cut") },
|
||||||
{ "ui_copy", TTRC("Copy") },
|
{ "ui_copy", TTRC("Copy") },
|
||||||
{ "ui_paste", TTRC("Paste") },
|
{ "ui_paste", TTRC("Paste") },
|
||||||
{ "ui_focus_mode", TTRC("Toggle Tab Focus Mode") },
|
{ "ui_focus_mode", TTRC("Toggle Tab Focus Mode") },
|
||||||
{ "ui_undo", TTRC("Undo") },
|
{ "ui_undo", TTRC("Undo") },
|
||||||
{ "ui_redo", TTRC("Redo") },
|
{ "ui_redo", TTRC("Redo") },
|
||||||
{ "ui_text_completion_query", TTRC("Completion Query") },
|
{ "ui_text_completion_query", TTRC("Completion Query") },
|
||||||
{ "ui_text_newline", TTRC("New Line") },
|
{ "ui_text_newline", TTRC("New Line") },
|
||||||
{ "ui_text_newline_blank", TTRC("New Blank Line") },
|
{ "ui_text_newline_blank", TTRC("New Blank Line") },
|
||||||
{ "ui_text_newline_above", TTRC("New Line Above") },
|
{ "ui_text_newline_above", TTRC("New Line Above") },
|
||||||
{ "ui_text_indent", TTRC("Indent") },
|
{ "ui_text_indent", TTRC("Indent") },
|
||||||
{ "ui_text_dedent", TTRC("Dedent") },
|
{ "ui_text_dedent", TTRC("Dedent") },
|
||||||
{ "ui_text_backspace", TTRC("Backspace") },
|
{ "ui_text_backspace", TTRC("Backspace") },
|
||||||
{ "ui_text_backspace_word", TTRC("Backspace Word") },
|
{ "ui_text_backspace_word", TTRC("Backspace Word") },
|
||||||
{ "ui_text_backspace_word.macos", TTRC("Backspace Word") },
|
{ "ui_text_backspace_word.macos", TTRC("Backspace Word") },
|
||||||
{ "ui_text_backspace_all_to_left", TTRC("Backspace all to Left") },
|
{ "ui_text_backspace_all_to_left", TTRC("Backspace all to Left") },
|
||||||
{ "ui_text_backspace_all_to_left.macos", TTRC("Backspace all to Left") },
|
{ "ui_text_backspace_all_to_left.macos", TTRC("Backspace all to Left") },
|
||||||
{ "ui_text_delete", TTRC("Delete") },
|
{ "ui_text_delete", TTRC("Delete") },
|
||||||
{ "ui_text_delete_word", TTRC("Delete Word") },
|
{ "ui_text_delete_word", TTRC("Delete Word") },
|
||||||
{ "ui_text_delete_word.macos", TTRC("Delete Word") },
|
{ "ui_text_delete_word.macos", TTRC("Delete Word") },
|
||||||
{ "ui_text_delete_all_to_right", TTRC("Delete all to Right") },
|
{ "ui_text_delete_all_to_right", TTRC("Delete all to Right") },
|
||||||
{ "ui_text_delete_all_to_right.macos", TTRC("Delete all to Right") },
|
{ "ui_text_delete_all_to_right.macos", TTRC("Delete all to Right") },
|
||||||
{ "ui_text_caret_left", TTRC("Caret Left") },
|
{ "ui_text_caret_left", TTRC("Caret Left") },
|
||||||
{ "ui_text_caret_word_left", TTRC("Caret Word Left") },
|
{ "ui_text_caret_word_left", TTRC("Caret Word Left") },
|
||||||
{ "ui_text_caret_word_left.macos", TTRC("Caret Word Left") },
|
{ "ui_text_caret_word_left.macos", TTRC("Caret Word Left") },
|
||||||
{ "ui_text_caret_right", TTRC("Caret Right") },
|
{ "ui_text_caret_right", TTRC("Caret Right") },
|
||||||
{ "ui_text_caret_word_right", TTRC("Caret Word Right") },
|
{ "ui_text_caret_word_right", TTRC("Caret Word Right") },
|
||||||
{ "ui_text_caret_word_right.macos", TTRC("Caret Word Right") },
|
{ "ui_text_caret_word_right.macos", TTRC("Caret Word Right") },
|
||||||
{ "ui_text_caret_up", TTRC("Caret Up") },
|
{ "ui_text_caret_up", TTRC("Caret Up") },
|
||||||
{ "ui_text_caret_down", TTRC("Caret Down") },
|
{ "ui_text_caret_down", TTRC("Caret Down") },
|
||||||
{ "ui_text_caret_line_start", TTRC("Caret Line Start") },
|
{ "ui_text_caret_line_start", TTRC("Caret Line Start") },
|
||||||
{ "ui_text_caret_line_start.macos", TTRC("Caret Line Start") },
|
{ "ui_text_caret_line_start.macos", TTRC("Caret Line Start") },
|
||||||
{ "ui_text_caret_line_end", TTRC("Caret Line End") },
|
{ "ui_text_caret_line_end", TTRC("Caret Line End") },
|
||||||
{ "ui_text_caret_line_end.macos", TTRC("Caret Line End") },
|
{ "ui_text_caret_line_end.macos", TTRC("Caret Line End") },
|
||||||
{ "ui_text_caret_page_up", TTRC("Caret Page Up") },
|
{ "ui_text_caret_page_up", TTRC("Caret Page Up") },
|
||||||
{ "ui_text_caret_page_down", TTRC("Caret Page Down") },
|
{ "ui_text_caret_page_down", TTRC("Caret Page Down") },
|
||||||
{ "ui_text_caret_document_start", TTRC("Caret Document Start") },
|
{ "ui_text_caret_document_start", TTRC("Caret Document Start") },
|
||||||
{ "ui_text_caret_document_start.macos", TTRC("Caret Document Start") },
|
{ "ui_text_caret_document_start.macos", TTRC("Caret Document Start") },
|
||||||
{ "ui_text_caret_document_end", TTRC("Caret Document End") },
|
{ "ui_text_caret_document_end", TTRC("Caret Document End") },
|
||||||
{ "ui_text_caret_document_end.macos", TTRC("Caret Document End") },
|
{ "ui_text_caret_document_end.macos", TTRC("Caret Document End") },
|
||||||
{ "ui_text_caret_add_below", TTRC("Caret Add Below") },
|
{ "ui_text_caret_add_below", TTRC("Caret Add Below") },
|
||||||
{ "ui_text_caret_add_below.macos", TTRC("Caret Add Below") },
|
{ "ui_text_caret_add_below.macos", TTRC("Caret Add Below") },
|
||||||
{ "ui_text_caret_add_above", TTRC("Caret Add Above") },
|
{ "ui_text_caret_add_above", TTRC("Caret Add Above") },
|
||||||
{ "ui_text_caret_add_above.macos", TTRC("Caret Add Above") },
|
{ "ui_text_caret_add_above.macos", TTRC("Caret Add Above") },
|
||||||
{ "ui_text_scroll_up", TTRC("Scroll Up") },
|
{ "ui_text_scroll_up", TTRC("Scroll Up") },
|
||||||
{ "ui_text_scroll_up.macos", TTRC("Scroll Up") },
|
{ "ui_text_scroll_up.macos", TTRC("Scroll Up") },
|
||||||
{ "ui_text_scroll_down", TTRC("Scroll Down") },
|
{ "ui_text_scroll_down", TTRC("Scroll Down") },
|
||||||
{ "ui_text_scroll_down.macos", TTRC("Scroll Down") },
|
{ "ui_text_scroll_down.macos", TTRC("Scroll Down") },
|
||||||
{ "ui_text_select_all", TTRC("Select All") },
|
{ "ui_text_select_all", TTRC("Select All") },
|
||||||
{ "ui_text_select_word_under_caret", TTRC("Select Word Under Caret") },
|
{ "ui_text_select_word_under_caret", TTRC("Select Word Under Caret") },
|
||||||
{ "ui_text_add_selection_for_next_occurrence", TTRC("Add Selection for Next Occurrence") },
|
{ "ui_text_add_selection_for_next_occurrence", TTRC("Add Selection for Next Occurrence") },
|
||||||
{ "ui_text_skip_selection_for_next_occurrence", TTRC("Skip Selection for Next Occurrence") },
|
{ "ui_text_skip_selection_for_next_occurrence", TTRC("Skip Selection for Next Occurrence") },
|
||||||
{ "ui_text_clear_carets_and_selection", TTRC("Clear Carets and Selection") },
|
{ "ui_text_clear_carets_and_selection", TTRC("Clear Carets and Selection") },
|
||||||
{ "ui_text_toggle_insert_mode", TTRC("Toggle Insert Mode") },
|
{ "ui_text_toggle_insert_mode", TTRC("Toggle Insert Mode") },
|
||||||
{ "ui_text_submit", TTRC("Submit Text") },
|
{ "ui_text_submit", TTRC("Submit Text") },
|
||||||
{ "ui_graph_duplicate", TTRC("Duplicate Nodes") },
|
{ "ui_graph_duplicate", TTRC("Duplicate Nodes") },
|
||||||
{ "ui_graph_delete", TTRC("Delete Nodes") },
|
{ "ui_graph_delete", TTRC("Delete Nodes") },
|
||||||
{ "ui_graph_follow_left", TTRC("Follow Input Port Connection") },
|
{ "ui_graph_follow_left", TTRC("Follow Input Port Connection") },
|
||||||
{ "ui_graph_follow_right", TTRC("Follow Output Port Connection") },
|
{ "ui_graph_follow_right", TTRC("Follow Output Port Connection") },
|
||||||
{ "ui_filedialog_up_one_level", TTRC("Go Up One Level") },
|
{ "ui_filedialog_up_one_level", TTRC("Go Up One Level") },
|
||||||
{ "ui_filedialog_refresh", TTRC("Refresh") },
|
{ "ui_filedialog_refresh", TTRC("Refresh") },
|
||||||
{ "ui_filedialog_show_hidden", TTRC("Show Hidden") },
|
{ "ui_filedialog_show_hidden", TTRC("Show Hidden") },
|
||||||
{ "ui_swap_input_direction ", TTRC("Swap Input Direction") },
|
{ "ui_swap_input_direction ", TTRC("Swap Input Direction") },
|
||||||
{ "ui_unicode_start", TTRC("Start Unicode Character Input") },
|
{ "ui_unicode_start", TTRC("Start Unicode Character Input") },
|
||||||
{ "ui_colorpicker_delete_preset", TTRC("Toggle License Notices") },
|
{ "ui_colorpicker_delete_preset", TTRC("Toggle License Notices") },
|
||||||
{ "ui_accessibility_drag_and_drop", TTRC("Accessibility: Keyboard Drag and Drop") },
|
{ "ui_accessibility_drag_and_drop", TTRC("Accessibility: Keyboard Drag and Drop") },
|
||||||
{ "", ""}
|
{ "", ""}
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -60,24 +60,7 @@ void Logger::log_error(const char *p_function, const char *p_file, int p_line, c
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *err_type = "ERROR";
|
const char *err_type = error_type_string(p_type);
|
||||||
switch (p_type) {
|
|
||||||
case ERR_ERROR:
|
|
||||||
err_type = "ERROR";
|
|
||||||
break;
|
|
||||||
case ERR_WARNING:
|
|
||||||
err_type = "WARNING";
|
|
||||||
break;
|
|
||||||
case ERR_SCRIPT:
|
|
||||||
err_type = "SCRIPT ERROR";
|
|
||||||
break;
|
|
||||||
case ERR_SHADER:
|
|
||||||
err_type = "SHADER ERROR";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERR_PRINT("Unknown error type");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *err_details;
|
const char *err_details;
|
||||||
if (p_rationale && *p_rationale) {
|
if (p_rationale && *p_rationale) {
|
||||||
|
|||||||
@@ -55,6 +55,34 @@ public:
|
|||||||
ERR_SHADER
|
ERR_SHADER
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static constexpr const char *error_type_string(ErrorType p_type) {
|
||||||
|
switch (p_type) {
|
||||||
|
case ERR_ERROR:
|
||||||
|
return "ERROR";
|
||||||
|
case ERR_WARNING:
|
||||||
|
return "WARNING";
|
||||||
|
case ERR_SCRIPT:
|
||||||
|
return "SCRIPT ERROR";
|
||||||
|
case ERR_SHADER:
|
||||||
|
return "SHADER ERROR";
|
||||||
|
}
|
||||||
|
return "UNKNOWN ERROR";
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr const char *error_type_indent(ErrorType p_type) {
|
||||||
|
switch (p_type) {
|
||||||
|
case ERR_ERROR:
|
||||||
|
return " ";
|
||||||
|
case ERR_WARNING:
|
||||||
|
return " ";
|
||||||
|
case ERR_SCRIPT:
|
||||||
|
return " ";
|
||||||
|
case ERR_SHADER:
|
||||||
|
return " ";
|
||||||
|
}
|
||||||
|
return " ";
|
||||||
|
}
|
||||||
|
|
||||||
static void set_flush_stdout_on_print(bool value);
|
static void set_flush_stdout_on_print(bool value);
|
||||||
|
|
||||||
virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0 = 0;
|
virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0 = 0;
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin
|
|||||||
// Avoid double-tracking, for progress reporting, resources that boil down to a remapped path containing the real payload (e.g., imported resources).
|
// Avoid double-tracking, for progress reporting, resources that boil down to a remapped path containing the real payload (e.g., imported resources).
|
||||||
bool is_remapped_load = original_path == parent_task_path;
|
bool is_remapped_load = original_path == parent_task_path;
|
||||||
if (E && !is_remapped_load) {
|
if (E && !is_remapped_load) {
|
||||||
E->value.sub_tasks.insert(p_original_path);
|
E->value.sub_tasks.insert(original_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
load_paths_stack.push_back(original_path);
|
load_paths_stack.push_back(original_path);
|
||||||
@@ -567,6 +567,7 @@ Ref<Resource> ResourceLoader::load(const String &p_path, const String &p_type_hi
|
|||||||
|
|
||||||
Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path, const String &p_type_hint, LoadThreadMode p_thread_mode, ResourceFormatLoader::CacheMode p_cache_mode, bool p_for_user) {
|
Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path, const String &p_type_hint, LoadThreadMode p_thread_mode, ResourceFormatLoader::CacheMode p_cache_mode, bool p_for_user) {
|
||||||
String local_path = _validate_local_path(p_path);
|
String local_path = _validate_local_path(p_path);
|
||||||
|
ERR_FAIL_COND_V(local_path.is_empty(), Ref<ResourceLoader::LoadToken>());
|
||||||
|
|
||||||
bool ignoring_cache = p_cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE || p_cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP;
|
bool ignoring_cache = p_cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE || p_cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP;
|
||||||
|
|
||||||
|
|||||||
@@ -443,5 +443,5 @@ Variant AABB::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) c
|
|||||||
}
|
}
|
||||||
|
|
||||||
AABB::operator String() const {
|
AABB::operator String() const {
|
||||||
return "[P: " + position.operator String() + ", S: " + size + "]";
|
return "[P: " + String(position) + ", S: " + String(size) + "]";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ struct [[nodiscard]] AABB {
|
|||||||
return position + (size * 0.5f);
|
return position + (size * 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
|
|
||||||
AABB() = default;
|
AABB() = default;
|
||||||
constexpr AABB(const Vector3 &p_pos, const Vector3 &p_size) :
|
constexpr AABB(const Vector3 &p_pos, const Vector3 &p_size) :
|
||||||
|
|||||||
@@ -234,15 +234,9 @@ Basis Basis::from_scale(const Vector3 &p_scale) {
|
|||||||
// Multiplies the matrix from left by the scaling matrix: M -> S.M
|
// Multiplies the matrix from left by the scaling matrix: M -> S.M
|
||||||
// See the comment for Basis::rotated for further explanation.
|
// See the comment for Basis::rotated for further explanation.
|
||||||
void Basis::scale(const Vector3 &p_scale) {
|
void Basis::scale(const Vector3 &p_scale) {
|
||||||
rows[0][0] *= p_scale.x;
|
rows[0] *= p_scale.x;
|
||||||
rows[0][1] *= p_scale.x;
|
rows[1] *= p_scale.y;
|
||||||
rows[0][2] *= p_scale.x;
|
rows[2] *= p_scale.z;
|
||||||
rows[1][0] *= p_scale.y;
|
|
||||||
rows[1][1] *= p_scale.y;
|
|
||||||
rows[1][2] *= p_scale.y;
|
|
||||||
rows[2][0] *= p_scale.z;
|
|
||||||
rows[2][1] *= p_scale.z;
|
|
||||||
rows[2][2] *= p_scale.z;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Basis Basis::scaled(const Vector3 &p_scale) const {
|
Basis Basis::scaled(const Vector3 &p_scale) const {
|
||||||
@@ -254,7 +248,9 @@ Basis Basis::scaled(const Vector3 &p_scale) const {
|
|||||||
void Basis::scale_local(const Vector3 &p_scale) {
|
void Basis::scale_local(const Vector3 &p_scale) {
|
||||||
// performs a scaling in object-local coordinate system:
|
// performs a scaling in object-local coordinate system:
|
||||||
// M -> (M.S.Minv).M = M.S.
|
// M -> (M.S.Minv).M = M.S.
|
||||||
*this = scaled_local(p_scale);
|
rows[0] *= p_scale;
|
||||||
|
rows[1] *= p_scale;
|
||||||
|
rows[2] *= p_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Basis::scale_orthogonal(const Vector3 &p_scale) {
|
void Basis::scale_orthogonal(const Vector3 &p_scale) {
|
||||||
@@ -285,7 +281,9 @@ real_t Basis::get_uniform_scale() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Basis Basis::scaled_local(const Vector3 &p_scale) const {
|
Basis Basis::scaled_local(const Vector3 &p_scale) const {
|
||||||
return (*this) * Basis::from_scale(p_scale);
|
Basis m = *this;
|
||||||
|
m.scale_local(p_scale);
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 Basis::get_scale_abs() const {
|
Vector3 Basis::get_scale_abs() const {
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ struct [[nodiscard]] Basis {
|
|||||||
Basis slerp(const Basis &p_to, real_t p_weight) const;
|
Basis slerp(const Basis &p_to, real_t p_weight) const;
|
||||||
void rotate_sh(real_t *p_values);
|
void rotate_sh(real_t *p_values);
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
|
|
||||||
/* create / set */
|
/* create / set */
|
||||||
|
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ struct [[nodiscard]] Color {
|
|||||||
static Color from_rgba8(int64_t p_r8, int64_t p_g8, int64_t p_b8, int64_t p_a8 = 255);
|
static Color from_rgba8(int64_t p_r8, int64_t p_g8, int64_t p_b8, int64_t p_a8 = 255);
|
||||||
|
|
||||||
constexpr bool operator<(const Color &p_color) const; // Used in set keys.
|
constexpr bool operator<(const Color &p_color) const; // Used in set keys.
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
|
|
||||||
// For the binder.
|
// For the binder.
|
||||||
_FORCE_INLINE_ void set_r8(int32_t r8) { r = (CLAMP(r8, 0, 255) / 255.0f); }
|
_FORCE_INLINE_ void set_r8(int32_t r8) { r = (CLAMP(r8, 0, 255) / 255.0f); }
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ bool Face3::intersects_aabb(const AABB &p_aabb) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Face3::operator String() const {
|
Face3::operator String() const {
|
||||||
return String() + vertex[0] + ", " + vertex[1] + ", " + vertex[2];
|
return String() + String(vertex[0]) + ", " + String(vertex[1]) + ", " + String(vertex[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Face3::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
|
void Face3::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ struct [[nodiscard]] Face3 {
|
|||||||
|
|
||||||
bool intersects_aabb(const AABB &p_aabb) const;
|
bool intersects_aabb(const AABB &p_aabb) const;
|
||||||
_FORCE_INLINE_ bool intersects_aabb2(const AABB &p_aabb) const;
|
_FORCE_INLINE_ bool intersects_aabb2(const AABB &p_aabb) const;
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
|
|
||||||
Face3() = default;
|
Face3() = default;
|
||||||
constexpr Face3(const Vector3 &p_v1, const Vector3 &p_v2, const Vector3 &p_v3) :
|
constexpr Face3(const Vector3 &p_v1, const Vector3 &p_v2, const Vector3 &p_v3) :
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ struct [[nodiscard]] Plane {
|
|||||||
|
|
||||||
constexpr bool operator==(const Plane &p_plane) const;
|
constexpr bool operator==(const Plane &p_plane) const;
|
||||||
constexpr bool operator!=(const Plane &p_plane) const;
|
constexpr bool operator!=(const Plane &p_plane) const;
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
|
|
||||||
Plane() = default;
|
Plane() = default;
|
||||||
constexpr Plane(real_t p_a, real_t p_b, real_t p_c, real_t p_d) :
|
constexpr Plane(real_t p_a, real_t p_b, real_t p_c, real_t p_d) :
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ struct [[nodiscard]] Projection {
|
|||||||
Vector4 xform(const Vector4 &p_vec4) const;
|
Vector4 xform(const Vector4 &p_vec4) const;
|
||||||
Vector4 xform_inv(const Vector4 &p_vec4) const;
|
Vector4 xform_inv(const Vector4 &p_vec4) const;
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
|
|
||||||
void scale_translate_to_fit(const AABB &p_aabb);
|
void scale_translate_to_fit(const AABB &p_aabb);
|
||||||
void add_jitter_offset(const Vector2 &p_offset);
|
void add_jitter_offset(const Vector2 &p_offset);
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ struct [[nodiscard]] Quaternion {
|
|||||||
constexpr bool operator==(const Quaternion &p_quaternion) const;
|
constexpr bool operator==(const Quaternion &p_quaternion) const;
|
||||||
constexpr bool operator!=(const Quaternion &p_quaternion) const;
|
constexpr bool operator!=(const Quaternion &p_quaternion) const;
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
|
|
||||||
constexpr Quaternion() :
|
constexpr Quaternion() :
|
||||||
x(0), y(0), z(0), w(1) {}
|
x(0), y(0), z(0), w(1) {}
|
||||||
|
|||||||
@@ -360,7 +360,7 @@ struct [[nodiscard]] Rect2 {
|
|||||||
return position + size;
|
return position + size;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
operator Rect2i() const;
|
operator Rect2i() const;
|
||||||
|
|
||||||
Rect2() = default;
|
Rect2() = default;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
#include "core/string/ustring.h"
|
#include "core/string/ustring.h"
|
||||||
|
|
||||||
Rect2i::operator String() const {
|
Rect2i::operator String() const {
|
||||||
return "[P: " + position.operator String() + ", S: " + size + "]";
|
return "[P: " + String(position) + ", S: " + String(size) + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
Rect2i::operator Rect2() const {
|
Rect2i::operator Rect2() const {
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ struct [[nodiscard]] Rect2i {
|
|||||||
return position + size;
|
return position + size;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
operator Rect2() const;
|
operator Rect2() const;
|
||||||
|
|
||||||
Rect2i() = default;
|
Rect2i() = default;
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ struct [[nodiscard]] Transform2D {
|
|||||||
_FORCE_INLINE_ Vector<Vector2> xform(const Vector<Vector2> &p_array) const;
|
_FORCE_INLINE_ Vector<Vector2> xform(const Vector<Vector2> &p_array) const;
|
||||||
_FORCE_INLINE_ Vector<Vector2> xform_inv(const Vector<Vector2> &p_array) const;
|
_FORCE_INLINE_ Vector<Vector2> xform_inv(const Vector<Vector2> &p_array) const;
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
|
|
||||||
constexpr Transform2D(real_t p_xx, real_t p_xy, real_t p_yx, real_t p_yy, real_t p_ox, real_t p_oy) :
|
constexpr Transform2D(real_t p_xx, real_t p_xy, real_t p_yx, real_t p_yy, real_t p_ox, real_t p_oy) :
|
||||||
columns{
|
columns{
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ struct [[nodiscard]] Transform3D {
|
|||||||
origin.z = p_tz;
|
origin.z = p_tz;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
|
|
||||||
Transform3D() = default;
|
Transform3D() = default;
|
||||||
constexpr Transform3D(const Basis &p_basis, const Vector3 &p_origin = Vector3()) :
|
constexpr Transform3D(const Basis &p_basis, const Vector3 &p_origin = Vector3()) :
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ struct [[nodiscard]] Vector2 {
|
|||||||
Vector2 clampf(real_t p_min, real_t p_max) const;
|
Vector2 clampf(real_t p_min, real_t p_max) const;
|
||||||
real_t aspect() const { return width / height; }
|
real_t aspect() const { return width / height; }
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
operator Vector2i() const;
|
operator Vector2i() const;
|
||||||
|
|
||||||
// NOLINTBEGIN(cppcoreguidelines-pro-type-member-init)
|
// NOLINTBEGIN(cppcoreguidelines-pro-type-member-init)
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ struct [[nodiscard]] Vector2i {
|
|||||||
Vector2i snapped(const Vector2i &p_step) const;
|
Vector2i snapped(const Vector2i &p_step) const;
|
||||||
Vector2i snappedi(int32_t p_step) const;
|
Vector2i snappedi(int32_t p_step) const;
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
operator Vector2() const;
|
operator Vector2() const;
|
||||||
|
|
||||||
// NOLINTBEGIN(cppcoreguidelines-pro-type-member-init)
|
// NOLINTBEGIN(cppcoreguidelines-pro-type-member-init)
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ struct [[nodiscard]] Vector3 {
|
|||||||
constexpr bool operator>(const Vector3 &p_v) const;
|
constexpr bool operator>(const Vector3 &p_v) const;
|
||||||
constexpr bool operator>=(const Vector3 &p_v) const;
|
constexpr bool operator>=(const Vector3 &p_v) const;
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
operator Vector3i() const;
|
operator Vector3i() const;
|
||||||
|
|
||||||
constexpr Vector3() :
|
constexpr Vector3() :
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ struct [[nodiscard]] Vector3i {
|
|||||||
constexpr bool operator>(const Vector3i &p_v) const;
|
constexpr bool operator>(const Vector3i &p_v) const;
|
||||||
constexpr bool operator>=(const Vector3i &p_v) const;
|
constexpr bool operator>=(const Vector3i &p_v) const;
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
operator Vector3() const;
|
operator Vector3() const;
|
||||||
|
|
||||||
constexpr Vector3i() :
|
constexpr Vector3i() :
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ struct [[nodiscard]] Vector4 {
|
|||||||
constexpr bool operator>=(const Vector4 &p_vec4) const;
|
constexpr bool operator>=(const Vector4 &p_vec4) const;
|
||||||
constexpr bool operator<=(const Vector4 &p_vec4) const;
|
constexpr bool operator<=(const Vector4 &p_vec4) const;
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
operator Vector4i() const;
|
operator Vector4i() const;
|
||||||
|
|
||||||
constexpr Vector4() :
|
constexpr Vector4() :
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ struct [[nodiscard]] Vector4i {
|
|||||||
constexpr bool operator>(const Vector4i &p_v) const;
|
constexpr bool operator>(const Vector4i &p_v) const;
|
||||||
constexpr bool operator>=(const Vector4i &p_v) const;
|
constexpr bool operator>=(const Vector4i &p_v) const;
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
operator Vector4() const;
|
operator Vector4() const;
|
||||||
|
|
||||||
constexpr Vector4i() :
|
constexpr Vector4i() :
|
||||||
|
|||||||
@@ -544,13 +544,8 @@ public:
|
|||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
|
|
||||||
template <typename... P>
|
|
||||||
_FORCE_INLINE_ Vector<Error> errarray(P... p_args) {
|
|
||||||
return Vector<Error>({ p_args... });
|
|
||||||
}
|
|
||||||
|
|
||||||
#define BIND_METHOD_ERR_RETURN_DOC(m_method, ...) \
|
#define BIND_METHOD_ERR_RETURN_DOC(m_method, ...) \
|
||||||
::ClassDB::set_method_error_return_values(get_class_static(), m_method, errarray(__VA_ARGS__));
|
::ClassDB::set_method_error_return_values(get_class_static(), m_method, Vector<Error>{ __VA_ARGS__ });
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class TranslationServer : public Object {
|
|||||||
(p_locale.variant == variant);
|
(p_locale.variant == variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
|
|
||||||
Locale(const TranslationServer &p_server, const String &p_locale, bool p_add_defaults);
|
Locale(const TranslationServer &p_server, const String &p_locale, bool p_add_defaults);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -57,6 +57,7 @@
|
|||||||
#include "core/templates/pair.h"
|
#include "core/templates/pair.h"
|
||||||
#include "core/templates/rid.h"
|
#include "core/templates/rid.h"
|
||||||
#include "core/typedefs.h"
|
#include "core/typedefs.h"
|
||||||
|
#include "core/variant/callable.h"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#include <intrin.h> // Needed for `__umulh` below.
|
#include <intrin.h> // Needed for `__umulh` below.
|
||||||
@@ -344,6 +345,7 @@ struct HashMapHasherDefault {
|
|||||||
static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
|
static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
|
||||||
static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); }
|
static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); }
|
||||||
static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); }
|
static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); }
|
||||||
|
static _FORCE_INLINE_ uint32_t hash(const Callable &p_callable) { return p_callable.hash(); }
|
||||||
|
|
||||||
static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); }
|
static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); }
|
||||||
static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash_one_uint64(uint64_t(p_int)); }
|
static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash_one_uint64(uint64_t(p_int)); }
|
||||||
@@ -391,6 +393,13 @@ struct HashMapHasherDefault {
|
|||||||
h = hash_murmur3_one_real(p_vec.w, h);
|
h = hash_murmur3_one_real(p_vec.w, h);
|
||||||
return hash_fmix32(h);
|
return hash_fmix32(h);
|
||||||
}
|
}
|
||||||
|
static _FORCE_INLINE_ uint32_t hash(const Color &p_vec) {
|
||||||
|
uint32_t h = hash_murmur3_one_float(p_vec.r);
|
||||||
|
h = hash_murmur3_one_float(p_vec.g, h);
|
||||||
|
h = hash_murmur3_one_float(p_vec.b, h);
|
||||||
|
h = hash_murmur3_one_float(p_vec.a, h);
|
||||||
|
return hash_fmix32(h);
|
||||||
|
}
|
||||||
static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) {
|
static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) {
|
||||||
uint32_t h = hash_murmur3_one_32(uint32_t(p_rect.position.x));
|
uint32_t h = hash_murmur3_one_32(uint32_t(p_rect.position.x));
|
||||||
h = hash_murmur3_one_32(uint32_t(p_rect.position.y), h);
|
h = hash_murmur3_one_32(uint32_t(p_rect.position.y), h);
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ public:
|
|||||||
|
|
||||||
void operator=(const Callable &p_callable);
|
void operator=(const Callable &p_callable);
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
|
|
||||||
static Callable create(const Variant &p_variant, const StringName &p_method);
|
static Callable create(const Variant &p_variant, const StringName &p_method);
|
||||||
|
|
||||||
@@ -192,7 +192,7 @@ public:
|
|||||||
bool operator!=(const Signal &p_signal) const;
|
bool operator!=(const Signal &p_signal) const;
|
||||||
bool operator<(const Signal &p_signal) const;
|
bool operator<(const Signal &p_signal) const;
|
||||||
|
|
||||||
operator String() const;
|
explicit operator String() const;
|
||||||
|
|
||||||
Error emit(const Variant **p_arguments, int p_argcount) const;
|
Error emit(const Variant **p_arguments, int p_argcount) const;
|
||||||
Error connect(const Callable &p_callable, uint32_t p_flags = 0);
|
Error connect(const Callable &p_callable, uint32_t p_flags = 0);
|
||||||
|
|||||||
@@ -37,113 +37,215 @@
|
|||||||
#include "core/typedefs.h"
|
#include "core/typedefs.h"
|
||||||
#include "core/variant/variant.h"
|
#include "core/variant/variant.h"
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct PtrToArgDirect {
|
||||||
|
_FORCE_INLINE_ static const T &convert(const void *p_ptr) {
|
||||||
|
return *reinterpret_cast<const T *>(p_ptr);
|
||||||
|
}
|
||||||
|
typedef T EncodeT;
|
||||||
|
_FORCE_INLINE_ static void encode(T p_val, void *p_ptr) {
|
||||||
|
*((T *)p_ptr) = p_val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename S>
|
||||||
|
struct PtrToArgConvert {
|
||||||
|
_FORCE_INLINE_ static T convert(const void *p_ptr) {
|
||||||
|
return static_cast<T>(*reinterpret_cast<const S *>(p_ptr));
|
||||||
|
}
|
||||||
|
typedef S EncodeT;
|
||||||
|
_FORCE_INLINE_ static void encode(T p_val, void *p_ptr) {
|
||||||
|
*((S *)p_ptr) = static_cast<S>(p_val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct PtrToArgByReference {
|
||||||
|
_FORCE_INLINE_ static const T &convert(const void *p_ptr) {
|
||||||
|
return *reinterpret_cast<const T *>(p_ptr);
|
||||||
|
}
|
||||||
|
typedef T EncodeT;
|
||||||
|
_FORCE_INLINE_ static void encode(const T &p_val, void *p_ptr) {
|
||||||
|
*((T *)p_ptr) = p_val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename TAlt>
|
||||||
|
struct PtrToArgVectorConvert {
|
||||||
|
_FORCE_INLINE_ static Vector<TAlt> convert(const void *p_ptr) {
|
||||||
|
const Vector<T> *dvs = reinterpret_cast<const Vector<T> *>(p_ptr);
|
||||||
|
Vector<TAlt> ret;
|
||||||
|
int len = dvs->size();
|
||||||
|
ret.resize(len);
|
||||||
|
{
|
||||||
|
const T *r = dvs->ptr();
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
ret.write[i] = r[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
// No EncodeT because direct pointer conversion not possible.
|
||||||
|
_FORCE_INLINE_ static void encode(const Vector<TAlt> &p_vec, void *p_ptr) {
|
||||||
|
Vector<T> *dv = reinterpret_cast<Vector<T> *>(p_ptr);
|
||||||
|
int len = p_vec.size();
|
||||||
|
dv->resize(len);
|
||||||
|
{
|
||||||
|
T *w = dv->ptrw();
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
w[i] = p_vec[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct PtrToArgVectorFromArray {
|
||||||
|
_FORCE_INLINE_ static Vector<T> convert(const void *p_ptr) {
|
||||||
|
const Array *arr = reinterpret_cast<const Array *>(p_ptr);
|
||||||
|
Vector<T> ret;
|
||||||
|
int len = arr->size();
|
||||||
|
ret.resize(len);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
ret.write[i] = (*arr)[i];
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
// No EncodeT because direct pointer conversion not possible.
|
||||||
|
_FORCE_INLINE_ static void encode(const Vector<T> &p_vec, void *p_ptr) {
|
||||||
|
Array *arr = reinterpret_cast<Array *>(p_ptr);
|
||||||
|
int len = p_vec.size();
|
||||||
|
arr->resize(len);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
(*arr)[i] = p_vec[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct PtrToArgStringConvertByReference {
|
||||||
|
_FORCE_INLINE_ static T convert(const void *p_ptr) {
|
||||||
|
T s = *reinterpret_cast<const String *>(p_ptr);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
// No EncodeT because direct pointer conversion not possible.
|
||||||
|
_FORCE_INLINE_ static void encode(const T &p_vec, void *p_ptr) {
|
||||||
|
String *arr = reinterpret_cast<String *>(p_ptr);
|
||||||
|
*arr = String(p_vec);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} //namespace Internal
|
||||||
|
|
||||||
template <typename T, typename = void>
|
template <typename T, typename = void>
|
||||||
struct PtrToArg;
|
struct PtrToArg;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct PtrToArg<T, std::enable_if_t<!std::is_same_v<T, GetSimpleTypeT<T>>>> : PtrToArg<GetSimpleTypeT<T>> {};
|
struct PtrToArg<T, std::enable_if_t<!std::is_same_v<T, GetSimpleTypeT<T>>>> : PtrToArg<GetSimpleTypeT<T>> {};
|
||||||
|
|
||||||
#define MAKE_PTRARG(m_type) \
|
template <>
|
||||||
template <> \
|
struct PtrToArg<bool> : Internal::PtrToArgConvert<bool, uint8_t> {};
|
||||||
struct PtrToArg<m_type> { \
|
|
||||||
_FORCE_INLINE_ static const m_type &convert(const void *p_ptr) { \
|
|
||||||
return *reinterpret_cast<const m_type *>(p_ptr); \
|
|
||||||
} \
|
|
||||||
typedef m_type EncodeT; \
|
|
||||||
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
|
|
||||||
*((m_type *)p_ptr) = p_val; \
|
|
||||||
} \
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAKE_PTRARGCONV(m_type, m_conv) \
|
|
||||||
template <> \
|
|
||||||
struct PtrToArg<m_type> { \
|
|
||||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
|
||||||
return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
|
|
||||||
} \
|
|
||||||
typedef m_conv EncodeT; \
|
|
||||||
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
|
|
||||||
*((m_conv *)p_ptr) = static_cast<m_conv>(p_val); \
|
|
||||||
} \
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAKE_PTRARG_BY_REFERENCE(m_type) \
|
|
||||||
template <> \
|
|
||||||
struct PtrToArg<m_type> { \
|
|
||||||
_FORCE_INLINE_ static const m_type &convert(const void *p_ptr) { \
|
|
||||||
return *reinterpret_cast<const m_type *>(p_ptr); \
|
|
||||||
} \
|
|
||||||
typedef m_type EncodeT; \
|
|
||||||
_FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \
|
|
||||||
*((m_type *)p_ptr) = p_val; \
|
|
||||||
} \
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAKE_PTRARGCONV_CONDITIONAL(m_type, m_conv, m_conditional) \
|
|
||||||
template <typename T> \
|
|
||||||
struct PtrToArg<m_type, std::enable_if_t<m_conditional>> { \
|
|
||||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
|
||||||
return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
|
|
||||||
} \
|
|
||||||
typedef m_conv EncodeT; \
|
|
||||||
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
|
|
||||||
*((m_conv *)p_ptr) = static_cast<m_conv>(p_val); \
|
|
||||||
} \
|
|
||||||
};
|
|
||||||
|
|
||||||
MAKE_PTRARGCONV(bool, uint8_t);
|
|
||||||
// Integer types.
|
// Integer types.
|
||||||
MAKE_PTRARGCONV(uint8_t, int64_t);
|
template <>
|
||||||
MAKE_PTRARGCONV(int8_t, int64_t);
|
struct PtrToArg<uint8_t> : Internal::PtrToArgConvert<uint8_t, int64_t> {};
|
||||||
MAKE_PTRARGCONV(uint16_t, int64_t);
|
template <>
|
||||||
MAKE_PTRARGCONV(int16_t, int64_t);
|
struct PtrToArg<int8_t> : Internal::PtrToArgConvert<int8_t, int64_t> {};
|
||||||
MAKE_PTRARGCONV(uint32_t, int64_t);
|
template <>
|
||||||
MAKE_PTRARGCONV(int32_t, int64_t);
|
struct PtrToArg<uint16_t> : Internal::PtrToArgConvert<uint16_t, int64_t> {};
|
||||||
MAKE_PTRARG(int64_t);
|
template <>
|
||||||
MAKE_PTRARG(uint64_t);
|
struct PtrToArg<int16_t> : Internal::PtrToArgConvert<int16_t, int64_t> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<uint32_t> : Internal::PtrToArgConvert<uint32_t, int64_t> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<int32_t> : Internal::PtrToArgConvert<int32_t, int64_t> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<int64_t> : Internal::PtrToArgDirect<int64_t> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<uint64_t> : Internal::PtrToArgDirect<uint64_t> {};
|
||||||
// Float types
|
// Float types
|
||||||
MAKE_PTRARGCONV(float, double);
|
template <>
|
||||||
MAKE_PTRARG(double);
|
struct PtrToArg<float> : Internal::PtrToArgConvert<float, double> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<double> : Internal::PtrToArgDirect<double> {};
|
||||||
|
|
||||||
MAKE_PTRARG(String);
|
template <>
|
||||||
MAKE_PTRARG(Vector2);
|
struct PtrToArg<String> : Internal::PtrToArgDirect<String> {};
|
||||||
MAKE_PTRARG(Vector2i);
|
template <>
|
||||||
MAKE_PTRARG(Rect2);
|
struct PtrToArg<Vector2> : Internal::PtrToArgDirect<Vector2> {};
|
||||||
MAKE_PTRARG(Rect2i);
|
template <>
|
||||||
MAKE_PTRARG_BY_REFERENCE(Vector3);
|
struct PtrToArg<Vector2i> : Internal::PtrToArgDirect<Vector2i> {};
|
||||||
MAKE_PTRARG_BY_REFERENCE(Vector3i);
|
template <>
|
||||||
MAKE_PTRARG_BY_REFERENCE(Vector4);
|
struct PtrToArg<Rect2> : Internal::PtrToArgDirect<Rect2> {};
|
||||||
MAKE_PTRARG_BY_REFERENCE(Vector4i);
|
template <>
|
||||||
MAKE_PTRARG(Transform2D);
|
struct PtrToArg<Rect2i> : Internal::PtrToArgDirect<Rect2i> {};
|
||||||
MAKE_PTRARG(Projection);
|
template <>
|
||||||
MAKE_PTRARG_BY_REFERENCE(Plane);
|
struct PtrToArg<Vector3> : Internal::PtrToArgByReference<Vector3> {};
|
||||||
MAKE_PTRARG(Quaternion);
|
template <>
|
||||||
MAKE_PTRARG_BY_REFERENCE(AABB);
|
struct PtrToArg<Vector3i> : Internal::PtrToArgByReference<Vector3i> {};
|
||||||
MAKE_PTRARG_BY_REFERENCE(Basis);
|
template <>
|
||||||
MAKE_PTRARG_BY_REFERENCE(Transform3D);
|
struct PtrToArg<Vector4> : Internal::PtrToArgByReference<Vector4> {};
|
||||||
MAKE_PTRARG_BY_REFERENCE(Color);
|
template <>
|
||||||
MAKE_PTRARG(StringName);
|
struct PtrToArg<Vector4i> : Internal::PtrToArgByReference<Vector4i> {};
|
||||||
MAKE_PTRARG(NodePath);
|
template <>
|
||||||
MAKE_PTRARG(RID);
|
struct PtrToArg<Transform2D> : Internal::PtrToArgDirect<Transform2D> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<Projection> : Internal::PtrToArgDirect<Projection> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<Plane> : Internal::PtrToArgByReference<Plane> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<Quaternion> : Internal::PtrToArgDirect<Quaternion> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<AABB> : Internal::PtrToArgByReference<AABB> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<Basis> : Internal::PtrToArgByReference<Basis> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<Transform3D> : Internal::PtrToArgByReference<Transform3D> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<Color> : Internal::PtrToArgByReference<Color> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<StringName> : Internal::PtrToArgDirect<StringName> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<NodePath> : Internal::PtrToArgDirect<NodePath> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<RID> : Internal::PtrToArgDirect<RID> {};
|
||||||
// Object doesn't need this.
|
// Object doesn't need this.
|
||||||
MAKE_PTRARG(Callable);
|
template <>
|
||||||
MAKE_PTRARG(Signal);
|
struct PtrToArg<Callable> : Internal::PtrToArgDirect<Callable> {};
|
||||||
MAKE_PTRARG(Dictionary);
|
template <>
|
||||||
MAKE_PTRARG(Array);
|
struct PtrToArg<Signal> : Internal::PtrToArgDirect<Signal> {};
|
||||||
MAKE_PTRARG(PackedByteArray);
|
template <>
|
||||||
MAKE_PTRARG(PackedInt32Array);
|
struct PtrToArg<Dictionary> : Internal::PtrToArgDirect<Dictionary> {};
|
||||||
MAKE_PTRARG(PackedInt64Array);
|
template <>
|
||||||
MAKE_PTRARG(PackedFloat32Array);
|
struct PtrToArg<Array> : Internal::PtrToArgDirect<Array> {};
|
||||||
MAKE_PTRARG(PackedFloat64Array);
|
template <>
|
||||||
MAKE_PTRARG(PackedStringArray);
|
struct PtrToArg<PackedByteArray> : Internal::PtrToArgDirect<PackedByteArray> {};
|
||||||
MAKE_PTRARG(PackedVector2Array);
|
template <>
|
||||||
MAKE_PTRARG(PackedVector3Array);
|
struct PtrToArg<PackedInt32Array> : Internal::PtrToArgDirect<PackedInt32Array> {};
|
||||||
MAKE_PTRARG(PackedColorArray);
|
template <>
|
||||||
MAKE_PTRARG(PackedVector4Array);
|
struct PtrToArg<PackedInt64Array> : Internal::PtrToArgDirect<PackedInt64Array> {};
|
||||||
MAKE_PTRARG_BY_REFERENCE(Variant);
|
template <>
|
||||||
|
struct PtrToArg<PackedFloat32Array> : Internal::PtrToArgDirect<PackedFloat32Array> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<PackedFloat64Array> : Internal::PtrToArgDirect<PackedFloat64Array> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<PackedStringArray> : Internal::PtrToArgDirect<PackedStringArray> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<PackedVector2Array> : Internal::PtrToArgDirect<PackedVector2Array> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<PackedVector3Array> : Internal::PtrToArgDirect<PackedVector3Array> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<PackedColorArray> : Internal::PtrToArgDirect<PackedColorArray> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<PackedVector4Array> : Internal::PtrToArgDirect<PackedVector4Array> {};
|
||||||
|
template <>
|
||||||
|
struct PtrToArg<Variant> : Internal::PtrToArgByReference<Variant> {};
|
||||||
|
|
||||||
MAKE_PTRARGCONV_CONDITIONAL(T, int64_t, std::is_enum_v<T>);
|
template <typename T>
|
||||||
MAKE_PTRARGCONV_CONDITIONAL(BitField<T>, int64_t, std::is_enum_v<T>);
|
struct PtrToArg<T, std::enable_if_t<std::is_enum_v<T>>> : Internal::PtrToArgConvert<T, int64_t> {};
|
||||||
|
template <typename T>
|
||||||
|
struct PtrToArg<BitField<T>, std::enable_if_t<std::is_enum_v<T>>> : Internal::PtrToArgConvert<BitField<T>, int64_t> {};
|
||||||
|
|
||||||
// This is for Object.
|
// This is for Object.
|
||||||
|
|
||||||
@@ -184,147 +286,23 @@ struct PtrToArg<ObjectID> {
|
|||||||
|
|
||||||
// This is for the special cases used by Variant.
|
// This is for the special cases used by Variant.
|
||||||
|
|
||||||
// No EncodeT because direct pointer conversion not possible.
|
template <>
|
||||||
#define MAKE_VECARG(m_type) \
|
struct PtrToArg<Vector<StringName>> : Internal::PtrToArgVectorConvert<String, StringName> {};
|
||||||
template <> \
|
|
||||||
struct PtrToArg<Vector<m_type>> { \
|
|
||||||
_FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
|
|
||||||
const Vector<m_type> *dvs = reinterpret_cast<const Vector<m_type> *>(p_ptr); \
|
|
||||||
Vector<m_type> ret; \
|
|
||||||
int len = dvs->size(); \
|
|
||||||
ret.resize(len); \
|
|
||||||
{ \
|
|
||||||
const m_type *r = dvs->ptr(); \
|
|
||||||
for (int i = 0; i < len; i++) { \
|
|
||||||
ret.write[i] = r[i]; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
return ret; \
|
|
||||||
} \
|
|
||||||
_FORCE_INLINE_ static void encode(const Vector<m_type> &p_vec, void *p_ptr) { \
|
|
||||||
Vector<m_type> *dv = reinterpret_cast<Vector<m_type> *>(p_ptr); \
|
|
||||||
int len = p_vec.size(); \
|
|
||||||
dv->resize(len); \
|
|
||||||
{ \
|
|
||||||
m_type *w = dv->ptrw(); \
|
|
||||||
for (int i = 0; i < len; i++) { \
|
|
||||||
w[i] = p_vec[i]; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
};
|
|
||||||
|
|
||||||
// No EncodeT because direct pointer conversion not possible.
|
|
||||||
#define MAKE_VECARG_ALT(m_type, m_type_alt) \
|
|
||||||
template <> \
|
|
||||||
struct PtrToArg<Vector<m_type_alt>> { \
|
|
||||||
_FORCE_INLINE_ static Vector<m_type_alt> convert(const void *p_ptr) { \
|
|
||||||
const Vector<m_type> *dvs = reinterpret_cast<const Vector<m_type> *>(p_ptr); \
|
|
||||||
Vector<m_type_alt> ret; \
|
|
||||||
int len = dvs->size(); \
|
|
||||||
ret.resize(len); \
|
|
||||||
{ \
|
|
||||||
const m_type *r = dvs->ptr(); \
|
|
||||||
for (int i = 0; i < len; i++) { \
|
|
||||||
ret.write[i] = r[i]; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
return ret; \
|
|
||||||
} \
|
|
||||||
_FORCE_INLINE_ static void encode(const Vector<m_type_alt> &p_vec, void *p_ptr) { \
|
|
||||||
Vector<m_type> *dv = reinterpret_cast<Vector<m_type> *>(p_ptr); \
|
|
||||||
int len = p_vec.size(); \
|
|
||||||
dv->resize(len); \
|
|
||||||
{ \
|
|
||||||
m_type *w = dv->ptrw(); \
|
|
||||||
for (int i = 0; i < len; i++) { \
|
|
||||||
w[i] = p_vec[i]; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
};
|
|
||||||
|
|
||||||
MAKE_VECARG_ALT(String, StringName);
|
|
||||||
|
|
||||||
// For stuff that gets converted to Array vectors.
|
// For stuff that gets converted to Array vectors.
|
||||||
|
|
||||||
// No EncodeT because direct pointer conversion not possible.
|
template <>
|
||||||
#define MAKE_VECARR(m_type) \
|
struct PtrToArg<Vector<Variant>> : Internal::PtrToArgVectorFromArray<Variant> {};
|
||||||
template <> \
|
template <>
|
||||||
struct PtrToArg<Vector<m_type>> { \
|
struct PtrToArg<Vector<RID>> : Internal::PtrToArgVectorFromArray<RID> {};
|
||||||
_FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
|
template <>
|
||||||
const Array *arr = reinterpret_cast<const Array *>(p_ptr); \
|
struct PtrToArg<Vector<Plane>> : Internal::PtrToArgVectorFromArray<Plane> {};
|
||||||
Vector<m_type> ret; \
|
|
||||||
int len = arr->size(); \
|
|
||||||
ret.resize(len); \
|
|
||||||
for (int i = 0; i < len; i++) { \
|
|
||||||
ret.write[i] = (*arr)[i]; \
|
|
||||||
} \
|
|
||||||
return ret; \
|
|
||||||
} \
|
|
||||||
_FORCE_INLINE_ static void encode(const Vector<m_type> &p_vec, void *p_ptr) { \
|
|
||||||
Array *arr = reinterpret_cast<Array *>(p_ptr); \
|
|
||||||
int len = p_vec.size(); \
|
|
||||||
arr->resize(len); \
|
|
||||||
for (int i = 0; i < len; i++) { \
|
|
||||||
(*arr)[i] = p_vec[i]; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
};
|
|
||||||
|
|
||||||
MAKE_VECARR(Variant);
|
|
||||||
MAKE_VECARR(RID);
|
|
||||||
MAKE_VECARR(Plane);
|
|
||||||
|
|
||||||
// No EncodeT because direct pointer conversion not possible.
|
|
||||||
#define MAKE_DVECARR(m_type) \
|
|
||||||
template <> \
|
|
||||||
struct PtrToArg<Vector<m_type>> { \
|
|
||||||
_FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
|
|
||||||
const Array *arr = reinterpret_cast<const Array *>(p_ptr); \
|
|
||||||
Vector<m_type> ret; \
|
|
||||||
int len = arr->size(); \
|
|
||||||
ret.resize(len); \
|
|
||||||
{ \
|
|
||||||
m_type *w = ret.ptrw(); \
|
|
||||||
for (int i = 0; i < len; i++) { \
|
|
||||||
w[i] = (*arr)[i]; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
return ret; \
|
|
||||||
} \
|
|
||||||
_FORCE_INLINE_ static void encode(const Vector<m_type> &p_vec, void *p_ptr) { \
|
|
||||||
Array *arr = reinterpret_cast<Array *>(p_ptr); \
|
|
||||||
int len = p_vec.size(); \
|
|
||||||
arr->resize(len); \
|
|
||||||
{ \
|
|
||||||
const m_type *r = p_vec.ptr(); \
|
|
||||||
for (int i = 0; i < len; i++) { \
|
|
||||||
(*arr)[i] = r[i]; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
};
|
|
||||||
|
|
||||||
// Special case for IPAddress.
|
// Special case for IPAddress.
|
||||||
|
|
||||||
// No EncodeT because direct pointer conversion not possible.
|
template <>
|
||||||
#define MAKE_STRINGCONV_BY_REFERENCE(m_type) \
|
struct PtrToArg<IPAddress> : Internal::PtrToArgStringConvertByReference<IPAddress> {};
|
||||||
template <> \
|
|
||||||
struct PtrToArg<m_type> { \
|
|
||||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
|
||||||
m_type s = *reinterpret_cast<const String *>(p_ptr); \
|
|
||||||
return s; \
|
|
||||||
} \
|
|
||||||
_FORCE_INLINE_ static void encode(const m_type &p_vec, void *p_ptr) { \
|
|
||||||
String *arr = reinterpret_cast<String *>(p_ptr); \
|
|
||||||
*arr = p_vec; \
|
|
||||||
} \
|
|
||||||
};
|
|
||||||
|
|
||||||
MAKE_STRINGCONV_BY_REFERENCE(IPAddress);
|
|
||||||
|
|
||||||
// No EncodeT because direct pointer conversion not possible.
|
|
||||||
template <>
|
template <>
|
||||||
struct PtrToArg<Vector<Face3>> {
|
struct PtrToArg<Vector<Face3>> {
|
||||||
_FORCE_INLINE_ static Vector<Face3> convert(const void *p_ptr) {
|
_FORCE_INLINE_ static Vector<Face3> convert(const void *p_ptr) {
|
||||||
@@ -343,6 +321,7 @@ struct PtrToArg<Vector<Face3>> {
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
// No EncodeT because direct pointer conversion not possible.
|
||||||
_FORCE_INLINE_ static void encode(const Vector<Face3> &p_vec, void *p_ptr) {
|
_FORCE_INLINE_ static void encode(const Vector<Face3> &p_vec, void *p_ptr) {
|
||||||
Vector<Vector3> *arr = reinterpret_cast<Vector<Vector3> *>(p_ptr);
|
Vector<Vector3> *arr = reinterpret_cast<Vector<Vector3> *>(p_ptr);
|
||||||
int len = p_vec.size();
|
int len = p_vec.size();
|
||||||
|
|||||||
@@ -1612,41 +1612,41 @@ String Variant::stringify(int recursion_count) const {
|
|||||||
case STRING:
|
case STRING:
|
||||||
return *reinterpret_cast<const String *>(_data._mem);
|
return *reinterpret_cast<const String *>(_data._mem);
|
||||||
case VECTOR2:
|
case VECTOR2:
|
||||||
return operator Vector2();
|
return String(operator Vector2());
|
||||||
case VECTOR2I:
|
case VECTOR2I:
|
||||||
return operator Vector2i();
|
return String(operator Vector2i());
|
||||||
case RECT2:
|
case RECT2:
|
||||||
return operator Rect2();
|
return String(operator Rect2());
|
||||||
case RECT2I:
|
case RECT2I:
|
||||||
return operator Rect2i();
|
return String(operator Rect2i());
|
||||||
case TRANSFORM2D:
|
case TRANSFORM2D:
|
||||||
return operator Transform2D();
|
return String(operator Transform2D());
|
||||||
case VECTOR3:
|
case VECTOR3:
|
||||||
return operator Vector3();
|
return String(operator Vector3());
|
||||||
case VECTOR3I:
|
case VECTOR3I:
|
||||||
return operator Vector3i();
|
return String(operator Vector3i());
|
||||||
case VECTOR4:
|
case VECTOR4:
|
||||||
return operator Vector4();
|
return String(operator Vector4());
|
||||||
case VECTOR4I:
|
case VECTOR4I:
|
||||||
return operator Vector4i();
|
return String(operator Vector4i());
|
||||||
case PLANE:
|
case PLANE:
|
||||||
return operator Plane();
|
return String(operator Plane());
|
||||||
case AABB:
|
case AABB:
|
||||||
return operator ::AABB();
|
return String(operator ::AABB());
|
||||||
case QUATERNION:
|
case QUATERNION:
|
||||||
return operator Quaternion();
|
return String(operator Quaternion());
|
||||||
case BASIS:
|
case BASIS:
|
||||||
return operator Basis();
|
return String(operator Basis());
|
||||||
case TRANSFORM3D:
|
case TRANSFORM3D:
|
||||||
return operator Transform3D();
|
return String(operator Transform3D());
|
||||||
case PROJECTION:
|
case PROJECTION:
|
||||||
return operator Projection();
|
return String(operator Projection());
|
||||||
case STRING_NAME:
|
case STRING_NAME:
|
||||||
return operator StringName();
|
return operator StringName();
|
||||||
case NODE_PATH:
|
case NODE_PATH:
|
||||||
return operator NodePath();
|
return operator NodePath();
|
||||||
case COLOR:
|
case COLOR:
|
||||||
return operator Color();
|
return String(operator Color());
|
||||||
case DICTIONARY: {
|
case DICTIONARY: {
|
||||||
ERR_FAIL_COND_V_MSG(recursion_count > MAX_RECURSION, "{ ... }", "Maximum dictionary recursion reached!");
|
ERR_FAIL_COND_V_MSG(recursion_count > MAX_RECURSION, "{ ... }", "Maximum dictionary recursion reached!");
|
||||||
recursion_count++;
|
recursion_count++;
|
||||||
@@ -1727,11 +1727,11 @@ String Variant::stringify(int recursion_count) const {
|
|||||||
}
|
}
|
||||||
case CALLABLE: {
|
case CALLABLE: {
|
||||||
const Callable &c = *reinterpret_cast<const Callable *>(_data._mem);
|
const Callable &c = *reinterpret_cast<const Callable *>(_data._mem);
|
||||||
return c;
|
return String(c);
|
||||||
}
|
}
|
||||||
case SIGNAL: {
|
case SIGNAL: {
|
||||||
const Signal &s = *reinterpret_cast<const Signal *>(_data._mem);
|
const Signal &s = *reinterpret_cast<const Signal *>(_data._mem);
|
||||||
return s;
|
return String(s);
|
||||||
}
|
}
|
||||||
case RID: {
|
case RID: {
|
||||||
const ::RID &s = *reinterpret_cast<const ::RID *>(_data._mem);
|
const ::RID &s = *reinterpret_cast<const ::RID *>(_data._mem);
|
||||||
|
|||||||
@@ -2301,6 +2301,7 @@ static void _register_variant_builtin_methods_misc() {
|
|||||||
bind_method(Basis, determinant, sarray(), varray());
|
bind_method(Basis, determinant, sarray(), varray());
|
||||||
bind_methodv(Basis, rotated, static_cast<Basis (Basis::*)(const Vector3 &, real_t) const>(&Basis::rotated), sarray("axis", "angle"), varray());
|
bind_methodv(Basis, rotated, static_cast<Basis (Basis::*)(const Vector3 &, real_t) const>(&Basis::rotated), sarray("axis", "angle"), varray());
|
||||||
bind_method(Basis, scaled, sarray("scale"), varray());
|
bind_method(Basis, scaled, sarray("scale"), varray());
|
||||||
|
bind_method(Basis, scaled_local, sarray("scale"), varray());
|
||||||
bind_method(Basis, get_scale, sarray(), varray());
|
bind_method(Basis, get_scale, sarray(), varray());
|
||||||
bind_method(Basis, get_euler, sarray("order"), varray((int64_t)EulerOrder::YXZ));
|
bind_method(Basis, get_euler, sarray("order"), varray((int64_t)EulerOrder::YXZ));
|
||||||
bind_method(Basis, tdotx, sarray("with"), varray());
|
bind_method(Basis, tdotx, sarray("with"), varray());
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ uint32_t VariantCallable::hash() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String VariantCallable::get_as_text() const {
|
String VariantCallable::get_as_text() const {
|
||||||
return vformat("%s::%s (Callable)", Variant::get_type_name(variant.get_type()), method);
|
return vformat("%s::%s", Variant::get_type_name(variant.get_type()), method);
|
||||||
}
|
}
|
||||||
|
|
||||||
CallableCustom::CompareEqualFunc VariantCallable::get_compare_equal_func() const {
|
CallableCustom::CompareEqualFunc VariantCallable::get_compare_equal_func() const {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include "core/crypto/crypto_core.h"
|
#include "core/crypto/crypto_core.h"
|
||||||
#include "core/io/resource_loader.h"
|
#include "core/io/resource_loader.h"
|
||||||
|
#include "core/io/resource_uid.h"
|
||||||
#include "core/object/script_language.h"
|
#include "core/object/script_language.h"
|
||||||
#include "core/string/string_buffer.h"
|
#include "core/string/string_buffer.h"
|
||||||
|
|
||||||
@@ -1125,13 +1126,55 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
|
|||||||
get_token(p_stream, token, line, r_err_str);
|
get_token(p_stream, token, line, r_err_str);
|
||||||
if (token.type == TK_STRING) {
|
if (token.type == TK_STRING) {
|
||||||
String path = token.value;
|
String path = token.value;
|
||||||
Ref<Resource> res = ResourceLoader::load(path);
|
String uid_string;
|
||||||
|
|
||||||
|
get_token(p_stream, token, line, r_err_str);
|
||||||
|
|
||||||
|
if (path.begins_with("uid://")) {
|
||||||
|
uid_string = path;
|
||||||
|
path = "";
|
||||||
|
}
|
||||||
|
if (token.type == TK_COMMA) {
|
||||||
|
get_token(p_stream, token, line, r_err_str);
|
||||||
|
if (token.type != TK_STRING) {
|
||||||
|
r_err_str = "Expected string in Resource reference";
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
String extra_path = token.value;
|
||||||
|
if (extra_path.begins_with("uid://")) {
|
||||||
|
if (!uid_string.is_empty()) {
|
||||||
|
r_err_str = "Two uid:// paths in one Resource reference";
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
uid_string = extra_path;
|
||||||
|
} else {
|
||||||
|
if (!path.is_empty()) {
|
||||||
|
r_err_str = "Two non-uid paths in one Resource reference";
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
path = extra_path;
|
||||||
|
}
|
||||||
|
get_token(p_stream, token, line, r_err_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Resource> res;
|
||||||
|
if (!uid_string.is_empty()) {
|
||||||
|
ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(uid_string);
|
||||||
|
if (uid != ResourceUID::INVALID_ID && ResourceUID::get_singleton()->has_id(uid)) {
|
||||||
|
const String id_path = ResourceUID::get_singleton()->get_id_path(uid);
|
||||||
|
if (!id_path.is_empty()) {
|
||||||
|
res = ResourceLoader::load(id_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (res.is_null() && !path.is_empty()) {
|
||||||
|
res = ResourceLoader::load(path);
|
||||||
|
}
|
||||||
if (res.is_null()) {
|
if (res.is_null()) {
|
||||||
r_err_str = "Can't load resource at path: " + path;
|
r_err_str = "Can't load resource at path: " + path + " with uid: " + uid_string;
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
get_token(p_stream, token, line, r_err_str);
|
|
||||||
if (token.type != TK_PARENTHESIS_CLOSE) {
|
if (token.type != TK_PARENTHESIS_CLOSE) {
|
||||||
r_err_str = "Expected ')'";
|
r_err_str = "Expected ')'";
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
@@ -1962,6 +2005,16 @@ static String rtos_fix(double p_value, bool p_compat) {
|
|||||||
return String::num_scientific(p_value);
|
return String::num_scientific(p_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String encode_resource_reference(const String &path) {
|
||||||
|
ResourceUID::ID uid = ResourceLoader::get_resource_uid(path);
|
||||||
|
if (uid != ResourceUID::INVALID_ID) {
|
||||||
|
return "Resource(\"" + ResourceUID::get_singleton()->id_to_text(uid) +
|
||||||
|
"\", \"" + path.c_escape_multiline() + "\")";
|
||||||
|
} else {
|
||||||
|
return "Resource(\"" + path.c_escape_multiline() + "\")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count, bool p_compat) {
|
Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count, bool p_compat) {
|
||||||
switch (p_variant.get_type()) {
|
switch (p_variant.get_type()) {
|
||||||
case Variant::NIL: {
|
case Variant::NIL: {
|
||||||
@@ -2148,22 +2201,21 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
|
|||||||
|
|
||||||
Ref<Resource> res = p_variant;
|
Ref<Resource> res = p_variant;
|
||||||
if (res.is_valid()) {
|
if (res.is_valid()) {
|
||||||
//is resource
|
|
||||||
String res_text;
|
String res_text;
|
||||||
|
|
||||||
//try external function
|
// Try external function.
|
||||||
if (p_encode_res_func) {
|
if (p_encode_res_func) {
|
||||||
res_text = p_encode_res_func(p_encode_res_ud, res);
|
res_text = p_encode_res_func(p_encode_res_ud, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
//try path because it's a file
|
// Try path, because it's a file.
|
||||||
if (res_text.is_empty() && res->get_path().is_resource_file()) {
|
if (res_text.is_empty() && res->get_path().is_resource_file()) {
|
||||||
//external resource
|
// External resource.
|
||||||
String path = res->get_path();
|
String path = res->get_path();
|
||||||
res_text = "Resource(\"" + path + "\")";
|
res_text = encode_resource_reference(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
//could come up with some sort of text
|
// Could come up with some sort of text.
|
||||||
if (!res_text.is_empty()) {
|
if (!res_text.is_empty()) {
|
||||||
p_store_string_func(p_store_string_ud, res_text);
|
p_store_string_func(p_store_string_ud, res_text);
|
||||||
break;
|
break;
|
||||||
@@ -2211,7 +2263,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
|
|||||||
resource_text = p_encode_res_func(p_encode_res_ud, key_script);
|
resource_text = p_encode_res_func(p_encode_res_ud, key_script);
|
||||||
}
|
}
|
||||||
if (resource_text.is_empty() && key_script->get_path().is_resource_file()) {
|
if (resource_text.is_empty() && key_script->get_path().is_resource_file()) {
|
||||||
resource_text = "Resource(\"" + key_script->get_path() + "\")";
|
resource_text = encode_resource_reference(key_script->get_path());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resource_text.is_empty()) {
|
if (!resource_text.is_empty()) {
|
||||||
@@ -2240,7 +2292,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
|
|||||||
resource_text = p_encode_res_func(p_encode_res_ud, value_script);
|
resource_text = p_encode_res_func(p_encode_res_ud, value_script);
|
||||||
}
|
}
|
||||||
if (resource_text.is_empty() && value_script->get_path().is_resource_file()) {
|
if (resource_text.is_empty() && value_script->get_path().is_resource_file()) {
|
||||||
resource_text = "Resource(\"" + value_script->get_path() + "\")";
|
resource_text = encode_resource_reference(value_script->get_path());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resource_text.is_empty()) {
|
if (!resource_text.is_empty()) {
|
||||||
@@ -2312,7 +2364,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
|
|||||||
resource_text = p_encode_res_func(p_encode_res_ud, script);
|
resource_text = p_encode_res_func(p_encode_res_ud, script);
|
||||||
}
|
}
|
||||||
if (resource_text.is_empty() && script->get_path().is_resource_file()) {
|
if (resource_text.is_empty() && script->get_path().is_resource_file()) {
|
||||||
resource_text = "Resource(\"" + script->get_path() + "\")";
|
resource_text = encode_resource_reference(script->get_path());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resource_text.is_empty()) {
|
if (!resource_text.is_empty()) {
|
||||||
|
|||||||
@@ -457,8 +457,8 @@
|
|||||||
[codeblock]
|
[codeblock]
|
||||||
print(" (x) (fmod(x, 1.5)) (fposmod(x, 1.5))")
|
print(" (x) (fmod(x, 1.5)) (fposmod(x, 1.5))")
|
||||||
for i in 7:
|
for i in 7:
|
||||||
var x = i * 0.5 - 1.5
|
var x = i * 0.5 - 1.5
|
||||||
print("%4.1f %4.1f | %4.1f" % [x, fmod(x, 1.5), fposmod(x, 1.5)])
|
print("%4.1f %4.1f | %4.1f" % [x, fmod(x, 1.5), fposmod(x, 1.5)])
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
Prints:
|
Prints:
|
||||||
[codeblock lang=text]
|
[codeblock lang=text]
|
||||||
@@ -498,21 +498,21 @@
|
|||||||
var drink = "water"
|
var drink = "water"
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
var id = get_instance_id()
|
var id = get_instance_id()
|
||||||
var instance = instance_from_id(id)
|
var instance = instance_from_id(id)
|
||||||
print(instance.foo) # Prints "water"
|
print(instance.foo) # Prints "water"
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public partial class MyNode : Node
|
public partial class MyNode : Node
|
||||||
{
|
{
|
||||||
public string Drink { get; set; } = "water";
|
public string Drink { get; set; } = "water";
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
ulong id = GetInstanceId();
|
ulong id = GetInstanceId();
|
||||||
var instance = (MyNode)InstanceFromId(Id);
|
var instance = (MyNode)InstanceFromId(Id);
|
||||||
GD.Print(instance.Drink); // Prints "water"
|
GD.Print(instance.Drink); // Prints "water"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -642,10 +642,10 @@
|
|||||||
extends Sprite
|
extends Sprite
|
||||||
var elapsed = 0.0
|
var elapsed = 0.0
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
var min_angle = deg_to_rad(0.0)
|
var min_angle = deg_to_rad(0.0)
|
||||||
var max_angle = deg_to_rad(90.0)
|
var max_angle = deg_to_rad(90.0)
|
||||||
rotation = lerp_angle(min_angle, max_angle, elapsed)
|
rotation = lerp_angle(min_angle, max_angle, elapsed)
|
||||||
elapsed += delta
|
elapsed += delta
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
[b]Note:[/b] This function lerps through the shortest path between [param from] and [param to]. However, when these two angles are approximately [code]PI + k * TAU[/code] apart for any integer [code]k[/code], it's not obvious which way they lerp due to floating-point precision errors. For example, [code]lerp_angle(0, PI, weight)[/code] lerps counter-clockwise, while [code]lerp_angle(0, PI + 5 * TAU, weight)[/code] lerps clockwise.
|
[b]Note:[/b] This function lerps through the shortest path between [param from] and [param to]. However, when these two angles are approximately [code]PI + k * TAU[/code] apart for any integer [code]k[/code], it's not obvious which way they lerp due to floating-point precision errors. For example, [code]lerp_angle(0, PI, weight)[/code] lerps counter-clockwise, while [code]lerp_angle(0, PI + 5 * TAU, weight)[/code] lerps clockwise.
|
||||||
</description>
|
</description>
|
||||||
@@ -815,7 +815,7 @@
|
|||||||
[codeblock]
|
[codeblock]
|
||||||
print("#(i) (i % 3) (posmod(i, 3))")
|
print("#(i) (i % 3) (posmod(i, 3))")
|
||||||
for i in range(-3, 4):
|
for i in range(-3, 4):
|
||||||
print("%2d %2d | %2d" % [i, i % 3, posmod(i, 3)])
|
print("%2d %2d | %2d" % [i, i % 3, posmod(i, 3)])
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
Prints:
|
Prints:
|
||||||
[codeblock lang=text]
|
[codeblock lang=text]
|
||||||
@@ -1507,9 +1507,9 @@
|
|||||||
json.parse('["a", "b", "c"]')
|
json.parse('["a", "b", "c"]')
|
||||||
var result = json.get_data()
|
var result = json.get_data()
|
||||||
if result is Array:
|
if result is Array:
|
||||||
print(result[0]) # Prints "a"
|
print(result[0]) # Prints "a"
|
||||||
else:
|
else:
|
||||||
print("Unexpected result!")
|
print("Unexpected result!")
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
See also [method type_string].
|
See also [method type_string].
|
||||||
</description>
|
</description>
|
||||||
@@ -1549,8 +1549,8 @@
|
|||||||
Prints:
|
Prints:
|
||||||
[codeblock lang=text]
|
[codeblock lang=text]
|
||||||
{
|
{
|
||||||
"a": 1,
|
"a": 1,
|
||||||
"b": 2
|
"b": 2
|
||||||
}
|
}
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
[b]Note:[/b] Converting [Signal] or [Callable] is not supported and will result in an empty value for these types, regardless of their data.
|
[b]Note:[/b] Converting [Signal] or [Callable] is not supported and will result in an empty value for these types, regardless of their data.
|
||||||
@@ -1570,8 +1570,8 @@
|
|||||||
<param index="1" name="min" type="Variant" />
|
<param index="1" name="min" type="Variant" />
|
||||||
<param index="2" name="max" type="Variant" />
|
<param index="2" name="max" type="Variant" />
|
||||||
<description>
|
<description>
|
||||||
Wraps the [Variant] [param value] between [param min] and [param max]. Can be used for creating loop-alike behavior or infinite surfaces.
|
Wraps the [Variant] [param value] between [param min] and [param max]. [param min] is [i]inclusive[/i] while [param max] is [i]exclusive[/i]. This can be used for creating loop-like behavior or infinite surfaces.
|
||||||
Variant types [int] and [float] are supported. If any of the arguments is [float] this function returns a [float], otherwise it returns an [int].
|
Variant types [int] and [float] are supported. If any of the arguments is [float], this function returns a [float], otherwise it returns an [int].
|
||||||
[codeblock]
|
[codeblock]
|
||||||
var a = wrap(4, 5, 10)
|
var a = wrap(4, 5, 10)
|
||||||
# a is 9 (int)
|
# a is 9 (int)
|
||||||
@@ -1590,7 +1590,7 @@
|
|||||||
<param index="1" name="min" type="float" />
|
<param index="1" name="min" type="float" />
|
||||||
<param index="2" name="max" type="float" />
|
<param index="2" name="max" type="float" />
|
||||||
<description>
|
<description>
|
||||||
Wraps the float [param value] between [param min] and [param max]. Can be used for creating loop-alike behavior or infinite surfaces.
|
Wraps the float [param value] between [param min] and [param max]. [param min] is [i]inclusive[/i] while [param max] is [i]exclusive[/i]. This can be used for creating loop-like behavior or infinite surfaces.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
# Infinite loop between 5.0 and 9.9
|
# Infinite loop between 5.0 and 9.9
|
||||||
value = wrapf(value + 0.1, 5.0, 10.0)
|
value = wrapf(value + 0.1, 5.0, 10.0)
|
||||||
@@ -1603,8 +1603,7 @@
|
|||||||
# Infinite rotation (in radians)
|
# Infinite rotation (in radians)
|
||||||
angle = wrapf(angle + 0.1, -PI, PI)
|
angle = wrapf(angle + 0.1, -PI, PI)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
[b]Note:[/b] If [param min] is [code]0[/code], this is equivalent to [method fposmod], so prefer using that instead.
|
[b]Note:[/b] If [param min] is [code]0[/code], this is equivalent to [method fposmod], so prefer using that instead. [method wrapf] is more flexible than using the [method fposmod] approach by giving the user control over the minimum value.
|
||||||
[method wrapf] is more flexible than using the [method fposmod] approach by giving the user control over the minimum value.
|
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="wrapi">
|
<method name="wrapi">
|
||||||
@@ -1613,7 +1612,7 @@
|
|||||||
<param index="1" name="min" type="int" />
|
<param index="1" name="min" type="int" />
|
||||||
<param index="2" name="max" type="int" />
|
<param index="2" name="max" type="int" />
|
||||||
<description>
|
<description>
|
||||||
Wraps the integer [param value] between [param min] and [param max]. Can be used for creating loop-alike behavior or infinite surfaces.
|
Wraps the integer [param value] between [param min] and [param max]. [param min] is [i]inclusive[/i] while [param max] is [i]exclusive[/i]. This can be used for creating loop-like behavior or infinite surfaces.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
# Infinite loop between 5 and 9
|
# Infinite loop between 5 and 9
|
||||||
frame = wrapi(frame + 1, 5, 10)
|
frame = wrapi(frame + 1, 5, 10)
|
||||||
@@ -2691,11 +2690,11 @@
|
|||||||
[codeblock]
|
[codeblock]
|
||||||
var error = method_that_returns_error()
|
var error = method_that_returns_error()
|
||||||
if error != OK:
|
if error != OK:
|
||||||
printerr("Failure!")
|
printerr("Failure!")
|
||||||
|
|
||||||
# Or, alternatively:
|
# Or, alternatively:
|
||||||
if error:
|
if error:
|
||||||
printerr("Still failing!")
|
printerr("Still failing!")
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
[b]Note:[/b] Many functions do not return an error code, but will print error messages to standard output.
|
[b]Note:[/b] Many functions do not return an error code, but will print error messages to standard output.
|
||||||
</constant>
|
</constant>
|
||||||
@@ -3162,7 +3161,7 @@
|
|||||||
Used internally. Allows to not dump core virtual methods (such as [method Object._notification]) to the JSON API.
|
Used internally. Allows to not dump core virtual methods (such as [method Object._notification]) to the JSON API.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="METHOD_FLAG_VIRTUAL_REQUIRED" value="128" enum="MethodFlags" is_bitfield="true">
|
<constant name="METHOD_FLAG_VIRTUAL_REQUIRED" value="128" enum="MethodFlags" is_bitfield="true">
|
||||||
Flag for a virtual method that is required.
|
Flag for a virtual method that is required. In GDScript, this flag is set for abstract functions.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="METHOD_FLAGS_DEFAULT" value="1" enum="MethodFlags" is_bitfield="true">
|
<constant name="METHOD_FLAGS_DEFAULT" value="1" enum="MethodFlags" is_bitfield="true">
|
||||||
Default method flags (normal).
|
Default method flags (normal).
|
||||||
|
|||||||
@@ -12,30 +12,30 @@
|
|||||||
var aes = AESContext.new()
|
var aes = AESContext.new()
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
var key = "My secret key!!!" # Key must be either 16 or 32 bytes.
|
var key = "My secret key!!!" # Key must be either 16 or 32 bytes.
|
||||||
var data = "My secret text!!" # Data size must be multiple of 16 bytes, apply padding if needed.
|
var data = "My secret text!!" # Data size must be multiple of 16 bytes, apply padding if needed.
|
||||||
# Encrypt ECB
|
# Encrypt ECB
|
||||||
aes.start(AESContext.MODE_ECB_ENCRYPT, key.to_utf8_buffer())
|
aes.start(AESContext.MODE_ECB_ENCRYPT, key.to_utf8_buffer())
|
||||||
var encrypted = aes.update(data.to_utf8_buffer())
|
var encrypted = aes.update(data.to_utf8_buffer())
|
||||||
aes.finish()
|
aes.finish()
|
||||||
# Decrypt ECB
|
# Decrypt ECB
|
||||||
aes.start(AESContext.MODE_ECB_DECRYPT, key.to_utf8_buffer())
|
aes.start(AESContext.MODE_ECB_DECRYPT, key.to_utf8_buffer())
|
||||||
var decrypted = aes.update(encrypted)
|
var decrypted = aes.update(encrypted)
|
||||||
aes.finish()
|
aes.finish()
|
||||||
# Check ECB
|
# Check ECB
|
||||||
assert(decrypted == data.to_utf8_buffer())
|
assert(decrypted == data.to_utf8_buffer())
|
||||||
|
|
||||||
var iv = "My secret iv!!!!" # IV must be of exactly 16 bytes.
|
var iv = "My secret iv!!!!" # IV must be of exactly 16 bytes.
|
||||||
# Encrypt CBC
|
# Encrypt CBC
|
||||||
aes.start(AESContext.MODE_CBC_ENCRYPT, key.to_utf8_buffer(), iv.to_utf8_buffer())
|
aes.start(AESContext.MODE_CBC_ENCRYPT, key.to_utf8_buffer(), iv.to_utf8_buffer())
|
||||||
encrypted = aes.update(data.to_utf8_buffer())
|
encrypted = aes.update(data.to_utf8_buffer())
|
||||||
aes.finish()
|
aes.finish()
|
||||||
# Decrypt CBC
|
# Decrypt CBC
|
||||||
aes.start(AESContext.MODE_CBC_DECRYPT, key.to_utf8_buffer(), iv.to_utf8_buffer())
|
aes.start(AESContext.MODE_CBC_DECRYPT, key.to_utf8_buffer(), iv.to_utf8_buffer())
|
||||||
decrypted = aes.update(encrypted)
|
decrypted = aes.update(encrypted)
|
||||||
aes.finish()
|
aes.finish()
|
||||||
# Check CBC
|
# Check CBC
|
||||||
assert(decrypted == data.to_utf8_buffer())
|
assert(decrypted == data.to_utf8_buffer())
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
using Godot;
|
using Godot;
|
||||||
@@ -43,35 +43,35 @@
|
|||||||
|
|
||||||
public partial class MyNode : Node
|
public partial class MyNode : Node
|
||||||
{
|
{
|
||||||
private AesContext _aes = new AesContext();
|
private AesContext _aes = new AesContext();
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
string key = "My secret key!!!"; // Key must be either 16 or 32 bytes.
|
string key = "My secret key!!!"; // Key must be either 16 or 32 bytes.
|
||||||
string data = "My secret text!!"; // Data size must be multiple of 16 bytes, apply padding if needed.
|
string data = "My secret text!!"; // Data size must be multiple of 16 bytes, apply padding if needed.
|
||||||
// Encrypt ECB
|
// Encrypt ECB
|
||||||
_aes.Start(AesContext.Mode.EcbEncrypt, key.ToUtf8Buffer());
|
_aes.Start(AesContext.Mode.EcbEncrypt, key.ToUtf8Buffer());
|
||||||
byte[] encrypted = _aes.Update(data.ToUtf8Buffer());
|
byte[] encrypted = _aes.Update(data.ToUtf8Buffer());
|
||||||
_aes.Finish();
|
_aes.Finish();
|
||||||
// Decrypt ECB
|
// Decrypt ECB
|
||||||
_aes.Start(AesContext.Mode.EcbDecrypt, key.ToUtf8Buffer());
|
_aes.Start(AesContext.Mode.EcbDecrypt, key.ToUtf8Buffer());
|
||||||
byte[] decrypted = _aes.Update(encrypted);
|
byte[] decrypted = _aes.Update(encrypted);
|
||||||
_aes.Finish();
|
_aes.Finish();
|
||||||
// Check ECB
|
// Check ECB
|
||||||
Debug.Assert(decrypted == data.ToUtf8Buffer());
|
Debug.Assert(decrypted == data.ToUtf8Buffer());
|
||||||
|
|
||||||
string iv = "My secret iv!!!!"; // IV must be of exactly 16 bytes.
|
string iv = "My secret iv!!!!"; // IV must be of exactly 16 bytes.
|
||||||
// Encrypt CBC
|
// Encrypt CBC
|
||||||
_aes.Start(AesContext.Mode.EcbEncrypt, key.ToUtf8Buffer(), iv.ToUtf8Buffer());
|
_aes.Start(AesContext.Mode.EcbEncrypt, key.ToUtf8Buffer(), iv.ToUtf8Buffer());
|
||||||
encrypted = _aes.Update(data.ToUtf8Buffer());
|
encrypted = _aes.Update(data.ToUtf8Buffer());
|
||||||
_aes.Finish();
|
_aes.Finish();
|
||||||
// Decrypt CBC
|
// Decrypt CBC
|
||||||
_aes.Start(AesContext.Mode.EcbDecrypt, key.ToUtf8Buffer(), iv.ToUtf8Buffer());
|
_aes.Start(AesContext.Mode.EcbDecrypt, key.ToUtf8Buffer(), iv.ToUtf8Buffer());
|
||||||
decrypted = _aes.Update(encrypted);
|
decrypted = _aes.Update(encrypted);
|
||||||
_aes.Finish();
|
_aes.Finish();
|
||||||
// Check CBC
|
// Check CBC
|
||||||
Debug.Assert(decrypted == data.ToUtf8Buffer());
|
Debug.Assert(decrypted == data.ToUtf8Buffer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
|
|||||||
@@ -14,14 +14,14 @@
|
|||||||
extends AStar3D
|
extends AStar3D
|
||||||
|
|
||||||
func _compute_cost(u, v):
|
func _compute_cost(u, v):
|
||||||
var u_pos = get_point_position(u)
|
var u_pos = get_point_position(u)
|
||||||
var v_pos = get_point_position(v)
|
var v_pos = get_point_position(v)
|
||||||
return abs(u_pos.x - v_pos.x) + abs(u_pos.y - v_pos.y) + abs(u_pos.z - v_pos.z)
|
return abs(u_pos.x - v_pos.x) + abs(u_pos.y - v_pos.y) + abs(u_pos.z - v_pos.z)
|
||||||
|
|
||||||
func _estimate_cost(u, v):
|
func _estimate_cost(u, v):
|
||||||
var u_pos = get_point_position(u)
|
var u_pos = get_point_position(u)
|
||||||
var v_pos = get_point_position(v)
|
var v_pos = get_point_position(v)
|
||||||
return abs(u_pos.x - v_pos.x) + abs(u_pos.y - v_pos.y) + abs(u_pos.z - v_pos.z)
|
return abs(u_pos.x - v_pos.x) + abs(u_pos.y - v_pos.y) + abs(u_pos.z - v_pos.z)
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
using Godot;
|
using Godot;
|
||||||
@@ -29,20 +29,20 @@
|
|||||||
[GlobalClass]
|
[GlobalClass]
|
||||||
public partial class MyAStar3D : AStar3D
|
public partial class MyAStar3D : AStar3D
|
||||||
{
|
{
|
||||||
public override float _ComputeCost(long fromId, long toId)
|
public override float _ComputeCost(long fromId, long toId)
|
||||||
{
|
{
|
||||||
Vector3 fromPoint = GetPointPosition(fromId);
|
Vector3 fromPoint = GetPointPosition(fromId);
|
||||||
Vector3 toPoint = GetPointPosition(toId);
|
Vector3 toPoint = GetPointPosition(toId);
|
||||||
|
|
||||||
return Mathf.Abs(fromPoint.X - toPoint.X) + Mathf.Abs(fromPoint.Y - toPoint.Y) + Mathf.Abs(fromPoint.Z - toPoint.Z);
|
return Mathf.Abs(fromPoint.X - toPoint.X) + Mathf.Abs(fromPoint.Y - toPoint.Y) + Mathf.Abs(fromPoint.Z - toPoint.Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override float _EstimateCost(long fromId, long toId)
|
public override float _EstimateCost(long fromId, long toId)
|
||||||
{
|
{
|
||||||
Vector3 fromPoint = GetPointPosition(fromId);
|
Vector3 fromPoint = GetPointPosition(fromId);
|
||||||
Vector3 toPoint = GetPointPosition(toId);
|
Vector3 toPoint = GetPointPosition(toId);
|
||||||
return Mathf.Abs(fromPoint.X - toPoint.X) + Mathf.Abs(fromPoint.Y - toPoint.Y) + Mathf.Abs(fromPoint.Z - toPoint.Z);
|
return Mathf.Abs(fromPoint.X - toPoint.X) + Mathf.Abs(fromPoint.Y - toPoint.Y) + Mathf.Abs(fromPoint.Z - toPoint.Z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
|
|||||||
@@ -115,24 +115,24 @@
|
|||||||
var current_rotation
|
var current_rotation
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
if Input.is_action_just_pressed("animate"):
|
if Input.is_action_just_pressed("animate"):
|
||||||
current_rotation = get_quaternion()
|
current_rotation = get_quaternion()
|
||||||
state_machine.travel("Animate")
|
state_machine.travel("Animate")
|
||||||
var velocity = current_rotation * animation_tree.get_root_motion_position() / delta
|
var velocity = current_rotation * animation_tree.get_root_motion_position() / delta
|
||||||
set_velocity(velocity)
|
set_velocity(velocity)
|
||||||
move_and_slide()
|
move_and_slide()
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
By using this in combination with [method get_root_motion_rotation_accumulator], you can apply the root motion position more correctly to account for the rotation of the node.
|
By using this in combination with [method get_root_motion_rotation_accumulator], you can apply the root motion position more correctly to account for the rotation of the node.
|
||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
if Input.is_action_just_pressed("animate"):
|
if Input.is_action_just_pressed("animate"):
|
||||||
state_machine.travel("Animate")
|
state_machine.travel("Animate")
|
||||||
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
|
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
|
||||||
var velocity = (animation_tree.get_root_motion_rotation_accumulator().inverse() * get_quaternion()) * animation_tree.get_root_motion_position() / delta
|
var velocity = (animation_tree.get_root_motion_rotation_accumulator().inverse() * get_quaternion()) * animation_tree.get_root_motion_position() / delta
|
||||||
set_velocity(velocity)
|
set_velocity(velocity)
|
||||||
move_and_slide()
|
move_and_slide()
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
If [member root_motion_local] is [code]true[/code], returns the pre-multiplied translation value with the inverted rotation.
|
If [member root_motion_local] is [code]true[/code], returns the pre-multiplied translation value with the inverted rotation.
|
||||||
@@ -140,12 +140,12 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
if Input.is_action_just_pressed("animate"):
|
if Input.is_action_just_pressed("animate"):
|
||||||
state_machine.travel("Animate")
|
state_machine.travel("Animate")
|
||||||
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
|
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
|
||||||
var velocity = get_quaternion() * animation_tree.get_root_motion_position() / delta
|
var velocity = get_quaternion() * animation_tree.get_root_motion_position() / delta
|
||||||
set_velocity(velocity)
|
set_velocity(velocity)
|
||||||
move_and_slide()
|
move_and_slide()
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
</description>
|
</description>
|
||||||
@@ -161,12 +161,12 @@
|
|||||||
var prev_root_motion_position_accumulator
|
var prev_root_motion_position_accumulator
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
if Input.is_action_just_pressed("animate"):
|
if Input.is_action_just_pressed("animate"):
|
||||||
state_machine.travel("Animate")
|
state_machine.travel("Animate")
|
||||||
var current_root_motion_position_accumulator = animation_tree.get_root_motion_position_accumulator()
|
var current_root_motion_position_accumulator = animation_tree.get_root_motion_position_accumulator()
|
||||||
var difference = current_root_motion_position_accumulator - prev_root_motion_position_accumulator
|
var difference = current_root_motion_position_accumulator - prev_root_motion_position_accumulator
|
||||||
prev_root_motion_position_accumulator = current_root_motion_position_accumulator
|
prev_root_motion_position_accumulator = current_root_motion_position_accumulator
|
||||||
transform.origin += difference
|
transform.origin += difference
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases.
|
However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases.
|
||||||
@@ -182,9 +182,9 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
if Input.is_action_just_pressed("animate"):
|
if Input.is_action_just_pressed("animate"):
|
||||||
state_machine.travel("Animate")
|
state_machine.travel("Animate")
|
||||||
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
|
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
</description>
|
</description>
|
||||||
@@ -201,12 +201,12 @@
|
|||||||
var prev_root_motion_rotation_accumulator
|
var prev_root_motion_rotation_accumulator
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
if Input.is_action_just_pressed("animate"):
|
if Input.is_action_just_pressed("animate"):
|
||||||
state_machine.travel("Animate")
|
state_machine.travel("Animate")
|
||||||
var current_root_motion_rotation_accumulator = animation_tree.get_root_motion_rotation_accumulator()
|
var current_root_motion_rotation_accumulator = animation_tree.get_root_motion_rotation_accumulator()
|
||||||
var difference = prev_root_motion_rotation_accumulator.inverse() * current_root_motion_rotation_accumulator
|
var difference = prev_root_motion_rotation_accumulator.inverse() * current_root_motion_rotation_accumulator
|
||||||
prev_root_motion_rotation_accumulator = current_root_motion_rotation_accumulator
|
prev_root_motion_rotation_accumulator = current_root_motion_rotation_accumulator
|
||||||
transform.basis *= Basis(difference)
|
transform.basis *= Basis(difference)
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases.
|
However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases.
|
||||||
@@ -225,12 +225,12 @@
|
|||||||
var scale_accum = Vector3(1, 1, 1)
|
var scale_accum = Vector3(1, 1, 1)
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
if Input.is_action_just_pressed("animate"):
|
if Input.is_action_just_pressed("animate"):
|
||||||
current_scale = get_scale()
|
current_scale = get_scale()
|
||||||
scale_accum = Vector3(1, 1, 1)
|
scale_accum = Vector3(1, 1, 1)
|
||||||
state_machine.travel("Animate")
|
state_machine.travel("Animate")
|
||||||
scale_accum += animation_tree.get_root_motion_scale()
|
scale_accum += animation_tree.get_root_motion_scale()
|
||||||
set_scale(current_scale * scale_accum)
|
set_scale(current_scale * scale_accum)
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
</description>
|
</description>
|
||||||
@@ -245,12 +245,12 @@
|
|||||||
var prev_root_motion_scale_accumulator
|
var prev_root_motion_scale_accumulator
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
if Input.is_action_just_pressed("animate"):
|
if Input.is_action_just_pressed("animate"):
|
||||||
state_machine.travel("Animate")
|
state_machine.travel("Animate")
|
||||||
var current_root_motion_scale_accumulator = animation_tree.get_root_motion_scale_accumulator()
|
var current_root_motion_scale_accumulator = animation_tree.get_root_motion_scale_accumulator()
|
||||||
var difference = current_root_motion_scale_accumulator - prev_root_motion_scale_accumulator
|
var difference = current_root_motion_scale_accumulator - prev_root_motion_scale_accumulator
|
||||||
prev_root_motion_scale_accumulator = current_root_motion_scale_accumulator
|
prev_root_motion_scale_accumulator = current_root_motion_scale_accumulator
|
||||||
transform.basis = transform.basis.scaled(difference)
|
transform.basis = transform.basis.scaled(difference)
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases.
|
However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases.
|
||||||
|
|||||||
@@ -93,4 +93,19 @@
|
|||||||
<members>
|
<members>
|
||||||
<member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="true" />
|
<member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="true" />
|
||||||
</members>
|
</members>
|
||||||
|
<signals>
|
||||||
|
<signal name="state_finished">
|
||||||
|
<param index="0" name="state" type="StringName" />
|
||||||
|
<description>
|
||||||
|
Emitted when the [param state] finishes playback. If [param state] is a state machine set to grouped mode, its signals are passed through with its name prefixed.
|
||||||
|
If there is a crossfade, this will be fired when the influence of the [method get_fading_from_node] animation is no longer present.
|
||||||
|
</description>
|
||||||
|
</signal>
|
||||||
|
<signal name="state_started">
|
||||||
|
<param index="0" name="state" type="StringName" />
|
||||||
|
<description>
|
||||||
|
Emitted when the [param state] starts playback. If [param state] is a state machine set to grouped mode, its signals are passed through with its name prefixed.
|
||||||
|
</description>
|
||||||
|
</signal>
|
||||||
|
</signals>
|
||||||
</class>
|
</class>
|
||||||
|
|||||||
@@ -57,13 +57,13 @@
|
|||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
class Stats:
|
class Stats:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
var a = Array([], TYPE_INT, "", null) # Array[int]
|
var a = Array([], TYPE_INT, "", null) # Array[int]
|
||||||
var b = Array([], TYPE_OBJECT, "Node", null) # Array[Node]
|
var b = Array([], TYPE_OBJECT, "Node", null) # Array[Node]
|
||||||
var c = Array([], TYPE_OBJECT, "Node", Sword) # Array[Sword]
|
var c = Array([], TYPE_OBJECT, "Node", Sword) # Array[Sword]
|
||||||
var d = Array([], TYPE_OBJECT, "RefCounted", Stats) # Array[Stats]
|
var d = Array([], TYPE_OBJECT, "RefCounted", Stats) # Array[Stats]
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
The [param base] array's elements are converted when necessary. If this is not possible or [param base] is already typed, this constructor fails and returns an empty [Array].
|
The [param base] array's elements are converted when necessary. If this is not possible or [param base] is already typed, this constructor fails and returns an empty [Array].
|
||||||
In GDScript, this constructor is usually not necessary, as it is possible to create a typed array through static typing:
|
In GDScript, this constructor is usually not necessary, as it is possible to create a typed array through static typing:
|
||||||
@@ -164,36 +164,36 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func greater_than_5(number):
|
func greater_than_5(number):
|
||||||
return number > 5
|
return number > 5
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
print([6, 10, 6].all(greater_than_5)) # Prints true (3/3 elements evaluate to true).
|
print([6, 10, 6].all(greater_than_5)) # Prints true (3/3 elements evaluate to true).
|
||||||
print([4, 10, 4].all(greater_than_5)) # Prints false (1/3 elements evaluate to true).
|
print([4, 10, 4].all(greater_than_5)) # Prints false (1/3 elements evaluate to true).
|
||||||
print([4, 4, 4].all(greater_than_5)) # Prints false (0/3 elements evaluate to true).
|
print([4, 4, 4].all(greater_than_5)) # Prints false (0/3 elements evaluate to true).
|
||||||
print([].all(greater_than_5)) # Prints true (0/0 elements evaluate to true).
|
print([].all(greater_than_5)) # Prints true (0/0 elements evaluate to true).
|
||||||
|
|
||||||
# Same as the first line above, but using a lambda function.
|
# Same as the first line above, but using a lambda function.
|
||||||
print([6, 10, 6].all(func(element): return element > 5)) # Prints true
|
print([6, 10, 6].all(func(element): return element > 5)) # Prints true
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
private static bool GreaterThan5(int number)
|
private static bool GreaterThan5(int number)
|
||||||
{
|
{
|
||||||
return number > 5;
|
return number > 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
// Prints True (3/3 elements evaluate to true).
|
// Prints True (3/3 elements evaluate to true).
|
||||||
GD.Print(new Godot.Collections.Array>int< { 6, 10, 6 }.All(GreaterThan5));
|
GD.Print(new Godot.Collections.Array>int< { 6, 10, 6 }.All(GreaterThan5));
|
||||||
// Prints False (1/3 elements evaluate to true).
|
// Prints False (1/3 elements evaluate to true).
|
||||||
GD.Print(new Godot.Collections.Array>int< { 4, 10, 4 }.All(GreaterThan5));
|
GD.Print(new Godot.Collections.Array>int< { 4, 10, 4 }.All(GreaterThan5));
|
||||||
// Prints False (0/3 elements evaluate to true).
|
// Prints False (0/3 elements evaluate to true).
|
||||||
GD.Print(new Godot.Collections.Array>int< { 4, 4, 4 }.All(GreaterThan5));
|
GD.Print(new Godot.Collections.Array>int< { 4, 4, 4 }.All(GreaterThan5));
|
||||||
// Prints True (0/0 elements evaluate to true).
|
// Prints True (0/0 elements evaluate to true).
|
||||||
GD.Print(new Godot.Collections.Array>int< { }.All(GreaterThan5));
|
GD.Print(new Godot.Collections.Array>int< { }.All(GreaterThan5));
|
||||||
|
|
||||||
// Same as the first line above, but using a lambda function.
|
// Same as the first line above, but using a lambda function.
|
||||||
GD.Print(new Godot.Collections.Array>int< { 6, 10, 6 }.All(element => element > 5)); // Prints True
|
GD.Print(new Godot.Collections.Array>int< { 6, 10, 6 }.All(element => element > 5)); // Prints True
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -210,16 +210,16 @@
|
|||||||
The [param method] should take one [Variant] parameter (the current array element) and return a [bool].
|
The [param method] should take one [Variant] parameter (the current array element) and return a [bool].
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func greater_than_5(number):
|
func greater_than_5(number):
|
||||||
return number > 5
|
return number > 5
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
print([6, 10, 6].any(greater_than_5)) # Prints true (3 elements evaluate to true).
|
print([6, 10, 6].any(greater_than_5)) # Prints true (3 elements evaluate to true).
|
||||||
print([4, 10, 4].any(greater_than_5)) # Prints true (1 elements evaluate to true).
|
print([4, 10, 4].any(greater_than_5)) # Prints true (1 elements evaluate to true).
|
||||||
print([4, 4, 4].any(greater_than_5)) # Prints false (0 elements evaluate to true).
|
print([4, 4, 4].any(greater_than_5)) # Prints false (0 elements evaluate to true).
|
||||||
print([].any(greater_than_5)) # Prints false (0 elements evaluate to true).
|
print([].any(greater_than_5)) # Prints false (0 elements evaluate to true).
|
||||||
|
|
||||||
# Same as the first line above, but using a lambda function.
|
# Same as the first line above, but using a lambda function.
|
||||||
print([6, 10, 6].any(func(number): return number > 5)) # Prints true
|
print([6, 10, 6].any(func(number): return number > 5)) # Prints true
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
See also [method all], [method filter], [method map] and [method reduce].
|
See also [method all], [method filter], [method map] and [method reduce].
|
||||||
[b]Note:[/b] Unlike relying on the size of an array returned by [method filter], this method will return as early as possible to improve performance (especially with large arrays).
|
[b]Note:[/b] Unlike relying on the size of an array returned by [method filter], this method will return as early as possible to improve performance (especially with large arrays).
|
||||||
@@ -292,23 +292,23 @@
|
|||||||
If [param before] is [code]true[/code] (as by default), the returned index comes before all existing elements equal to [param value] in the array.
|
If [param before] is [code]true[/code] (as by default), the returned index comes before all existing elements equal to [param value] in the array.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func sort_by_amount(a, b):
|
func sort_by_amount(a, b):
|
||||||
if a[1] < b[1]:
|
if a[1] < b[1]:
|
||||||
return true
|
return true
|
||||||
return false
|
return false
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
var my_items = [["Tomato", 2], ["Kiwi", 5], ["Rice", 9]]
|
var my_items = [["Tomato", 2], ["Kiwi", 5], ["Rice", 9]]
|
||||||
|
|
||||||
var apple = ["Apple", 5]
|
var apple = ["Apple", 5]
|
||||||
# "Apple" is inserted before "Kiwi".
|
# "Apple" is inserted before "Kiwi".
|
||||||
my_items.insert(my_items.bsearch_custom(apple, sort_by_amount, true), apple)
|
my_items.insert(my_items.bsearch_custom(apple, sort_by_amount, true), apple)
|
||||||
|
|
||||||
var banana = ["Banana", 5]
|
var banana = ["Banana", 5]
|
||||||
# "Banana" is inserted after "Kiwi".
|
# "Banana" is inserted after "Kiwi".
|
||||||
my_items.insert(my_items.bsearch_custom(banana, sort_by_amount, false), banana)
|
my_items.insert(my_items.bsearch_custom(banana, sort_by_amount, false), banana)
|
||||||
|
|
||||||
# Prints [["Tomato", 2], ["Apple", 5], ["Kiwi", 5], ["Banana", 5], ["Rice", 9]]
|
# Prints [["Tomato", 2], ["Apple", 5], ["Kiwi", 5], ["Banana", 5], ["Rice", 9]]
|
||||||
print(my_items)
|
print(my_items)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
[b]Note:[/b] Calling [method bsearch_custom] on an [i]unsorted[/i] array will result in unexpected behavior. Use [method sort_custom] with [param func] before calling this method.
|
[b]Note:[/b] Calling [method bsearch_custom] on an [i]unsorted[/i] array will result in unexpected behavior. Use [method sort_custom] with [param func] before calling this method.
|
||||||
</description>
|
</description>
|
||||||
@@ -384,13 +384,13 @@
|
|||||||
The [param method] receives one of the array elements as an argument, and should return [code]true[/code] to add the element to the filtered array, or [code]false[/code] to exclude it.
|
The [param method] receives one of the array elements as an argument, and should return [code]true[/code] to add the element to the filtered array, or [code]false[/code] to exclude it.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func is_even(number):
|
func is_even(number):
|
||||||
return number % 2 == 0
|
return number % 2 == 0
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
print([1, 4, 5, 8].filter(is_even)) # Prints [4, 8]
|
print([1, 4, 5, 8].filter(is_even)) # Prints [4, 8]
|
||||||
|
|
||||||
# Same as above, but using a lambda function.
|
# Same as above, but using a lambda function.
|
||||||
print([1, 4, 5, 8].filter(func(number): return number % 2 == 0))
|
print([1, 4, 5, 8].filter(func(number): return number % 2 == 0))
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
See also [method any], [method all], [method map] and [method reduce].
|
See also [method any], [method all], [method map] and [method reduce].
|
||||||
</description>
|
</description>
|
||||||
@@ -416,10 +416,10 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func is_even(number):
|
func is_even(number):
|
||||||
return number % 2 == 0
|
return number % 2 == 0
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
print([1, 3, 4, 7].find_custom(is_even.bind())) # Prints 2
|
print([1, 3, 4, 7].find_custom(is_even.bind())) # Prints 2
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
</description>
|
</description>
|
||||||
@@ -481,7 +481,7 @@
|
|||||||
In GDScript, this is equivalent to the [code]in[/code] operator:
|
In GDScript, this is equivalent to the [code]in[/code] operator:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
if 4 in [2, 4, 6, 8]:
|
if 4 in [2, 4, 6, 8]:
|
||||||
print("4 is here!") # Will be printed.
|
print("4 is here!") # Will be printed.
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
[b]Note:[/b] For performance reasons, the search is affected by the [param value]'s [enum Variant.Type]. For example, [code]7[/code] ([int]) and [code]7.0[/code] ([float]) are not considered equal for this method.
|
[b]Note:[/b] For performance reasons, the search is affected by the [param value]'s [enum Variant.Type]. For example, [code]7[/code] ([int]) and [code]7.0[/code] ([float]) are not considered equal for this method.
|
||||||
</description>
|
</description>
|
||||||
@@ -549,13 +549,13 @@
|
|||||||
The [param method] should take one [Variant] parameter (the current array element) and can return any [Variant].
|
The [param method] should take one [Variant] parameter (the current array element) and can return any [Variant].
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func double(number):
|
func double(number):
|
||||||
return number * 2
|
return number * 2
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
print([1, 2, 3].map(double)) # Prints [2, 4, 6]
|
print([1, 2, 3].map(double)) # Prints [2, 4, 6]
|
||||||
|
|
||||||
# Same as above, but using a lambda function.
|
# Same as above, but using a lambda function.
|
||||||
print([1, 2, 3].map(func(element): return element * 2))
|
print([1, 2, 3].map(func(element): return element * 2))
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
See also [method filter], [method reduce], [method any] and [method all].
|
See also [method filter], [method reduce], [method any] and [method all].
|
||||||
</description>
|
</description>
|
||||||
@@ -635,36 +635,36 @@
|
|||||||
The [param method] takes two arguments: the current value of [param accum] and the current array element. If [param accum] is [code]null[/code] (as by default), the iteration will start from the second element, with the first one used as initial value of [param accum].
|
The [param method] takes two arguments: the current value of [param accum] and the current array element. If [param accum] is [code]null[/code] (as by default), the iteration will start from the second element, with the first one used as initial value of [param accum].
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func sum(accum, number):
|
func sum(accum, number):
|
||||||
return accum + number
|
return accum + number
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
print([1, 2, 3].reduce(sum, 0)) # Prints 6
|
print([1, 2, 3].reduce(sum, 0)) # Prints 6
|
||||||
print([1, 2, 3].reduce(sum, 10)) # Prints 16
|
print([1, 2, 3].reduce(sum, 10)) # Prints 16
|
||||||
|
|
||||||
# Same as above, but using a lambda function.
|
# Same as above, but using a lambda function.
|
||||||
print([1, 2, 3].reduce(func(accum, number): return accum + number, 10))
|
print([1, 2, 3].reduce(func(accum, number): return accum + number, 10))
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
If [method max] is not desirable, this method may also be used to implement a custom comparator:
|
If [method max] is not desirable, this method may also be used to implement a custom comparator:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _ready():
|
func _ready():
|
||||||
var arr = [Vector2i(5, 0), Vector2i(3, 4), Vector2i(1, 2)]
|
var arr = [Vector2i(5, 0), Vector2i(3, 4), Vector2i(1, 2)]
|
||||||
|
|
||||||
var longest_vec = arr.reduce(func(max, vec): return vec if is_length_greater(vec, max) else max)
|
var longest_vec = arr.reduce(func(max, vec): return vec if is_length_greater(vec, max) else max)
|
||||||
print(longest_vec) # Prints (3, 4)
|
print(longest_vec) # Prints (3, 4)
|
||||||
|
|
||||||
func is_length_greater(a, b):
|
func is_length_greater(a, b):
|
||||||
return a.length() > b.length()
|
return a.length() > b.length()
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
This method can also be used to count how many elements in an array satisfy a certain condition, similar to [method count]:
|
This method can also be used to count how many elements in an array satisfy a certain condition, similar to [method count]:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func is_even(number):
|
func is_even(number):
|
||||||
return number % 2 == 0
|
return number % 2 == 0
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
var arr = [1, 2, 3, 4, 5]
|
var arr = [1, 2, 3, 4, 5]
|
||||||
# If the current element is even, increment count, otherwise leave count the same.
|
# If the current element is even, increment count, otherwise leave count the same.
|
||||||
var even_count = arr.reduce(func(count, next): return count + 1 if is_even(next) else count, 0)
|
var even_count = arr.reduce(func(count, next): return count + 1 if is_even(next) else count, 0)
|
||||||
print(even_count) # Prints 2
|
print(even_count) # Prints 2
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
See also [method map], [method filter], [method any], and [method all].
|
See also [method map], [method filter], [method any], and [method all].
|
||||||
</description>
|
</description>
|
||||||
@@ -781,18 +781,18 @@
|
|||||||
[param func] is called as many times as necessary, receiving two array elements as arguments. The function should return [code]true[/code] if the first element should be moved [i]before[/i] the second one, otherwise it should return [code]false[/code].
|
[param func] is called as many times as necessary, receiving two array elements as arguments. The function should return [code]true[/code] if the first element should be moved [i]before[/i] the second one, otherwise it should return [code]false[/code].
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func sort_ascending(a, b):
|
func sort_ascending(a, b):
|
||||||
if a[1] < b[1]:
|
if a[1] < b[1]:
|
||||||
return true
|
return true
|
||||||
return false
|
return false
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
var my_items = [["Tomato", 5], ["Apple", 9], ["Rice", 4]]
|
var my_items = [["Tomato", 5], ["Apple", 9], ["Rice", 4]]
|
||||||
my_items.sort_custom(sort_ascending)
|
my_items.sort_custom(sort_ascending)
|
||||||
print(my_items) # Prints [["Rice", 4], ["Tomato", 5], ["Apple", 9]]
|
print(my_items) # Prints [["Rice", 4], ["Tomato", 5], ["Apple", 9]]
|
||||||
|
|
||||||
# Sort descending, using a lambda function.
|
# Sort descending, using a lambda function.
|
||||||
my_items.sort_custom(func(a, b): return a[1] > b[1])
|
my_items.sort_custom(func(a, b): return a[1] > b[1])
|
||||||
print(my_items) # Prints [["Apple", 9], ["Tomato", 5], ["Rice", 4]]
|
print(my_items) # Prints [["Apple", 9], ["Tomato", 5], ["Rice", 4]]
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
It may also be necessary to use this method to sort strings by natural order, with [method String.naturalnocasecmp_to], as in the following example:
|
It may also be necessary to use this method to sort strings by natural order, with [method String.naturalnocasecmp_to], as in the following example:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
|
|||||||
@@ -27,9 +27,9 @@
|
|||||||
[csharp]
|
[csharp]
|
||||||
Vector3[] vertices =
|
Vector3[] vertices =
|
||||||
[
|
[
|
||||||
new Vector3(0, 1, 0),
|
new Vector3(0, 1, 0),
|
||||||
new Vector3(1, 0, 0),
|
new Vector3(1, 0, 0),
|
||||||
new Vector3(0, 0, 1),
|
new Vector3(0, 0, 1),
|
||||||
];
|
];
|
||||||
|
|
||||||
// Initialize the ArrayMesh.
|
// Initialize the ArrayMesh.
|
||||||
|
|||||||
@@ -22,10 +22,10 @@
|
|||||||
@export var strength = 4.0
|
@export var strength = 4.0
|
||||||
|
|
||||||
func _instantiate():
|
func _instantiate():
|
||||||
var effect = CustomAudioEffectInstance.new()
|
var effect = CustomAudioEffectInstance.new()
|
||||||
effect.base = self
|
effect.base = self
|
||||||
|
|
||||||
return effect
|
return effect
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
[b]Note:[/b] It is recommended to keep a reference to the original [AudioEffect] in the new instance. Depending on the implementation this allows the effect instance to listen for changes at run-time and be modified accordingly.
|
[b]Note:[/b] It is recommended to keep a reference to the original [AudioEffect] in the new instance. Depending on the implementation this allows the effect instance to listen for changes at run-time and be modified accordingly.
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<description>
|
<description>
|
||||||
Dynamic range compressor reduces the level of the sound when the amplitude goes over a certain threshold in Decibels. One of the main uses of a compressor is to increase the dynamic range by clipping as little as possible (when sound goes over 0dB).
|
Dynamic range compressor reduces the level of the sound when the amplitude goes over a certain threshold in Decibels. One of the main uses of a compressor is to increase the dynamic range by clipping as little as possible (when sound goes over 0dB).
|
||||||
Compressor has many uses in the mix:
|
Compressor has many uses in the mix:
|
||||||
- In the Master bus to compress the whole output (although an [AudioEffectLimiter] is probably better).
|
- In the Master bus to compress the whole output (although an [AudioEffectHardLimiter] is probably better).
|
||||||
- In voice channels to ensure they sound as balanced as possible.
|
- In voice channels to ensure they sound as balanced as possible.
|
||||||
- Sidechained. This can reduce the sound level sidechained with another audio bus for threshold detection. This technique is common in video game mixing to the level of music and SFX while voices are being heard.
|
- Sidechained. This can reduce the sound level sidechained with another audio bus for threshold detection. This technique is common in video game mixing to the level of music and SFX while voices are being heard.
|
||||||
- Accentuates transients by using a wider attack, making effects sound more punchy.
|
- Accentuates transients by using a wider attack, making effects sound more punchy.
|
||||||
|
|||||||
@@ -14,17 +14,17 @@
|
|||||||
var phase = 0.0
|
var phase = 0.0
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
$AudioStreamPlayer.play()
|
$AudioStreamPlayer.play()
|
||||||
playback = $AudioStreamPlayer.get_stream_playback()
|
playback = $AudioStreamPlayer.get_stream_playback()
|
||||||
fill_buffer()
|
fill_buffer()
|
||||||
|
|
||||||
func fill_buffer():
|
func fill_buffer():
|
||||||
var increment = pulse_hz / sample_hz
|
var increment = pulse_hz / sample_hz
|
||||||
var frames_available = playback.get_frames_available()
|
var frames_available = playback.get_frames_available()
|
||||||
|
|
||||||
for i in range(frames_available):
|
for i in range(frames_available):
|
||||||
playback.push_frame(Vector2.ONE * sin(phase * TAU))
|
playback.push_frame(Vector2.ONE * sin(phase * TAU))
|
||||||
phase = fmod(phase + increment, 1.0)
|
phase = fmod(phase + increment, 1.0)
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
[Export] public AudioStreamPlayer Player { get; set; }
|
[Export] public AudioStreamPlayer Player { get; set; }
|
||||||
@@ -36,25 +36,25 @@
|
|||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
if (Player.Stream is AudioStreamGenerator generator) // Type as a generator to access MixRate.
|
if (Player.Stream is AudioStreamGenerator generator) // Type as a generator to access MixRate.
|
||||||
{
|
{
|
||||||
_sampleHz = generator.MixRate;
|
_sampleHz = generator.MixRate;
|
||||||
Player.Play();
|
Player.Play();
|
||||||
_playback = (AudioStreamGeneratorPlayback)Player.GetStreamPlayback();
|
_playback = (AudioStreamGeneratorPlayback)Player.GetStreamPlayback();
|
||||||
FillBuffer();
|
FillBuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FillBuffer()
|
public void FillBuffer()
|
||||||
{
|
{
|
||||||
float increment = _pulseHz / _sampleHz;
|
float increment = _pulseHz / _sampleHz;
|
||||||
int framesAvailable = _playback.GetFramesAvailable();
|
int framesAvailable = _playback.GetFramesAvailable();
|
||||||
|
|
||||||
for (int i = 0; i < framesAvailable; i++)
|
for (int i = 0; i < framesAvailable; i++)
|
||||||
{
|
{
|
||||||
_playback.PushFrame(Vector2.One * (float)Mathf.Sin(phase * Mathf.Tau));
|
_playback.PushFrame(Vector2.One * (float)Mathf.Sin(phase * Mathf.Tau));
|
||||||
phase = Mathf.PosMod(phase + increment, 1.0);
|
phase = Mathf.PosMod(phase + increment, 1.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
|
|||||||
@@ -32,15 +32,15 @@
|
|||||||
@onready var audio_player = $AudioStreamPlayer
|
@onready var audio_player = $AudioStreamPlayer
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
get_window().files_dropped.connect(_on_files_dropped)
|
get_window().files_dropped.connect(_on_files_dropped)
|
||||||
|
|
||||||
func _on_files_dropped(files):
|
func _on_files_dropped(files):
|
||||||
if files[0].get_extension() == "wav":
|
if files[0].get_extension() == "wav":
|
||||||
audio_player.stream = AudioStreamWAV.load_from_file(files[0], {
|
audio_player.stream = AudioStreamWAV.load_from_file(files[0], {
|
||||||
"force/max_rate": true,
|
"force/max_rate": true,
|
||||||
"force/max_rate_hz": 11025
|
"force/max_rate_hz": 11025
|
||||||
})
|
})
|
||||||
audio_player.play()
|
audio_player.play()
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@@ -155,9 +155,9 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
var my_basis = Basis(
|
var my_basis = Basis(
|
||||||
Vector3(2, 0, 0),
|
Vector3(2, 0, 0),
|
||||||
Vector3(0, 4, 0),
|
Vector3(0, 4, 0),
|
||||||
Vector3(0, 0, 8)
|
Vector3(0, 0, 8)
|
||||||
)
|
)
|
||||||
# Rotating the Basis in any way preserves its scale.
|
# Rotating the Basis in any way preserves its scale.
|
||||||
my_basis = my_basis.rotated(Vector3.UP, TAU / 2)
|
my_basis = my_basis.rotated(Vector3.UP, TAU / 2)
|
||||||
@@ -167,9 +167,9 @@
|
|||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
var myBasis = new Basis(
|
var myBasis = new Basis(
|
||||||
Vector3(2.0f, 0.0f, 0.0f),
|
Vector3(2.0f, 0.0f, 0.0f),
|
||||||
Vector3(0.0f, 4.0f, 0.0f),
|
Vector3(0.0f, 4.0f, 0.0f),
|
||||||
Vector3(0.0f, 0.0f, 8.0f)
|
Vector3(0.0f, 0.0f, 8.0f)
|
||||||
);
|
);
|
||||||
// Rotating the Basis in any way preserves its scale.
|
// Rotating the Basis in any way preserves its scale.
|
||||||
myBasis = myBasis.Rotated(Vector3.Up, Mathf.Tau / 2.0f);
|
myBasis = myBasis.Rotated(Vector3.Up, Mathf.Tau / 2.0f);
|
||||||
@@ -227,18 +227,17 @@
|
|||||||
[gdscript]
|
[gdscript]
|
||||||
# Rotate this Node3D every frame.
|
# Rotate this Node3D every frame.
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
basis = basis.rotated(Vector3.UP, TAU * delta)
|
basis = basis.rotated(Vector3.UP, TAU * delta)
|
||||||
basis = basis.rotated(Vector3.RIGHT, TAU * delta)
|
basis = basis.rotated(Vector3.RIGHT, TAU * delta)
|
||||||
|
basis = basis.orthonormalized()
|
||||||
basis = basis.orthonormalized()
|
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
// Rotate this Node3D every frame.
|
// Rotate this Node3D every frame.
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
Basis = Basis.Rotated(Vector3.Up, Mathf.Tau * (float)delta)
|
Basis = Basis.Rotated(Vector3.Up, Mathf.Tau * (float)delta)
|
||||||
.Rotated(Vector3.Right, Mathf.Tau * (float)delta)
|
.Rotated(Vector3.Right, Mathf.Tau * (float)delta)
|
||||||
.Orthonormalized();
|
.Orthonormalized();
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -280,9 +279,9 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
var my_basis = Basis(
|
var my_basis = Basis(
|
||||||
Vector3(1, 1, 1),
|
Vector3(1, 1, 1),
|
||||||
Vector3(2, 2, 2),
|
Vector3(2, 2, 2),
|
||||||
Vector3(3, 3, 3)
|
Vector3(3, 3, 3)
|
||||||
)
|
)
|
||||||
my_basis = my_basis.scaled(Vector3(0, 2, -2))
|
my_basis = my_basis.scaled(Vector3(0, 2, -2))
|
||||||
|
|
||||||
@@ -292,9 +291,9 @@
|
|||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
var myBasis = new Basis(
|
var myBasis = new Basis(
|
||||||
new Vector3(1.0f, 1.0f, 1.0f),
|
new Vector3(1.0f, 1.0f, 1.0f),
|
||||||
new Vector3(2.0f, 2.0f, 2.0f),
|
new Vector3(2.0f, 2.0f, 2.0f),
|
||||||
new Vector3(3.0f, 3.0f, 3.0f)
|
new Vector3(3.0f, 3.0f, 3.0f)
|
||||||
);
|
);
|
||||||
myBasis = myBasis.Scaled(new Vector3(0.0f, 2.0f, -2.0f));
|
myBasis = myBasis.Scaled(new Vector3(0.0f, 2.0f, -2.0f));
|
||||||
|
|
||||||
@@ -305,6 +304,40 @@
|
|||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="scaled_local" qualifiers="const">
|
||||||
|
<return type="Basis" />
|
||||||
|
<param index="0" name="scale" type="Vector3" />
|
||||||
|
<description>
|
||||||
|
Returns this basis with each axis scaled by the corresponding component in the given [param scale].
|
||||||
|
The basis matrix's columns are multiplied by [param scale]'s components. This operation is a local scale (relative to self).
|
||||||
|
[codeblocks]
|
||||||
|
[gdscript]
|
||||||
|
var my_basis = Basis(
|
||||||
|
Vector3(1, 1, 1),
|
||||||
|
Vector3(2, 2, 2),
|
||||||
|
Vector3(3, 3, 3)
|
||||||
|
)
|
||||||
|
my_basis = my_basis.scaled_local(Vector3(0, 2, -2))
|
||||||
|
|
||||||
|
print(my_basis.x) # Prints (0.0, 0.0, 0.0)
|
||||||
|
print(my_basis.y) # Prints (4.0, 4.0, 4.0)
|
||||||
|
print(my_basis.z) # Prints (-6.0, -6.0, -6.0)
|
||||||
|
[/gdscript]
|
||||||
|
[csharp]
|
||||||
|
var myBasis = new Basis(
|
||||||
|
new Vector3(1.0f, 1.0f, 1.0f),
|
||||||
|
new Vector3(2.0f, 2.0f, 2.0f),
|
||||||
|
new Vector3(3.0f, 3.0f, 3.0f)
|
||||||
|
);
|
||||||
|
myBasis = myBasis.ScaledLocal(new Vector3(0.0f, 2.0f, -2.0f));
|
||||||
|
|
||||||
|
GD.Print(myBasis.X); // Prints (0, 0, 0)
|
||||||
|
GD.Print(myBasis.Y); // Prints (4, 4, 4)
|
||||||
|
GD.Print(myBasis.Z); // Prints (-6, -6, -6)
|
||||||
|
[/csharp]
|
||||||
|
[/codeblocks]
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="slerp" qualifiers="const" keywords="interpolate">
|
<method name="slerp" qualifiers="const" keywords="interpolate">
|
||||||
<return type="Basis" />
|
<return type="Basis" />
|
||||||
<param index="0" name="to" type="Basis" />
|
<param index="0" name="to" type="Basis" />
|
||||||
@@ -317,10 +350,10 @@
|
|||||||
var target_basis = Basis.IDENTITY.rotated(Vector3.UP, TAU / 2)
|
var target_basis = Basis.IDENTITY.rotated(Vector3.UP, TAU / 2)
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
create_tween().tween_method(interpolate, 0.0, 1.0, 5.0).set_trans(Tween.TRANS_EXPO)
|
create_tween().tween_method(interpolate, 0.0, 1.0, 5.0).set_trans(Tween.TRANS_EXPO)
|
||||||
|
|
||||||
func interpolate(weight):
|
func interpolate(weight):
|
||||||
basis = start_basis.slerp(target_basis, weight)
|
basis = start_basis.slerp(target_basis, weight)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -355,9 +388,9 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
var my_basis = Basis(
|
var my_basis = Basis(
|
||||||
Vector3(1, 2, 3),
|
Vector3(1, 2, 3),
|
||||||
Vector3(4, 5, 6),
|
Vector3(4, 5, 6),
|
||||||
Vector3(7, 8, 9)
|
Vector3(7, 8, 9)
|
||||||
)
|
)
|
||||||
my_basis = my_basis.transposed()
|
my_basis = my_basis.transposed()
|
||||||
|
|
||||||
@@ -367,9 +400,9 @@
|
|||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
var myBasis = new Basis(
|
var myBasis = new Basis(
|
||||||
new Vector3(1.0f, 2.0f, 3.0f),
|
new Vector3(1.0f, 2.0f, 3.0f),
|
||||||
new Vector3(4.0f, 5.0f, 6.0f),
|
new Vector3(4.0f, 5.0f, 6.0f),
|
||||||
new Vector3(7.0f, 8.0f, 9.0f)
|
new Vector3(7.0f, 8.0f, 9.0f)
|
||||||
);
|
);
|
||||||
myBasis = myBasis.Transposed();
|
myBasis = myBasis.Transposed();
|
||||||
|
|
||||||
|
|||||||
@@ -9,26 +9,26 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _ready():
|
func _ready():
|
||||||
var button = Button.new()
|
var button = Button.new()
|
||||||
button.text = "Click me"
|
button.text = "Click me"
|
||||||
button.pressed.connect(_button_pressed)
|
button.pressed.connect(_button_pressed)
|
||||||
add_child(button)
|
add_child(button)
|
||||||
|
|
||||||
func _button_pressed():
|
func _button_pressed():
|
||||||
print("Hello world!")
|
print("Hello world!")
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
var button = new Button();
|
var button = new Button();
|
||||||
button.Text = "Click me";
|
button.Text = "Click me";
|
||||||
button.Pressed += ButtonPressed;
|
button.Pressed += ButtonPressed;
|
||||||
AddChild(button);
|
AddChild(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ButtonPressed()
|
private void ButtonPressed()
|
||||||
{
|
{
|
||||||
GD.Print("Hello world!");
|
GD.Print("Hello world!");
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
|
|||||||
@@ -8,42 +8,42 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func print_args(arg1, arg2, arg3 = ""):
|
func print_args(arg1, arg2, arg3 = ""):
|
||||||
prints(arg1, arg2, arg3)
|
prints(arg1, arg2, arg3)
|
||||||
|
|
||||||
func test():
|
func test():
|
||||||
var callable = Callable(self, "print_args")
|
var callable = Callable(self, "print_args")
|
||||||
callable.call("hello", "world") # Prints "hello world ".
|
callable.call("hello", "world") # Prints "hello world ".
|
||||||
callable.call(Vector2.UP, 42, callable) # Prints "(0.0, -1.0) 42 Node(node.gd)::print_args"
|
callable.call(Vector2.UP, 42, callable) # Prints "(0.0, -1.0) 42 Node(node.gd)::print_args"
|
||||||
callable.call("invalid") # Invalid call, should have at least 2 arguments.
|
callable.call("invalid") # Invalid call, should have at least 2 arguments.
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
// Default parameter values are not supported.
|
// Default parameter values are not supported.
|
||||||
public void PrintArgs(Variant arg1, Variant arg2, Variant arg3 = default)
|
public void PrintArgs(Variant arg1, Variant arg2, Variant arg3 = default)
|
||||||
{
|
{
|
||||||
GD.PrintS(arg1, arg2, arg3);
|
GD.PrintS(arg1, arg2, arg3);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Test()
|
public void Test()
|
||||||
{
|
{
|
||||||
// Invalid calls fail silently.
|
// Invalid calls fail silently.
|
||||||
Callable callable = new Callable(this, MethodName.PrintArgs);
|
Callable callable = new Callable(this, MethodName.PrintArgs);
|
||||||
callable.Call("hello", "world"); // Default parameter values are not supported, should have 3 arguments.
|
callable.Call("hello", "world"); // Default parameter values are not supported, should have 3 arguments.
|
||||||
callable.Call(Vector2.Up, 42, callable); // Prints "(0, -1) 42 Node(Node.cs)::PrintArgs"
|
callable.Call(Vector2.Up, 42, callable); // Prints "(0, -1) 42 Node(Node.cs)::PrintArgs"
|
||||||
callable.Call("invalid"); // Invalid call, should have 3 arguments.
|
callable.Call("invalid"); // Invalid call, should have 3 arguments.
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
In GDScript, it's possible to create lambda functions within a method. Lambda functions are custom callables that are not associated with an [Object] instance. Optionally, lambda functions can also be named. The name will be displayed in the debugger, or when calling [method get_method].
|
In GDScript, it's possible to create lambda functions within a method. Lambda functions are custom callables that are not associated with an [Object] instance. Optionally, lambda functions can also be named. The name will be displayed in the debugger, or when calling [method get_method].
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _init():
|
func _init():
|
||||||
var my_lambda = func (message):
|
var my_lambda = func (message):
|
||||||
print(message)
|
print(message)
|
||||||
|
|
||||||
# Prints "Hello everyone!"
|
# Prints "Hello everyone!"
|
||||||
my_lambda.call("Hello everyone!")
|
my_lambda.call("Hello everyone!")
|
||||||
|
|
||||||
# Prints "Attack!", when the button_pressed signal is emitted.
|
# Prints "Attack!", when the button_pressed signal is emitted.
|
||||||
button_pressed.connect(func(): print("Attack!"))
|
button_pressed.connect(func(): print("Attack!"))
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
In GDScript, you can access methods and global functions as [Callable]s:
|
In GDScript, you can access methods and global functions as [Callable]s:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
[/codeblock]
|
[/codeblock]
|
||||||
[b]Note:[/b] [Dictionary] does not support the above due to ambiguity with keys.
|
[b]Note:[/b] [Dictionary] does not support the above due to ambiguity with keys.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
var dictionary = {"hello": "world"}
|
var dictionary = { "hello": "world" }
|
||||||
|
|
||||||
# This will not work, `clear` is treated as a key.
|
# This will not work, `clear` is treated as a key.
|
||||||
tween.tween_callback(dictionary.clear)
|
tween.tween_callback(dictionary.clear)
|
||||||
@@ -117,12 +117,12 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _ready():
|
func _ready():
|
||||||
grab_focus.call_deferred()
|
grab_focus.call_deferred()
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
Callable.From(GrabFocus).CallDeferred();
|
Callable.From(GrabFocus).CallDeferred();
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -158,10 +158,10 @@
|
|||||||
Returns the array of arguments bound via successive [method bind] or [method unbind] calls. These arguments will be added [i]after[/i] the arguments passed to the call, from which [method get_unbound_arguments_count] arguments on the right have been previously excluded.
|
Returns the array of arguments bound via successive [method bind] or [method unbind] calls. These arguments will be added [i]after[/i] the arguments passed to the call, from which [method get_unbound_arguments_count] arguments on the right have been previously excluded.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func get_effective_arguments(callable, call_args):
|
func get_effective_arguments(callable, call_args):
|
||||||
assert(call_args.size() - callable.get_unbound_arguments_count() >= 0)
|
assert(call_args.size() - callable.get_unbound_arguments_count() >= 0)
|
||||||
var result = call_args.slice(0, call_args.size() - callable.get_unbound_arguments_count())
|
var result = call_args.slice(0, call_args.size() - callable.get_unbound_arguments_count())
|
||||||
result.append_array(callable.get_bound_arguments())
|
result.append_array(callable.get_bound_arguments())
|
||||||
return result
|
return result
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -254,8 +254,8 @@
|
|||||||
[b]Note:[/b] When this method is chained with other similar methods, the order in which the argument list is modified is read from right to left.
|
[b]Note:[/b] When this method is chained with other similar methods, the order in which the argument list is modified is read from right to left.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _ready():
|
func _ready():
|
||||||
foo.unbind(1).call(1, 2) # Calls foo(1).
|
foo.unbind(1).call(1, 2) # Calls foo(1).
|
||||||
foo.bind(3, 4).unbind(1).call(1, 2) # Calls foo(1, 3, 4), note that it does not change the arguments from bind.
|
foo.bind(3, 4).unbind(1).call(1, 2) # Calls foo(1, 3, 4), note that it does not change the arguments from bind.
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@@ -186,7 +186,7 @@
|
|||||||
The angular, asymptotic speed of the camera's rotation smoothing effect when [member rotation_smoothing_enabled] is [code]true[/code].
|
The angular, asymptotic speed of the camera's rotation smoothing effect when [member rotation_smoothing_enabled] is [code]true[/code].
|
||||||
</member>
|
</member>
|
||||||
<member name="zoom" type="Vector2" setter="set_zoom" getter="get_zoom" default="Vector2(1, 1)">
|
<member name="zoom" type="Vector2" setter="set_zoom" getter="get_zoom" default="Vector2(1, 1)">
|
||||||
The camera's zoom. A zoom of [code]Vector(2, 2)[/code] doubles the size seen in the viewport. A zoom of [code]Vector(0.5, 0.5)[/code] halves the size seen in the viewport.
|
The camera's zoom. Higher values are more zoomed in. For example, a zoom of [code]Vector2(2.0, 2.0)[/code] will be twice as zoomed in on each axis (the view covers an area four times smaller). In contrast, a zoom of [code]Vector2(0.5, 0.5)[/code] will be twice as zoomed out on each axis (the view covers an area four times larger). The X and Y components should generally always be set to the same value, unless you wish to stretch the camera view.
|
||||||
[b]Note:[/b] [member FontFile.oversampling] does [i]not[/i] take [Camera2D] zoom into account. This means that zooming in/out will cause bitmap fonts and rasterized (non-MSDF) dynamic fonts to appear blurry or pixelated unless the font is part of a [CanvasLayer] that makes it ignore camera zoom. To ensure text remains crisp regardless of zoom, you can enable MSDF font rendering by enabling [member ProjectSettings.gui/theme/default_font_multichannel_signed_distance_field] (applies to the default project font only), or enabling [b]Multichannel Signed Distance Field[/b] in the import options of a DynamicFont for custom fonts. On system fonts, [member SystemFont.multichannel_signed_distance_field] can be enabled in the inspector.
|
[b]Note:[/b] [member FontFile.oversampling] does [i]not[/i] take [Camera2D] zoom into account. This means that zooming in/out will cause bitmap fonts and rasterized (non-MSDF) dynamic fonts to appear blurry or pixelated unless the font is part of a [CanvasLayer] that makes it ignore camera zoom. To ensure text remains crisp regardless of zoom, you can enable MSDF font rendering by enabling [member ProjectSettings.gui/theme/default_font_multichannel_signed_distance_field] (applies to the default project font only), or enabling [b]Multichannel Signed Distance Field[/b] in the import options of a DynamicFont for custom fonts. On system fonts, [member SystemFont.multichannel_signed_distance_field] can be enabled in the inspector.
|
||||||
</member>
|
</member>
|
||||||
</members>
|
</members>
|
||||||
|
|||||||
@@ -13,13 +13,13 @@
|
|||||||
uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
|
uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
|
||||||
|
|
||||||
void fragment() {
|
void fragment() {
|
||||||
vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
|
vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
|
||||||
|
|
||||||
if (c.a > 0.0001) {
|
if (c.a > 0.0001) {
|
||||||
c.rgb /= c.a;
|
c.rgb /= c.a;
|
||||||
}
|
}
|
||||||
|
|
||||||
COLOR *= c;
|
COLOR *= c;
|
||||||
}
|
}
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
[b]Note:[/b] Since [CanvasGroup] and [member CanvasItem.clip_children] both utilize the backbuffer, children of a [CanvasGroup] who have their [member CanvasItem.clip_children] set to anything other than [constant CanvasItem.CLIP_CHILDREN_DISABLED] will not function correctly.
|
[b]Note:[/b] Since [CanvasGroup] and [member CanvasItem.clip_children] both utilize the backbuffer, children of a [CanvasGroup] who have their [member CanvasItem.clip_children] set to anything other than [constant CanvasItem.CLIP_CHILDREN_DISABLED] will not function correctly.
|
||||||
|
|||||||
@@ -73,14 +73,14 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
for i in get_slide_collision_count():
|
for i in get_slide_collision_count():
|
||||||
var collision = get_slide_collision(i)
|
var collision = get_slide_collision(i)
|
||||||
print("Collided with: ", collision.get_collider().name)
|
print("Collided with: ", collision.get_collider().name)
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
for (int i = 0; i < GetSlideCollisionCount(); i++)
|
for (int i = 0; i < GetSlideCollisionCount(); i++)
|
||||||
{
|
{
|
||||||
KinematicCollision2D collision = GetSlideCollision(i);
|
KinematicCollision2D collision = GetSlideCollision(i);
|
||||||
GD.Print("Collided with: ", (collision.GetCollider() as Node).Name);
|
GD.Print("Collided with: ", (collision.GetCollider() as Node).Name);
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
Collision build mode.
|
Collision build mode.
|
||||||
</member>
|
</member>
|
||||||
<member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false" keywords="enabled">
|
<member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false" keywords="enabled">
|
||||||
If [code]true[/code], no collisions will be detected.
|
If [code]true[/code], no collisions will be detected. This property should be changed with [method Object.set_deferred].
|
||||||
</member>
|
</member>
|
||||||
<member name="one_way_collision" type="bool" setter="set_one_way_collision" getter="is_one_way_collision_enabled" default="false">
|
<member name="one_way_collision" type="bool" setter="set_one_way_collision" getter="is_one_way_collision_enabled" default="false">
|
||||||
If [code]true[/code], only edges that face up, relative to [CollisionPolygon2D]'s rotation, will collide with other objects.
|
If [code]true[/code], only edges that face up, relative to [CollisionPolygon2D]'s rotation, will collide with other objects.
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
Length that the resulting collision extends in either direction perpendicular to its 2D polygon.
|
Length that the resulting collision extends in either direction perpendicular to its 2D polygon.
|
||||||
</member>
|
</member>
|
||||||
<member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false" keywords="enabled">
|
<member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false" keywords="enabled">
|
||||||
If [code]true[/code], no collision will be produced.
|
If [code]true[/code], no collision will be produced. This property should be changed with [method Object.set_deferred].
|
||||||
</member>
|
</member>
|
||||||
<member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.04">
|
<member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.04">
|
||||||
The collision margin for the generated [Shape3D]. See [member Shape3D.margin] for more details.
|
The collision margin for the generated [Shape3D]. See [member Shape3D.margin] for more details.
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
If [code]true[/code], when the shape is displayed, it will show a solid fill color in addition to its wireframe.
|
If [code]true[/code], when the shape is displayed, it will show a solid fill color in addition to its wireframe.
|
||||||
</member>
|
</member>
|
||||||
<member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false" keywords="enabled">
|
<member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false" keywords="enabled">
|
||||||
A disabled collision shape has no effect in the world.
|
A disabled collision shape has no effect in the world. This property should be changed with [method Object.set_deferred].
|
||||||
</member>
|
</member>
|
||||||
<member name="shape" type="Shape3D" setter="set_shape" getter="get_shape">
|
<member name="shape" type="Shape3D" setter="set_shape" getter="get_shape">
|
||||||
The actual shape owned by this collision shape.
|
The actual shape owned by this collision shape.
|
||||||
|
|||||||
@@ -150,6 +150,12 @@
|
|||||||
<constant name="SHAPE_NONE" value="4" enum="PickerShapeType">
|
<constant name="SHAPE_NONE" value="4" enum="PickerShapeType">
|
||||||
The color space shape and the shape select button are hidden. Can't be selected from the shapes popup.
|
The color space shape and the shape select button are hidden. Can't be selected from the shapes popup.
|
||||||
</constant>
|
</constant>
|
||||||
|
<constant name="SHAPE_OK_HS_RECTANGLE" value="5" enum="PickerShapeType">
|
||||||
|
OKHSL Color Model rectangle with constant lightness.
|
||||||
|
</constant>
|
||||||
|
<constant name="SHAPE_OK_HL_RECTANGLE" value="6" enum="PickerShapeType">
|
||||||
|
OKHSL Color Model rectangle with constant saturation.
|
||||||
|
</constant>
|
||||||
</constants>
|
</constants>
|
||||||
<theme_items>
|
<theme_items>
|
||||||
<theme_item name="focused_not_editing_cursor_color" data_type="color" type="Color" default="Color(1, 1, 1, 0.275)">
|
<theme_item name="focused_not_editing_cursor_color" data_type="color" type="Color" default="Color(1, 1, 1, 0.275)">
|
||||||
|
|||||||
@@ -60,12 +60,12 @@
|
|||||||
The raw normal and roughness buffer is stored in an optimized format, different than the one available in Spatial shaders. When sampling the buffer, a conversion function must be applied. Use this function, copied from [url=https://github.com/Redot-Engine/redot-engine/blob/da5f39889f155658cef7f7ec3cc1abb94e17d815/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl#L334-L341]here[/url]:
|
The raw normal and roughness buffer is stored in an optimized format, different than the one available in Spatial shaders. When sampling the buffer, a conversion function must be applied. Use this function, copied from [url=https://github.com/Redot-Engine/redot-engine/blob/da5f39889f155658cef7f7ec3cc1abb94e17d815/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl#L334-L341]here[/url]:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
vec4 normal_roughness_compatibility(vec4 p_normal_roughness) {
|
vec4 normal_roughness_compatibility(vec4 p_normal_roughness) {
|
||||||
float roughness = p_normal_roughness.w;
|
float roughness = p_normal_roughness.w;
|
||||||
if (roughness > 0.5) {
|
if (roughness > 0.5) {
|
||||||
roughness = 1.0 - roughness;
|
roughness = 1.0 - roughness;
|
||||||
}
|
}
|
||||||
roughness /= (127.0 / 255.0);
|
roughness /= (127.0 / 255.0);
|
||||||
return vec4(normalize(p_normal_roughness.xyz * 2.0 - 1.0) * 0.5 + 0.5, roughness);
|
return vec4(normalize(p_normal_roughness.xyz * 2.0 - 1.0) * 0.5 + 0.5, roughness);
|
||||||
}
|
}
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</member>
|
</member>
|
||||||
|
|||||||
@@ -52,14 +52,14 @@
|
|||||||
|
|
||||||
# If the file didn't load, ignore it.
|
# If the file didn't load, ignore it.
|
||||||
if err != OK:
|
if err != OK:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Iterate over all sections.
|
# Iterate over all sections.
|
||||||
for player in config.get_sections():
|
for player in config.get_sections():
|
||||||
# Fetch the data for each section.
|
# Fetch the data for each section.
|
||||||
var player_name = config.get_value(player, "player_name")
|
var player_name = config.get_value(player, "player_name")
|
||||||
var player_score = config.get_value(player, "best_score")
|
var player_score = config.get_value(player, "best_score")
|
||||||
score_data[player_name] = player_score
|
score_data[player_name] = player_score
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
var score_data = new Godot.Collections.Dictionary();
|
var score_data = new Godot.Collections.Dictionary();
|
||||||
@@ -71,16 +71,16 @@
|
|||||||
// If the file didn't load, ignore it.
|
// If the file didn't load, ignore it.
|
||||||
if (err != Error.Ok)
|
if (err != Error.Ok)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over all sections.
|
// Iterate over all sections.
|
||||||
foreach (String player in config.GetSections())
|
foreach (String player in config.GetSections())
|
||||||
{
|
{
|
||||||
// Fetch the data for each section.
|
// Fetch the data for each section.
|
||||||
var player_name = (String)config.GetValue(player, "player_name");
|
var player_name = (String)config.GetValue(player, "player_name");
|
||||||
var player_score = (int)config.GetValue(player, "best_score");
|
var player_score = (int)config.GetValue(player, "best_score");
|
||||||
score_data[player_name] = player_score;
|
score_data[player_name] = player_score;
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
|
|||||||
@@ -41,16 +41,16 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _can_drop_data(position, data):
|
func _can_drop_data(position, data):
|
||||||
# Check position if it is relevant to you
|
# Check position if it is relevant to you
|
||||||
# Otherwise, just check data
|
# Otherwise, just check data
|
||||||
return typeof(data) == TYPE_DICTIONARY and data.has("expected")
|
return typeof(data) == TYPE_DICTIONARY and data.has("expected")
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override bool _CanDropData(Vector2 atPosition, Variant data)
|
public override bool _CanDropData(Vector2 atPosition, Variant data)
|
||||||
{
|
{
|
||||||
// Check position if it is relevant to you
|
// Check position if it is relevant to you
|
||||||
// Otherwise, just check data
|
// Otherwise, just check data
|
||||||
return data.VariantType == Variant.Type.Dictionary && data.AsGodotDictionary().ContainsKey("expected");
|
return data.VariantType == Variant.Type.Dictionary && data.AsGodotDictionary().ContainsKey("expected");
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -66,25 +66,32 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _can_drop_data(position, data):
|
func _can_drop_data(position, data):
|
||||||
return typeof(data) == TYPE_DICTIONARY and data.has("color")
|
return typeof(data) == TYPE_DICTIONARY and data.has("color")
|
||||||
|
|
||||||
func _drop_data(position, data):
|
func _drop_data(position, data):
|
||||||
var color = data["color"]
|
var color = data["color"]
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override bool _CanDropData(Vector2 atPosition, Variant data)
|
public override bool _CanDropData(Vector2 atPosition, Variant data)
|
||||||
{
|
{
|
||||||
return data.VariantType == Variant.Type.Dictionary && data.AsGodotDictionary().ContainsKey("color");
|
return data.VariantType == Variant.Type.Dictionary && data.AsGodotDictionary().ContainsKey("color");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _DropData(Vector2 atPosition, Variant data)
|
public override void _DropData(Vector2 atPosition, Variant data)
|
||||||
{
|
{
|
||||||
Color color = data.AsGodotDictionary()["color"].AsColor();
|
Color color = data.AsGodotDictionary()["color"].AsColor();
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="_get_accessibility_container_name" qualifiers="virtual const">
|
||||||
|
<return type="String" />
|
||||||
|
<param index="0" name="node" type="Node" />
|
||||||
|
<description>
|
||||||
|
Override this method to return a human-readable description of the position of the child [param node] in the custom container, added to the [member accessibility_name].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="_get_drag_data" qualifiers="virtual">
|
<method name="_get_drag_data" qualifiers="virtual">
|
||||||
<return type="Variant" />
|
<return type="Variant" />
|
||||||
<param index="0" name="at_position" type="Vector2" />
|
<param index="0" name="at_position" type="Vector2" />
|
||||||
@@ -95,16 +102,16 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _get_drag_data(position):
|
func _get_drag_data(position):
|
||||||
var mydata = make_data() # This is your custom method generating the drag data.
|
var mydata = make_data() # This is your custom method generating the drag data.
|
||||||
set_drag_preview(make_preview(mydata)) # This is your custom method generating the preview of the drag data.
|
set_drag_preview(make_preview(mydata)) # This is your custom method generating the preview of the drag data.
|
||||||
return mydata
|
return mydata
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override Variant _GetDragData(Vector2 atPosition)
|
public override Variant _GetDragData(Vector2 atPosition)
|
||||||
{
|
{
|
||||||
var myData = MakeData(); // This is your custom method generating the drag data.
|
var myData = MakeData(); // This is your custom method generating the drag data.
|
||||||
SetDragPreview(MakePreview(myData)); // This is your custom method generating the preview of the drag data.
|
SetDragPreview(MakePreview(myData)); // This is your custom method generating the preview of the drag data.
|
||||||
return myData;
|
return myData;
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -135,20 +142,20 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _gui_input(event):
|
func _gui_input(event):
|
||||||
if event is InputEventMouseButton:
|
if event is InputEventMouseButton:
|
||||||
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
|
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
|
||||||
print("I've been clicked D:")
|
print("I've been clicked D:")
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override void _GuiInput(InputEvent @event)
|
public override void _GuiInput(InputEvent @event)
|
||||||
{
|
{
|
||||||
if (@event is InputEventMouseButton mb)
|
if (@event is InputEventMouseButton mb)
|
||||||
{
|
{
|
||||||
if (mb.ButtonIndex == MouseButton.Left && mb.Pressed)
|
if (mb.ButtonIndex == MouseButton.Left && mb.Pressed)
|
||||||
{
|
{
|
||||||
GD.Print("I've been clicked D:");
|
GD.Print("I've been clicked D:");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -184,16 +191,16 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _make_custom_tooltip(for_text):
|
func _make_custom_tooltip(for_text):
|
||||||
var label = Label.new()
|
var label = Label.new()
|
||||||
label.text = for_text
|
label.text = for_text
|
||||||
return label
|
return label
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override Control _MakeCustomTooltip(string forText)
|
public override Control _MakeCustomTooltip(string forText)
|
||||||
{
|
{
|
||||||
var label = new Label();
|
var label = new Label();
|
||||||
label.Text = forText;
|
label.Text = forText;
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -201,16 +208,16 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _make_custom_tooltip(for_text):
|
func _make_custom_tooltip(for_text):
|
||||||
var tooltip = preload("res://some_tooltip_scene.tscn").instantiate()
|
var tooltip = preload("res://some_tooltip_scene.tscn").instantiate()
|
||||||
tooltip.get_node("Label").text = for_text
|
tooltip.get_node("Label").text = for_text
|
||||||
return tooltip
|
return tooltip
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override Control _MakeCustomTooltip(string forText)
|
public override Control _MakeCustomTooltip(string forText)
|
||||||
{
|
{
|
||||||
Node tooltip = ResourceLoader.Load<PackedScene>("res://some_tooltip_scene.tscn").Instantiate();
|
Node tooltip = ResourceLoader.Load<PackedScene>("res://some_tooltip_scene.tscn").Instantiate();
|
||||||
tooltip.GetNode<Label>("Label").Text = forText;
|
tooltip.GetNode<Label>("Label").Text = forText;
|
||||||
return tooltip;
|
return tooltip;
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -499,18 +506,18 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _ready():
|
func _ready():
|
||||||
# Get the font color defined for the current Control's class, if it exists.
|
# Get the font color defined for the current Control's class, if it exists.
|
||||||
modulate = get_theme_color("font_color")
|
modulate = get_theme_color("font_color")
|
||||||
# Get the font color defined for the Button class.
|
# Get the font color defined for the Button class.
|
||||||
modulate = get_theme_color("font_color", "Button")
|
modulate = get_theme_color("font_color", "Button")
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
// Get the font color defined for the current Control's class, if it exists.
|
// Get the font color defined for the current Control's class, if it exists.
|
||||||
Modulate = GetThemeColor("font_color");
|
Modulate = GetThemeColor("font_color");
|
||||||
// Get the font color defined for the Button class.
|
// Get the font color defined for the Button class.
|
||||||
Modulate = GetThemeColor("font_color", "Button");
|
Modulate = GetThemeColor("font_color", "Button");
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -598,12 +605,12 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
grab_click_focus() # When clicking another Control node, this node will be clicked instead.
|
grab_click_focus() # When clicking another Control node, this node will be clicked instead.
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
GrabClickFocus(); // When clicking another Control node, this node will be clicked instead.
|
GrabClickFocus(); // When clicking another Control node, this node will be clicked instead.
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -861,12 +868,12 @@
|
|||||||
@export var color = Color(1, 0, 0, 1)
|
@export var color = Color(1, 0, 0, 1)
|
||||||
|
|
||||||
func _get_drag_data(position):
|
func _get_drag_data(position):
|
||||||
# Use a control that is not in the tree
|
# Use a control that is not in the tree
|
||||||
var cpb = ColorPickerButton.new()
|
var cpb = ColorPickerButton.new()
|
||||||
cpb.color = color
|
cpb.color = color
|
||||||
cpb.size = Vector2(50, 50)
|
cpb.size = Vector2(50, 50)
|
||||||
set_drag_preview(cpb)
|
set_drag_preview(cpb)
|
||||||
return color
|
return color
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
[Export]
|
[Export]
|
||||||
@@ -874,12 +881,12 @@
|
|||||||
|
|
||||||
public override Variant _GetDragData(Vector2 atPosition)
|
public override Variant _GetDragData(Vector2 atPosition)
|
||||||
{
|
{
|
||||||
// Use a control that is not in the tree
|
// Use a control that is not in the tree
|
||||||
var cpb = new ColorPickerButton();
|
var cpb = new ColorPickerButton();
|
||||||
cpb.Color = _color;
|
cpb.Color = _color;
|
||||||
cpb.Size = new Vector2(50, 50);
|
cpb.Size = new Vector2(50, 50);
|
||||||
SetDragPreview(cpb);
|
SetDragPreview(cpb);
|
||||||
return _color;
|
return _color;
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -962,6 +969,27 @@
|
|||||||
</method>
|
</method>
|
||||||
</methods>
|
</methods>
|
||||||
<members>
|
<members>
|
||||||
|
<member name="accessibility_controls_nodes" type="NodePath[]" setter="set_accessibility_controls_nodes" getter="get_accessibility_controls_nodes" default="[]">
|
||||||
|
The paths to the nodes which are controlled by this node.
|
||||||
|
</member>
|
||||||
|
<member name="accessibility_described_by_nodes" type="NodePath[]" setter="set_accessibility_described_by_nodes" getter="get_accessibility_described_by_nodes" default="[]">
|
||||||
|
The paths to the nodes which are describing this node.
|
||||||
|
</member>
|
||||||
|
<member name="accessibility_description" type="String" setter="set_accessibility_description" getter="get_accessibility_description" default="""">
|
||||||
|
The human-readable node description that is reported to assistive apps.
|
||||||
|
</member>
|
||||||
|
<member name="accessibility_flow_to_nodes" type="NodePath[]" setter="set_accessibility_flow_to_nodes" getter="get_accessibility_flow_to_nodes" default="[]">
|
||||||
|
The paths to the nodes which this node flows into.
|
||||||
|
</member>
|
||||||
|
<member name="accessibility_labeled_by_nodes" type="NodePath[]" setter="set_accessibility_labeled_by_nodes" getter="get_accessibility_labeled_by_nodes" default="[]">
|
||||||
|
The paths to the nodes which label this node.
|
||||||
|
</member>
|
||||||
|
<member name="accessibility_live" type="int" setter="set_accessibility_live" getter="get_accessibility_live" enum="DisplayServer.AccessibilityLiveMode" default="0">
|
||||||
|
The mode with which a live region updates. A live region is a [Node] that is updated as a result of an external event when the user's focus may be elsewhere.
|
||||||
|
</member>
|
||||||
|
<member name="accessibility_name" type="String" setter="set_accessibility_name" getter="get_accessibility_name" default="""">
|
||||||
|
The human-readable node name that is reported to assistive apps.
|
||||||
|
</member>
|
||||||
<member name="anchor_bottom" type="float" setter="_set_anchor" getter="get_anchor" default="0.0">
|
<member name="anchor_bottom" type="float" setter="_set_anchor" getter="get_anchor" default="0.0">
|
||||||
Anchors the bottom edge of the node to the origin, the center, or the end of its parent control. It changes how the bottom offset updates when the node moves or changes size. You can use one of the [enum Anchor] constants for convenience.
|
Anchors the bottom edge of the node to the origin, the center, or the end of its parent control. It changes how the bottom offset updates when the node moves or changes size. You can use one of the [enum Anchor] constants for convenience.
|
||||||
</member>
|
</member>
|
||||||
@@ -1164,8 +1192,8 @@
|
|||||||
[b]Note:[/b] If you want to check whether the mouse truly left the area, ignoring any top nodes, you can use code like this:
|
[b]Note:[/b] If you want to check whether the mouse truly left the area, ignoring any top nodes, you can use code like this:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _on_mouse_exited():
|
func _on_mouse_exited():
|
||||||
if not Rect2(Vector2(), size).has_point(get_local_mouse_position()):
|
if not Rect2(Vector2(), size).has_point(get_local_mouse_position()):
|
||||||
# Not hovering over area.
|
# Not hovering over area.
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</signal>
|
</signal>
|
||||||
@@ -1255,10 +1283,10 @@
|
|||||||
[b]Note:[/b] This notification is received alongside [constant Node.NOTIFICATION_ENTER_TREE], so if you are instantiating a scene, the child nodes will not be initialized yet. You can use it to setup theming for this node, child nodes created from script, or if you want to access child nodes added in the editor, make sure the node is ready using [method Node.is_node_ready].
|
[b]Note:[/b] This notification is received alongside [constant Node.NOTIFICATION_ENTER_TREE], so if you are instantiating a scene, the child nodes will not be initialized yet. You can use it to setup theming for this node, child nodes created from script, or if you want to access child nodes added in the editor, make sure the node is ready using [method Node.is_node_ready].
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _notification(what):
|
func _notification(what):
|
||||||
if what == NOTIFICATION_THEME_CHANGED:
|
if what == NOTIFICATION_THEME_CHANGED:
|
||||||
if not is_node_ready():
|
if not is_node_ready():
|
||||||
await ready # Wait until ready signal.
|
await ready # Wait until ready signal.
|
||||||
$Label.add_theme_color_override("font_color", Color.YELLOW)
|
$Label.add_theme_color_override("font_color", Color.YELLOW)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="NOTIFICATION_SCROLL_BEGIN" value="47">
|
<constant name="NOTIFICATION_SCROLL_BEGIN" value="47">
|
||||||
|
|||||||
@@ -20,10 +20,10 @@
|
|||||||
uniform float exposure : hint_range(0, 128) = 1.0;
|
uniform float exposure : hint_range(0, 128) = 1.0;
|
||||||
|
|
||||||
void sky() {
|
void sky() {
|
||||||
// If importing a cubemap from another engine, you may need to flip one of the `EYEDIR` components below
|
// If importing a cubemap from another engine, you may need to flip one of the `EYEDIR` components below
|
||||||
// by replacing it with `-EYEDIR`.
|
// by replacing it with `-EYEDIR`.
|
||||||
vec3 eyedir = vec3(EYEDIR.x, EYEDIR.y, EYEDIR.z);
|
vec3 eyedir = vec3(EYEDIR.x, EYEDIR.y, EYEDIR.z);
|
||||||
COLOR = texture(source_panorama, eyedir).rgb * exposure;
|
COLOR = texture(source_panorama, eyedir).rgb * exposure;
|
||||||
}
|
}
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
After replacing the shader code and saving, specify the imported Cubemap resource in the Shader Parameters section of the ShaderMaterial in the inspector.
|
After replacing the shader code and saving, specify the imported Cubemap resource in the Shader Parameters section of the ShaderMaterial in the inspector.
|
||||||
|
|||||||
@@ -16,26 +16,26 @@
|
|||||||
var peers = []
|
var peers = []
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
server.listen(4242)
|
server.listen(4242)
|
||||||
var key = load("key.key") # Your private key.
|
var key = load("key.key") # Your private key.
|
||||||
var cert = load("cert.crt") # Your X509 certificate.
|
var cert = load("cert.crt") # Your X509 certificate.
|
||||||
dtls.setup(TlsOptions.server(key, cert))
|
dtls.setup(TlsOptions.server(key, cert))
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
while server.is_connection_available():
|
while server.is_connection_available():
|
||||||
var peer = server.take_connection()
|
var peer = server.take_connection()
|
||||||
var dtls_peer = dtls.take_connection(peer)
|
var dtls_peer = dtls.take_connection(peer)
|
||||||
if dtls_peer.get_status() != PacketPeerDTLS.STATUS_HANDSHAKING:
|
if dtls_peer.get_status() != PacketPeerDTLS.STATUS_HANDSHAKING:
|
||||||
continue # It is normal that 50% of the connections fails due to cookie exchange.
|
continue # It is normal that 50% of the connections fails due to cookie exchange.
|
||||||
print("Peer connected!")
|
print("Peer connected!")
|
||||||
peers.append(dtls_peer)
|
peers.append(dtls_peer)
|
||||||
|
|
||||||
for p in peers:
|
for p in peers:
|
||||||
p.poll() # Must poll to update the state.
|
p.poll() # Must poll to update the state.
|
||||||
if p.get_status() == PacketPeerDTLS.STATUS_CONNECTED:
|
if p.get_status() == PacketPeerDTLS.STATUS_CONNECTED:
|
||||||
while p.get_available_packet_count() > 0:
|
while p.get_available_packet_count() > 0:
|
||||||
print("Received message from client: %s" % p.get_packet().get_string_from_utf8())
|
print("Received message from client: %s" % p.get_packet().get_string_from_utf8())
|
||||||
p.put_packet("Hello DTLS client".to_utf8_buffer())
|
p.put_packet("Hello DTLS client".to_utf8_buffer())
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
// ServerNode.cs
|
// ServerNode.cs
|
||||||
@@ -43,45 +43,45 @@
|
|||||||
|
|
||||||
public partial class ServerNode : Node
|
public partial class ServerNode : Node
|
||||||
{
|
{
|
||||||
private DtlsServer _dtls = new DtlsServer();
|
private DtlsServer _dtls = new DtlsServer();
|
||||||
private UdpServer _server = new UdpServer();
|
private UdpServer _server = new UdpServer();
|
||||||
private Godot.Collections.Array<PacketPeerDtls> _peers = [];
|
private Godot.Collections.Array<PacketPeerDtls> _peers = [];
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
_server.Listen(4242);
|
_server.Listen(4242);
|
||||||
var key = GD.Load<CryptoKey>("key.key"); // Your private key.
|
var key = GD.Load<CryptoKey>("key.key"); // Your private key.
|
||||||
var cert = GD.Load<X509Certificate>("cert.crt"); // Your X509 certificate.
|
var cert = GD.Load<X509Certificate>("cert.crt"); // Your X509 certificate.
|
||||||
_dtls.Setup(TlsOptions.Server(key, cert));
|
_dtls.Setup(TlsOptions.Server(key, cert));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
while (_server.IsConnectionAvailable())
|
while (_server.IsConnectionAvailable())
|
||||||
{
|
{
|
||||||
PacketPeerUdp peer = _server.TakeConnection();
|
PacketPeerUdp peer = _server.TakeConnection();
|
||||||
PacketPeerDtls dtlsPeer = _dtls.TakeConnection(peer);
|
PacketPeerDtls dtlsPeer = _dtls.TakeConnection(peer);
|
||||||
if (dtlsPeer.GetStatus() != PacketPeerDtls.Status.Handshaking)
|
if (dtlsPeer.GetStatus() != PacketPeerDtls.Status.Handshaking)
|
||||||
{
|
{
|
||||||
continue; // It is normal that 50% of the connections fails due to cookie exchange.
|
continue; // It is normal that 50% of the connections fails due to cookie exchange.
|
||||||
}
|
}
|
||||||
GD.Print("Peer connected!");
|
GD.Print("Peer connected!");
|
||||||
_peers.Add(dtlsPeer);
|
_peers.Add(dtlsPeer);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var p in _peers)
|
foreach (var p in _peers)
|
||||||
{
|
{
|
||||||
p.Poll(); // Must poll to update the state.
|
p.Poll(); // Must poll to update the state.
|
||||||
if (p.GetStatus() == PacketPeerDtls.Status.Connected)
|
if (p.GetStatus() == PacketPeerDtls.Status.Connected)
|
||||||
{
|
{
|
||||||
while (p.GetAvailablePacketCount() > 0)
|
while (p.GetAvailablePacketCount() > 0)
|
||||||
{
|
{
|
||||||
GD.Print($"Received Message From Client: {p.GetPacket().GetStringFromUtf8()}");
|
GD.Print($"Received Message From Client: {p.GetPacket().GetStringFromUtf8()}");
|
||||||
p.PutPacket("Hello DTLS Client".ToUtf8Buffer());
|
p.PutPacket("Hello DTLS Client".ToUtf8Buffer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -95,18 +95,18 @@
|
|||||||
var connected = false
|
var connected = false
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
udp.connect_to_host("127.0.0.1", 4242)
|
udp.connect_to_host("127.0.0.1", 4242)
|
||||||
dtls.connect_to_peer(udp, false) # Use true in production for certificate validation!
|
dtls.connect_to_peer(udp, false) # Use true in production for certificate validation!
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
dtls.poll()
|
dtls.poll()
|
||||||
if dtls.get_status() == PacketPeerDTLS.STATUS_CONNECTED:
|
if dtls.get_status() == PacketPeerDTLS.STATUS_CONNECTED:
|
||||||
if !connected:
|
if !connected:
|
||||||
# Try to contact server
|
# Try to contact server
|
||||||
dtls.put_packet("The answer is... 42!".to_utf8_buffer())
|
dtls.put_packet("The answer is... 42!".to_utf8_buffer())
|
||||||
while dtls.get_available_packet_count() > 0:
|
while dtls.get_available_packet_count() > 0:
|
||||||
print("Connected: %s" % dtls.get_packet().get_string_from_utf8())
|
print("Connected: %s" % dtls.get_packet().get_string_from_utf8())
|
||||||
connected = true
|
connected = true
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
// ClientNode.cs
|
// ClientNode.cs
|
||||||
@@ -115,33 +115,33 @@
|
|||||||
|
|
||||||
public partial class ClientNode : Node
|
public partial class ClientNode : Node
|
||||||
{
|
{
|
||||||
private PacketPeerDtls _dtls = new PacketPeerDtls();
|
private PacketPeerDtls _dtls = new PacketPeerDtls();
|
||||||
private PacketPeerUdp _udp = new PacketPeerUdp();
|
private PacketPeerUdp _udp = new PacketPeerUdp();
|
||||||
private bool _connected = false;
|
private bool _connected = false;
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
_udp.ConnectToHost("127.0.0.1", 4242);
|
_udp.ConnectToHost("127.0.0.1", 4242);
|
||||||
_dtls.ConnectToPeer(_udp, validateCerts: false); // Use true in production for certificate validation!
|
_dtls.ConnectToPeer(_udp, validateCerts: false); // Use true in production for certificate validation!
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
_dtls.Poll();
|
_dtls.Poll();
|
||||||
if (_dtls.GetStatus() == PacketPeerDtls.Status.Connected)
|
if (_dtls.GetStatus() == PacketPeerDtls.Status.Connected)
|
||||||
{
|
{
|
||||||
if (!_connected)
|
if (!_connected)
|
||||||
{
|
{
|
||||||
// Try to contact server
|
// Try to contact server
|
||||||
_dtls.PutPacket("The Answer Is..42!".ToUtf8Buffer());
|
_dtls.PutPacket("The Answer Is..42!".ToUtf8Buffer());
|
||||||
}
|
}
|
||||||
while (_dtls.GetAvailablePacketCount() > 0)
|
while (_dtls.GetAvailablePacketCount() > 0)
|
||||||
{
|
{
|
||||||
GD.Print($"Connected: {_dtls.GetPacket().GetStringFromUtf8()}");
|
GD.Print($"Connected: {_dtls.GetPacket().GetStringFromUtf8()}");
|
||||||
_connected = true;
|
_connected = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
|
|||||||
@@ -24,12 +24,12 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
for i in Decal.TEXTURE_MAX:
|
for i in Decal.TEXTURE_MAX:
|
||||||
$NewDecal.set_texture(i, $OldDecal.get_texture(i))
|
$NewDecal.set_texture(i, $OldDecal.get_texture(i))
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
for (int i = 0; i < (int)Decal.DecalTexture.Max; i++)
|
for (int i = 0; i < (int)Decal.DecalTexture.Max; i++)
|
||||||
{
|
{
|
||||||
GetNode<Decal>("NewDecal").SetTexture(i, GetNode<Decal>("OldDecal").GetTexture(i));
|
GetNode<Decal>("NewDecal").SetTexture(i, GetNode<Decal>("OldDecal").GetTexture(i));
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -46,12 +46,12 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
for i in Decal.TEXTURE_MAX:
|
for i in Decal.TEXTURE_MAX:
|
||||||
$NewDecal.set_texture(i, $OldDecal.get_texture(i))
|
$NewDecal.set_texture(i, $OldDecal.get_texture(i))
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
for (int i = 0; i < (int)Decal.DecalTexture.Max; i++)
|
for (int i = 0; i < (int)Decal.DecalTexture.Max; i++)
|
||||||
{
|
{
|
||||||
GetNode<Decal>("NewDecal").SetTexture(i, GetNode<Decal>("OldDecal").GetTexture(i));
|
GetNode<Decal>("NewDecal").SetTexture(i, GetNode<Decal>("OldDecal").GetTexture(i));
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
|
|||||||
@@ -14,27 +14,27 @@
|
|||||||
var dict_variable_key = "Another key name"
|
var dict_variable_key = "Another key name"
|
||||||
var dict_variable_value = "value2"
|
var dict_variable_value = "value2"
|
||||||
var another_dict = {
|
var another_dict = {
|
||||||
"Some key name": "value1",
|
"Some key name": "value1",
|
||||||
dict_variable_key: dict_variable_value,
|
dict_variable_key: dict_variable_value,
|
||||||
}
|
}
|
||||||
|
|
||||||
var points_dict = {"White": 50, "Yellow": 75, "Orange": 100}
|
var points_dict = { "White": 50, "Yellow": 75, "Orange": 100 }
|
||||||
|
|
||||||
# Alternative Lua-style syntax.
|
# Alternative Lua-style syntax.
|
||||||
# Doesn't require quotes around keys, but only string constants can be used as key names.
|
# Doesn't require quotes around keys, but only string constants can be used as key names.
|
||||||
# Additionally, key names must start with a letter or an underscore.
|
# Additionally, key names must start with a letter or an underscore.
|
||||||
# Here, `some_key` is a string literal, not a variable!
|
# Here, `some_key` is a string literal, not a variable!
|
||||||
another_dict = {
|
another_dict = {
|
||||||
some_key = 42,
|
some_key = 42,
|
||||||
}
|
}
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
var myDict = new Godot.Collections.Dictionary(); // Creates an empty dictionary.
|
var myDict = new Godot.Collections.Dictionary(); // Creates an empty dictionary.
|
||||||
var pointsDict = new Godot.Collections.Dictionary
|
var pointsDict = new Godot.Collections.Dictionary
|
||||||
{
|
{
|
||||||
{"White", 50},
|
{ "White", 50 },
|
||||||
{"Yellow", 75},
|
{ "Yellow", 75 },
|
||||||
{"Orange", 100}
|
{ "Orange", 100 },
|
||||||
};
|
};
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -42,24 +42,24 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
@export_enum("White", "Yellow", "Orange") var my_color: String
|
@export_enum("White", "Yellow", "Orange") var my_color: String
|
||||||
var points_dict = {"White": 50, "Yellow": 75, "Orange": 100}
|
var points_dict = { "White": 50, "Yellow": 75, "Orange": 100 }
|
||||||
func _ready():
|
func _ready():
|
||||||
# We can't use dot syntax here as `my_color` is a variable.
|
# We can't use dot syntax here as `my_color` is a variable.
|
||||||
var points = points_dict[my_color]
|
var points = points_dict[my_color]
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
[Export(PropertyHint.Enum, "White,Yellow,Orange")]
|
[Export(PropertyHint.Enum, "White,Yellow,Orange")]
|
||||||
public string MyColor { get; set; }
|
public string MyColor { get; set; }
|
||||||
private Godot.Collections.Dictionary _pointsDict = new Godot.Collections.Dictionary
|
private Godot.Collections.Dictionary _pointsDict = new Godot.Collections.Dictionary
|
||||||
{
|
{
|
||||||
{"White", 50},
|
{ "White", 50 },
|
||||||
{"Yellow", 75},
|
{ "Yellow", 75 },
|
||||||
{"Orange", 100}
|
{ "Orange", 100 },
|
||||||
};
|
};
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
int points = (int)_pointsDict[MyColor];
|
int points = (int)_pointsDict[MyColor];
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -68,28 +68,28 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
var my_dict = {
|
var my_dict = {
|
||||||
"First Array": [1, 2, 3, 4] # Assigns an Array to a String key.
|
"First Array": [1, 2, 3, 4] # Assigns an Array to a String key.
|
||||||
}
|
}
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
var myDict = new Godot.Collections.Dictionary
|
var myDict = new Godot.Collections.Dictionary
|
||||||
{
|
{
|
||||||
{"First Array", new Godot.Collections.Array{1, 2, 3, 4}}
|
{ "First Array", new Godot.Collections.Array { 1, 2, 3, 4 } }
|
||||||
};
|
};
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
To add a key to an existing dictionary, access it like an existing key and assign to it:
|
To add a key to an existing dictionary, access it like an existing key and assign to it:
|
||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
var points_dict = {"White": 50, "Yellow": 75, "Orange": 100}
|
var points_dict = { "White": 50, "Yellow": 75, "Orange": 100 }
|
||||||
points_dict["Blue"] = 150 # Add "Blue" as a key and assign 150 as its value.
|
points_dict["Blue"] = 150 # Add "Blue" as a key and assign 150 as its value.
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
var pointsDict = new Godot.Collections.Dictionary
|
var pointsDict = new Godot.Collections.Dictionary
|
||||||
{
|
{
|
||||||
{"White", 50},
|
{ "White", 50 },
|
||||||
{"Yellow", 75},
|
{ "Yellow", 75 },
|
||||||
{"Orange", 100}
|
{ "Orange", 100 },
|
||||||
};
|
};
|
||||||
pointsDict["Blue"] = 150; // Add "Blue" as a key and assign 150 as its value.
|
pointsDict["Blue"] = 150; // Add "Blue" as a key and assign 150 as its value.
|
||||||
[/csharp]
|
[/csharp]
|
||||||
@@ -101,35 +101,35 @@
|
|||||||
# To access the string "Nested value" below, use `my_dict.sub_dict.sub_key` or `my_dict["sub_dict"]["sub_key"]`.
|
# To access the string "Nested value" below, use `my_dict.sub_dict.sub_key` or `my_dict["sub_dict"]["sub_key"]`.
|
||||||
# Indexing styles can be mixed and matched depending on your needs.
|
# Indexing styles can be mixed and matched depending on your needs.
|
||||||
var my_dict = {
|
var my_dict = {
|
||||||
"String Key": 5,
|
"String Key": 5,
|
||||||
4: [1, 2, 3],
|
4: [1, 2, 3],
|
||||||
7: "Hello",
|
7: "Hello",
|
||||||
"sub_dict": {"sub_key": "Nested value"},
|
"sub_dict": { "sub_key": "Nested value" },
|
||||||
}
|
}
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
// This is a valid dictionary.
|
// This is a valid dictionary.
|
||||||
// To access the string "Nested value" below, use `((Godot.Collections.Dictionary)myDict["sub_dict"])["sub_key"]`.
|
// To access the string "Nested value" below, use `((Godot.Collections.Dictionary)myDict["sub_dict"])["sub_key"]`.
|
||||||
var myDict = new Godot.Collections.Dictionary {
|
var myDict = new Godot.Collections.Dictionary {
|
||||||
{"String Key", 5},
|
{ "String Key", 5 },
|
||||||
{4, new Godot.Collections.Array{1,2,3}},
|
{ 4, new Godot.Collections.Array { 1, 2, 3 } },
|
||||||
{7, "Hello"},
|
{ 7, "Hello" },
|
||||||
{"sub_dict", new Godot.Collections.Dictionary{{"sub_key", "Nested value"}}}
|
{ "sub_dict", new Godot.Collections.Dictionary { { "sub_key", "Nested value" } } },
|
||||||
};
|
};
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
The keys of a dictionary can be iterated with the [code]for[/code] keyword:
|
The keys of a dictionary can be iterated with the [code]for[/code] keyword:
|
||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
var groceries = {"Orange": 20, "Apple": 2, "Banana": 4}
|
var groceries = { "Orange": 20, "Apple": 2, "Banana": 4 }
|
||||||
for fruit in groceries:
|
for fruit in groceries:
|
||||||
var amount = groceries[fruit]
|
var amount = groceries[fruit]
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
var groceries = new Godot.Collections.Dictionary{{"Orange", 20}, {"Apple", 2}, {"Banana", 4}};
|
var groceries = new Godot.Collections.Dictionary { { "Orange", 20 }, { "Apple", 2 }, { "Banana", 4 } };
|
||||||
foreach (var (fruit, amount) in groceries)
|
foreach (var (fruit, amount) in groceries)
|
||||||
{
|
{
|
||||||
// `fruit` is the key, `amount` is the value.
|
// `fruit` is the key, `amount` is the value.
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -276,8 +276,8 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
var my_dict = {
|
var my_dict = {
|
||||||
"Redot" : 4,
|
"Redot" : 4,
|
||||||
210 : null,
|
210 : null,
|
||||||
}
|
}
|
||||||
|
|
||||||
print(my_dict.has("Redot")) # Prints true
|
print(my_dict.has("Redot")) # Prints true
|
||||||
@@ -287,8 +287,8 @@
|
|||||||
[csharp]
|
[csharp]
|
||||||
var myDict = new Godot.Collections.Dictionary
|
var myDict = new Godot.Collections.Dictionary
|
||||||
{
|
{
|
||||||
{ "Redot", 4 },
|
{ "Redot", 4 },
|
||||||
{ 210, default },
|
{ 210, default },
|
||||||
};
|
};
|
||||||
|
|
||||||
GD.Print(myDict.ContainsKey("Redot")); // Prints True
|
GD.Print(myDict.ContainsKey("Redot")); // Prints True
|
||||||
@@ -298,8 +298,8 @@
|
|||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
In GDScript, this is equivalent to the [code]in[/code] operator:
|
In GDScript, this is equivalent to the [code]in[/code] operator:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
if "Redot" in {"Redot": 4}:
|
if "Redot" in { "Redot": 4 }:
|
||||||
print("The key is here!") # Will be printed.
|
print("The key is here!") # Will be printed.
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
[b]Note:[/b] This method returns [code]true[/code] as long as the [param key] exists, even if its corresponding value is [code]null[/code].
|
[b]Note:[/b] This method returns [code]true[/code] as long as the [param key] exists, even if its corresponding value is [code]null[/code].
|
||||||
</description>
|
</description>
|
||||||
@@ -310,7 +310,7 @@
|
|||||||
<description>
|
<description>
|
||||||
Returns [code]true[/code] if the dictionary contains all keys in the given [param keys] array.
|
Returns [code]true[/code] if the dictionary contains all keys in the given [param keys] array.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
var data = {"width" : 10, "height" : 20}
|
var data = { "width": 10, "height": 20 }
|
||||||
data.has_all(["height", "width"]) # Returns true
|
data.has_all(["height", "width"]) # Returns true
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
@@ -321,14 +321,14 @@
|
|||||||
Returns a hashed 32-bit integer value representing the dictionary contents.
|
Returns a hashed 32-bit integer value representing the dictionary contents.
|
||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
var dict1 = {"A": 10, "B": 2}
|
var dict1 = { "A": 10, "B": 2 }
|
||||||
var dict2 = {"A": 10, "B": 2}
|
var dict2 = { "A": 10, "B": 2 }
|
||||||
|
|
||||||
print(dict1.hash() == dict2.hash()) # Prints true
|
print(dict1.hash() == dict2.hash()) # Prints true
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
var dict1 = new Godot.Collections.Dictionary{{"A", 10}, {"B", 2}};
|
var dict1 = new Godot.Collections.Dictionary { { "A", 10 }, { "B", 2 } };
|
||||||
var dict2 = new Godot.Collections.Dictionary{{"A", 10}, {"B", 2}};
|
var dict2 = new Godot.Collections.Dictionary { { "A", 10 }, { "B", 2 } };
|
||||||
|
|
||||||
// Godot.Collections.Dictionary has no Hash() method. Use GD.Hash() instead.
|
// Godot.Collections.Dictionary has no Hash() method. Use GD.Hash() instead.
|
||||||
GD.Print(GD.Hash(dict1) == GD.Hash(dict2)); // Prints True
|
GD.Print(GD.Hash(dict1) == GD.Hash(dict2)); // Prints True
|
||||||
@@ -423,14 +423,14 @@
|
|||||||
[csharp]
|
[csharp]
|
||||||
var dict = new Godot.Collections.Dictionary
|
var dict = new Godot.Collections.Dictionary
|
||||||
{
|
{
|
||||||
["item"] = "sword",
|
["item"] = "sword",
|
||||||
["quantity"] = 2,
|
["quantity"] = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
var otherDict = new Godot.Collections.Dictionary
|
var otherDict = new Godot.Collections.Dictionary
|
||||||
{
|
{
|
||||||
["quantity"] = 15,
|
["quantity"] = 15,
|
||||||
["color"] = "silver",
|
["color"] = "silver",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Overwriting of existing keys is disabled by default.
|
// Overwriting of existing keys is disabled by default.
|
||||||
|
|||||||
@@ -19,44 +19,44 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func dir_contents(path):
|
func dir_contents(path):
|
||||||
var dir = DirAccess.open(path)
|
var dir = DirAccess.open(path)
|
||||||
if dir:
|
if dir:
|
||||||
dir.list_dir_begin()
|
dir.list_dir_begin()
|
||||||
var file_name = dir.get_next()
|
var file_name = dir.get_next()
|
||||||
while file_name != "":
|
while file_name != "":
|
||||||
if dir.current_is_dir():
|
if dir.current_is_dir():
|
||||||
print("Found directory: " + file_name)
|
print("Found directory: " + file_name)
|
||||||
else:
|
else:
|
||||||
print("Found file: " + file_name)
|
print("Found file: " + file_name)
|
||||||
file_name = dir.get_next()
|
file_name = dir.get_next()
|
||||||
else:
|
else:
|
||||||
print("An error occurred when trying to access the path.")
|
print("An error occurred when trying to access the path.")
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public void DirContents(string path)
|
public void DirContents(string path)
|
||||||
{
|
{
|
||||||
using var dir = DirAccess.Open(path);
|
using var dir = DirAccess.Open(path);
|
||||||
if (dir != null)
|
if (dir != null)
|
||||||
{
|
{
|
||||||
dir.ListDirBegin();
|
dir.ListDirBegin();
|
||||||
string fileName = dir.GetNext();
|
string fileName = dir.GetNext();
|
||||||
while (fileName != "")
|
while (fileName != "")
|
||||||
{
|
{
|
||||||
if (dir.CurrentIsDir())
|
if (dir.CurrentIsDir())
|
||||||
{
|
{
|
||||||
GD.Print($"Found directory: {fileName}");
|
GD.Print($"Found directory: {fileName}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GD.Print($"Found file: {fileName}");
|
GD.Print($"Found file: {fileName}");
|
||||||
}
|
}
|
||||||
fileName = dir.GetNext();
|
fileName = dir.GetNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GD.Print("An error occurred when trying to access the path.");
|
GD.Print("An error occurred when trying to access the path.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
</brief_description>
|
</brief_description>
|
||||||
<description>
|
<description>
|
||||||
A directional light is a type of [Light2D] node that models an infinite number of parallel rays covering the entire scene. It is used for lights with strong intensity that are located far away from the scene (for example: to model sunlight or moonlight).
|
A directional light is a type of [Light2D] node that models an infinite number of parallel rays covering the entire scene. It is used for lights with strong intensity that are located far away from the scene (for example: to model sunlight or moonlight).
|
||||||
|
Light is emitted in the +Y direction of the node's global basis. For an unrotated light, this means that the light is emitted downwards. The position of the node is ignored; only the basis is used to determine light direction.
|
||||||
[b]Note:[/b] [DirectionalLight2D] does not support light cull masks (but it supports shadow cull masks). It will always light up 2D nodes, regardless of the 2D node's [member CanvasItem.light_mask].
|
[b]Note:[/b] [DirectionalLight2D] does not support light cull masks (but it supports shadow cull masks). It will always light up 2D nodes, regardless of the 2D node's [member CanvasItem.light_mask].
|
||||||
</description>
|
</description>
|
||||||
<tutorials>
|
<tutorials>
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
Directional light from a distance, as from the Sun.
|
Directional light from a distance, as from the Sun.
|
||||||
</brief_description>
|
</brief_description>
|
||||||
<description>
|
<description>
|
||||||
A directional light is a type of [Light3D] node that models an infinite number of parallel rays covering the entire scene. It is used for lights with strong intensity that are located far away from the scene to model sunlight or moonlight. The worldspace location of the DirectionalLight3D transform (origin) is ignored. Only the basis is used to determine light direction.
|
A directional light is a type of [Light3D] node that models an infinite number of parallel rays covering the entire scene. It is used for lights with strong intensity that are located far away from the scene to model sunlight or moonlight.
|
||||||
|
Light is emitted in the -Z direction of the node's global basis. For an unrotated light, this means that the light is emitted forwards, illuminating the front side of a 3D model (see [constant Vector3.FORWARD] and [constant Vector3.MODEL_FRONT]). The position of the node is ignored; only the basis is used to determine light direction.
|
||||||
</description>
|
</description>
|
||||||
<tutorials>
|
<tutorials>
|
||||||
<link title="3D lights and shadows">$DOCS_URL/tutorials/3d/lights_and_shadows.html</link>
|
<link title="3D lights and shadows">$DOCS_URL/tutorials/3d/lights_and_shadows.html</link>
|
||||||
|
|||||||
@@ -1783,7 +1783,7 @@
|
|||||||
[codeblock]
|
[codeblock]
|
||||||
var refresh_rate = DisplayServer.screen_get_refresh_rate()
|
var refresh_rate = DisplayServer.screen_get_refresh_rate()
|
||||||
if refresh_rate < 0:
|
if refresh_rate < 0:
|
||||||
refresh_rate = 60.0
|
refresh_rate = 60.0
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
[b]Note:[/b] One of the following constants can be used as [param screen]: [constant SCREEN_OF_MAIN_WINDOW], [constant SCREEN_PRIMARY], [constant SCREEN_WITH_MOUSE_FOCUS], or [constant SCREEN_WITH_KEYBOARD_FOCUS].
|
[b]Note:[/b] One of the following constants can be used as [param screen]: [constant SCREEN_OF_MAIN_WINDOW], [constant SCREEN_PRIMARY], [constant SCREEN_WITH_MOUSE_FOCUS], or [constant SCREEN_WITH_KEYBOARD_FOCUS].
|
||||||
[b]Note:[/b] This method is implemented on Android, iOS, macOS, Linux (X11 and Wayland), and Windows. On other platforms, this method always returns [code]-1.0[/code].
|
[b]Note:[/b] This method is implemented on Android, iOS, macOS, Linux (X11 and Wayland), and Windows. On other platforms, this method always returns [code]-1.0[/code].
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
Add custom option to the context menu of the plugin's specified slot. When the option is activated, [param callback] will be called. Callback should take single [Array] argument; array contents depend on context menu slot.
|
Add custom option to the context menu of the plugin's specified slot. When the option is activated, [param callback] will be called. Callback should take single [Array] argument; array contents depend on context menu slot.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _popup_menu(paths):
|
func _popup_menu(paths):
|
||||||
add_context_menu_item("File Custom options", handle, ICON)
|
add_context_menu_item("File Custom options", handle, ICON)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
If you want to assign shortcut to the menu item, use [method add_context_menu_item_from_shortcut] instead.
|
If you want to assign shortcut to the menu item, use [method add_context_menu_item_from_shortcut] instead.
|
||||||
</description>
|
</description>
|
||||||
@@ -40,10 +40,10 @@
|
|||||||
Add custom option to the context menu of the plugin's specified slot. The option will have the [param shortcut] assigned and reuse its callback. The shortcut has to be registered beforehand with [method add_menu_shortcut].
|
Add custom option to the context menu of the plugin's specified slot. The option will have the [param shortcut] assigned and reuse its callback. The shortcut has to be registered beforehand with [method add_menu_shortcut].
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _init():
|
func _init():
|
||||||
add_menu_shortcut(SHORTCUT, handle)
|
add_menu_shortcut(SHORTCUT, handle)
|
||||||
|
|
||||||
func _popup_menu(paths):
|
func _popup_menu(paths):
|
||||||
add_context_menu_item_from_shortcut("File Custom options", SHORTCUT, ICON)
|
add_context_menu_item_from_shortcut("File Custom options", SHORTCUT, ICON)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -56,12 +56,12 @@
|
|||||||
Add a submenu to the context menu of the plugin's specified slot. The submenu is not automatically handled, you need to connect to its signals yourself. Also the submenu is freed on every popup, so provide a new [PopupMenu] every time.
|
Add a submenu to the context menu of the plugin's specified slot. The submenu is not automatically handled, you need to connect to its signals yourself. Also the submenu is freed on every popup, so provide a new [PopupMenu] every time.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _popup_menu(paths):
|
func _popup_menu(paths):
|
||||||
var popup_menu = PopupMenu.new()
|
var popup_menu = PopupMenu.new()
|
||||||
popup_menu.add_item("Blue")
|
popup_menu.add_item("Blue")
|
||||||
popup_menu.add_item("White")
|
popup_menu.add_item("White")
|
||||||
popup_menu.id_pressed.connect(_on_color_submenu_option)
|
popup_menu.id_pressed.connect(_on_color_submenu_option)
|
||||||
|
|
||||||
add_context_submenu_item("Set Node Color", popup_menu)
|
add_context_submenu_item("Set Node Color", popup_menu)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
Registers a shortcut associated with the plugin's context menu. This method should be called once (e.g. in plugin's [method Object._init]). [param callback] will be called when user presses the specified [param shortcut] while the menu's context is in effect (e.g. FileSystem dock is focused). Callback should take single [Array] argument; array contents depend on context menu slot.
|
Registers a shortcut associated with the plugin's context menu. This method should be called once (e.g. in plugin's [method Object._init]). [param callback] will be called when user presses the specified [param shortcut] while the menu's context is in effect (e.g. FileSystem dock is focused). Callback should take single [Array] argument; array contents depend on context menu slot.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _init():
|
func _init():
|
||||||
add_menu_shortcut(SHORTCUT, handle)
|
add_menu_shortcut(SHORTCUT, handle)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -95,7 +95,7 @@
|
|||||||
Context menu of Script editor's code editor. [method _popup_menu] will be called with the path to the [CodeEdit] node. You can fetch it using this code:
|
Context menu of Script editor's code editor. [method _popup_menu] will be called with the path to the [CodeEdit] node. You can fetch it using this code:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _popup_menu(paths):
|
func _popup_menu(paths):
|
||||||
var code_edit = Engine.get_main_loop().root.get_node(paths[0]);
|
var code_edit = Engine.get_main_loop().root.get_node(paths[0]);
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
The option callback will receive reference to that node. You can use [CodeEdit] methods to perform symbol lookups etc.
|
The option callback will receive reference to that node. You can use [CodeEdit] methods to perform symbol lookups etc.
|
||||||
</constant>
|
</constant>
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
Context menu of 2D editor's basic right-click menu. [method _popup_menu] will be called with paths to all [CanvasItem] nodes under the cursor. You can fetch them using this code:
|
Context menu of 2D editor's basic right-click menu. [method _popup_menu] will be called with paths to all [CanvasItem] nodes under the cursor. You can fetch them using this code:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _popup_menu(paths):
|
func _popup_menu(paths):
|
||||||
var canvas_item = Engine.get_main_loop().root.get_node(paths[0]); # Replace 0 with the desired index.
|
var canvas_item = Engine.get_main_loop().root.get_node(paths[0]); # Replace 0 with the desired index.
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
The paths array is empty if there weren't any nodes under cursor. The option callback will receive a typed array of [CanvasItem] nodes.
|
The paths array is empty if there weren't any nodes under cursor. The option callback will receive a typed array of [CanvasItem] nodes.
|
||||||
</constant>
|
</constant>
|
||||||
|
|||||||
@@ -15,34 +15,34 @@
|
|||||||
|
|
||||||
class ExampleEditorDebugger extends EditorDebuggerPlugin:
|
class ExampleEditorDebugger extends EditorDebuggerPlugin:
|
||||||
|
|
||||||
func _has_capture(capture):
|
func _has_capture(capture):
|
||||||
# Return true if you wish to handle messages with the prefix "my_plugin:".
|
# Return true if you wish to handle messages with the prefix "my_plugin:".
|
||||||
return capture == "my_plugin"
|
return capture == "my_plugin"
|
||||||
|
|
||||||
func _capture(message, data, session_id):
|
func _capture(message, data, session_id):
|
||||||
if message == "my_plugin:ping":
|
if message == "my_plugin:ping":
|
||||||
get_session(session_id).send_message("my_plugin:echo", data)
|
get_session(session_id).send_message("my_plugin:echo", data)
|
||||||
return true
|
return true
|
||||||
return false
|
return false
|
||||||
|
|
||||||
func _setup_session(session_id):
|
func _setup_session(session_id):
|
||||||
# Add a new tab in the debugger session UI containing a label.
|
# Add a new tab in the debugger session UI containing a label.
|
||||||
var label = Label.new()
|
var label = Label.new()
|
||||||
label.name = "Example plugin" # Will be used as the tab title.
|
label.name = "Example plugin" # Will be used as the tab title.
|
||||||
label.text = "Example plugin"
|
label.text = "Example plugin"
|
||||||
var session = get_session(session_id)
|
var session = get_session(session_id)
|
||||||
# Listens to the session started and stopped signals.
|
# Listens to the session started and stopped signals.
|
||||||
session.started.connect(func (): print("Session started"))
|
session.started.connect(func (): print("Session started"))
|
||||||
session.stopped.connect(func (): print("Session stopped"))
|
session.stopped.connect(func (): print("Session stopped"))
|
||||||
session.add_session_tab(label)
|
session.add_session_tab(label)
|
||||||
|
|
||||||
var debugger = ExampleEditorDebugger.new()
|
var debugger = ExampleEditorDebugger.new()
|
||||||
|
|
||||||
func _enter_tree():
|
func _enter_tree():
|
||||||
add_debugger_plugin(debugger)
|
add_debugger_plugin(debugger)
|
||||||
|
|
||||||
func _exit_tree():
|
func _exit_tree():
|
||||||
remove_debugger_plugin(debugger)
|
remove_debugger_plugin(debugger)
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
To connect on the running game side, use the [EngineDebugger] singleton:
|
To connect on the running game side, use the [EngineDebugger] singleton:
|
||||||
@@ -51,15 +51,15 @@
|
|||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
EngineDebugger.register_message_capture("my_plugin", _capture)
|
EngineDebugger.register_message_capture("my_plugin", _capture)
|
||||||
EngineDebugger.send_message("my_plugin:ping", ["test"])
|
EngineDebugger.send_message("my_plugin:ping", ["test"])
|
||||||
|
|
||||||
func _capture(message, data):
|
func _capture(message, data):
|
||||||
# Note that the "my_plugin:" prefix is not used here.
|
# Note that the "my_plugin:" prefix is not used here.
|
||||||
if message == "echo":
|
if message == "echo":
|
||||||
prints("Echo received:", data)
|
prints("Echo received:", data)
|
||||||
return true
|
return true
|
||||||
return false
|
return false
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
[b]Note:[/b] While the game is running, [method @GlobalScope.print] and similar functions [i]called in the editor[/i] do not print anything, the Output Log prints only game messages.
|
[b]Note:[/b] While the game is running, [method @GlobalScope.print] and similar functions [i]called in the editor[/i] do not print anything, the Output Log prints only game messages.
|
||||||
|
|||||||
@@ -202,20 +202,20 @@
|
|||||||
Return a [Dictionary] of override values for export options, that will be used instead of user-provided values. Overridden options will be hidden from the user interface.
|
Return a [Dictionary] of override values for export options, that will be used instead of user-provided values. Overridden options will be hidden from the user interface.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
class MyExportPlugin extends EditorExportPlugin:
|
class MyExportPlugin extends EditorExportPlugin:
|
||||||
func _get_name() -> String:
|
func _get_name() -> String:
|
||||||
return "MyExportPlugin"
|
return "MyExportPlugin"
|
||||||
|
|
||||||
func _supports_platform(platform) -> bool:
|
func _supports_platform(platform) -> bool:
|
||||||
if platform is EditorExportPlatformPC:
|
if platform is EditorExportPlatformPC:
|
||||||
# Run on all desktop platforms including Windows, MacOS and Linux.
|
# Run on all desktop platforms including Windows, MacOS and Linux.
|
||||||
return true
|
return true
|
||||||
return false
|
return false
|
||||||
|
|
||||||
func _get_export_options_overrides(platform) -> Dictionary:
|
func _get_export_options_overrides(platform) -> Dictionary:
|
||||||
# Override "Embed PCK" to always be enabled.
|
# Override "Embed PCK" to always be enabled.
|
||||||
return {
|
return {
|
||||||
"binary_format/embed_pck": true,
|
"binary_format/embed_pck": true,
|
||||||
}
|
}
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@@ -13,104 +13,104 @@
|
|||||||
extends EditorImportPlugin
|
extends EditorImportPlugin
|
||||||
|
|
||||||
func _get_importer_name():
|
func _get_importer_name():
|
||||||
return "my.special.plugin"
|
return "my.special.plugin"
|
||||||
|
|
||||||
func _get_visible_name():
|
func _get_visible_name():
|
||||||
return "Special Mesh"
|
return "Special Mesh"
|
||||||
|
|
||||||
func _get_recognized_extensions():
|
func _get_recognized_extensions():
|
||||||
return ["special", "spec"]
|
return ["special", "spec"]
|
||||||
|
|
||||||
func _get_save_extension():
|
func _get_save_extension():
|
||||||
return "mesh"
|
return "mesh"
|
||||||
|
|
||||||
func _get_resource_type():
|
func _get_resource_type():
|
||||||
return "Mesh"
|
return "Mesh"
|
||||||
|
|
||||||
func _get_preset_count():
|
func _get_preset_count():
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
func _get_preset_name(preset_index):
|
func _get_preset_name(preset_index):
|
||||||
return "Default"
|
return "Default"
|
||||||
|
|
||||||
func _get_import_options(path, preset_index):
|
func _get_import_options(path, preset_index):
|
||||||
return [{"name": "my_option", "default_value": false}]
|
return [{"name": "my_option", "default_value": false}]
|
||||||
|
|
||||||
func _import(source_file, save_path, options, platform_variants, gen_files):
|
func _import(source_file, save_path, options, platform_variants, gen_files):
|
||||||
var file = FileAccess.open(source_file, FileAccess.READ)
|
var file = FileAccess.open(source_file, FileAccess.READ)
|
||||||
if file == null:
|
if file == null:
|
||||||
return FAILED
|
return FAILED
|
||||||
var mesh = ArrayMesh.new()
|
var mesh = ArrayMesh.new()
|
||||||
# Fill the Mesh with data read in "file", left as an exercise to the reader.
|
# Fill the Mesh with data read in "file", left as an exercise to the reader.
|
||||||
|
|
||||||
var filename = save_path + "." + _get_save_extension()
|
var filename = save_path + "." + _get_save_extension()
|
||||||
return ResourceSaver.save(mesh, filename)
|
return ResourceSaver.save(mesh, filename)
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public partial class MySpecialPlugin : EditorImportPlugin
|
public partial class MySpecialPlugin : EditorImportPlugin
|
||||||
{
|
{
|
||||||
public override string _GetImporterName()
|
public override string _GetImporterName()
|
||||||
{
|
{
|
||||||
return "my.special.plugin";
|
return "my.special.plugin";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string _GetVisibleName()
|
public override string _GetVisibleName()
|
||||||
{
|
{
|
||||||
return "Special Mesh";
|
return "Special Mesh";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string[] _GetRecognizedExtensions()
|
public override string[] _GetRecognizedExtensions()
|
||||||
{
|
{
|
||||||
return ["special", "spec"];
|
return ["special", "spec"];
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string _GetSaveExtension()
|
public override string _GetSaveExtension()
|
||||||
{
|
{
|
||||||
return "mesh";
|
return "mesh";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string _GetResourceType()
|
public override string _GetResourceType()
|
||||||
{
|
{
|
||||||
return "Mesh";
|
return "Mesh";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int _GetPresetCount()
|
public override int _GetPresetCount()
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string _GetPresetName(int presetIndex)
|
public override string _GetPresetName(int presetIndex)
|
||||||
{
|
{
|
||||||
return "Default";
|
return "Default";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Godot.Collections.Array<Godot.Collections.Dictionary> _GetImportOptions(string path, int presetIndex)
|
public override Godot.Collections.Array<Godot.Collections.Dictionary> _GetImportOptions(string path, int presetIndex)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
[
|
[
|
||||||
new Godot.Collections.Dictionary
|
new Godot.Collections.Dictionary
|
||||||
{
|
{
|
||||||
{ "name", "myOption" },
|
{ "name", "myOption" },
|
||||||
{ "default_value", false },
|
{ "default_value", false },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Error _Import(string sourceFile, string savePath, Godot.Collections.Dictionary options, Godot.Collections.Array<string> platformVariants, Godot.Collections.Array<string> genFiles)
|
public override Error _Import(string sourceFile, string savePath, Godot.Collections.Dictionary options, Godot.Collections.Array<string> platformVariants, Godot.Collections.Array<string> genFiles)
|
||||||
{
|
{
|
||||||
using var file = FileAccess.Open(sourceFile, FileAccess.ModeFlags.Read);
|
using var file = FileAccess.Open(sourceFile, FileAccess.ModeFlags.Read);
|
||||||
if (file.GetError() != Error.Ok)
|
if (file.GetError() != Error.Ok)
|
||||||
{
|
{
|
||||||
return Error.Failed;
|
return Error.Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
var mesh = new ArrayMesh();
|
var mesh = new ArrayMesh();
|
||||||
// Fill the Mesh with data read in "file", left as an exercise to the reader.
|
// Fill the Mesh with data read in "file", left as an exercise to the reader.
|
||||||
string filename = $"{savePath}.{_GetSaveExtension()}";
|
string filename = $"{savePath}.{_GetSaveExtension()}";
|
||||||
return ResourceSaver.Save(mesh, filename);
|
return ResourceSaver.Save(mesh, filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -164,22 +164,22 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _get_option_visibility(option, options):
|
func _get_option_visibility(option, options):
|
||||||
# Only show the lossy quality setting if the compression mode is set to "Lossy".
|
# Only show the lossy quality setting if the compression mode is set to "Lossy".
|
||||||
if option == "compress/lossy_quality" and options.has("compress/mode"):
|
if option == "compress/lossy_quality" and options.has("compress/mode"):
|
||||||
return int(options["compress/mode"]) == COMPRESS_LOSSY # This is a constant that you set
|
return int(options["compress/mode"]) == COMPRESS_LOSSY # This is a constant that you set
|
||||||
|
|
||||||
return true
|
return true
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public void _GetOptionVisibility(string option, Godot.Collections.Dictionary options)
|
public void _GetOptionVisibility(string option, Godot.Collections.Dictionary options)
|
||||||
{
|
{
|
||||||
// Only show the lossy quality setting if the compression mode is set to "Lossy".
|
// Only show the lossy quality setting if the compression mode is set to "Lossy".
|
||||||
if (option == "compress/lossy_quality" && options.ContainsKey("compress/mode"))
|
if (option == "compress/lossy_quality" && options.ContainsKey("compress/mode"))
|
||||||
{
|
{
|
||||||
return (int)options["compress/mode"] == CompressLossy; // This is a constant you set
|
return (int)options["compress/mode"] == CompressLossy; // This is a constant you set
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
|
|||||||
@@ -356,14 +356,14 @@
|
|||||||
[b]Example:[/b] Display the node selection dialog as soon as this node is added to the tree for the first time:
|
[b]Example:[/b] Display the node selection dialog as soon as this node is added to the tree for the first time:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _ready():
|
func _ready():
|
||||||
if Engine.is_editor_hint():
|
if Engine.is_editor_hint():
|
||||||
EditorInterface.popup_node_selector(_on_node_selected, ["Button"])
|
EditorInterface.popup_node_selector(_on_node_selected, ["Button"])
|
||||||
|
|
||||||
func _on_node_selected(node_path):
|
func _on_node_selected(node_path):
|
||||||
if node_path.is_empty():
|
if node_path.is_empty():
|
||||||
print("node selection canceled")
|
print("node selection canceled")
|
||||||
else:
|
else:
|
||||||
print("selected ", node_path)
|
print("selected ", node_path)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -377,14 +377,14 @@
|
|||||||
Pops up an editor dialog for selecting properties from [param object]. The [param callback] must take a single argument of type [NodePath]. It is called on the selected property path (see [method NodePath.get_as_property_path]) or the empty path [code]^""[/code] if the dialog is canceled. If [param type_filter] is provided, the dialog will only show properties that match one of the listed [enum Variant.Type] values. If [param current_value] is provided, the property will be selected automatically in the property list, if it exists.
|
Pops up an editor dialog for selecting properties from [param object]. The [param callback] must take a single argument of type [NodePath]. It is called on the selected property path (see [method NodePath.get_as_property_path]) or the empty path [code]^""[/code] if the dialog is canceled. If [param type_filter] is provided, the dialog will only show properties that match one of the listed [enum Variant.Type] values. If [param current_value] is provided, the property will be selected automatically in the property list, if it exists.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _ready():
|
func _ready():
|
||||||
if Engine.is_editor_hint():
|
if Engine.is_editor_hint():
|
||||||
EditorInterface.popup_property_selector(this, _on_property_selected, [TYPE_INT])
|
EditorInterface.popup_property_selector(this, _on_property_selected, [TYPE_INT])
|
||||||
|
|
||||||
func _on_property_selected(property_path):
|
func _on_property_selected(property_path):
|
||||||
if property_path.is_empty():
|
if property_path.is_empty():
|
||||||
print("property selection canceled")
|
print("property selection canceled")
|
||||||
else:
|
else:
|
||||||
print("selected ", property_path)
|
print("selected ", property_path)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@@ -59,32 +59,32 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _forward_3d_draw_over_viewport(overlay):
|
func _forward_3d_draw_over_viewport(overlay):
|
||||||
# Draw a circle at the cursor's position.
|
# Draw a circle at the cursor's position.
|
||||||
overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.WHITE)
|
overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.WHITE)
|
||||||
|
|
||||||
func _forward_3d_gui_input(camera, event):
|
func _forward_3d_gui_input(camera, event):
|
||||||
if event is InputEventMouseMotion:
|
if event is InputEventMouseMotion:
|
||||||
# Redraw the viewport when the cursor is moved.
|
# Redraw the viewport when the cursor is moved.
|
||||||
update_overlays()
|
update_overlays()
|
||||||
return EditorPlugin.AFTER_GUI_INPUT_STOP
|
return EditorPlugin.AFTER_GUI_INPUT_STOP
|
||||||
return EditorPlugin.AFTER_GUI_INPUT_PASS
|
return EditorPlugin.AFTER_GUI_INPUT_PASS
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override void _Forward3DDrawOverViewport(Control viewportControl)
|
public override void _Forward3DDrawOverViewport(Control viewportControl)
|
||||||
{
|
{
|
||||||
// Draw a circle at the cursor's position.
|
// Draw a circle at the cursor's position.
|
||||||
viewportControl.DrawCircle(viewportControl.GetLocalMousePosition(), 64, Colors.White);
|
viewportControl.DrawCircle(viewportControl.GetLocalMousePosition(), 64, Colors.White);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override EditorPlugin.AfterGuiInput _Forward3DGuiInput(Camera3D viewportCamera, InputEvent @event)
|
public override EditorPlugin.AfterGuiInput _Forward3DGuiInput(Camera3D viewportCamera, InputEvent @event)
|
||||||
{
|
{
|
||||||
if (@event is InputEventMouseMotion)
|
if (@event is InputEventMouseMotion)
|
||||||
{
|
{
|
||||||
// Redraw the viewport when the cursor is moved.
|
// Redraw the viewport when the cursor is moved.
|
||||||
UpdateOverlays();
|
UpdateOverlays();
|
||||||
return EditorPlugin.AfterGuiInput.Stop;
|
return EditorPlugin.AfterGuiInput.Stop;
|
||||||
}
|
}
|
||||||
return EditorPlugin.AfterGuiInput.Pass;
|
return EditorPlugin.AfterGuiInput.Pass;
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -108,13 +108,13 @@
|
|||||||
[gdscript]
|
[gdscript]
|
||||||
# Prevents the InputEvent from reaching other Editor classes.
|
# Prevents the InputEvent from reaching other Editor classes.
|
||||||
func _forward_3d_gui_input(camera, event):
|
func _forward_3d_gui_input(camera, event):
|
||||||
return EditorPlugin.AFTER_GUI_INPUT_STOP
|
return EditorPlugin.AFTER_GUI_INPUT_STOP
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
// Prevents the InputEvent from reaching other Editor classes.
|
// Prevents the InputEvent from reaching other Editor classes.
|
||||||
public override EditorPlugin.AfterGuiInput _Forward3DGuiInput(Camera3D camera, InputEvent @event)
|
public override EditorPlugin.AfterGuiInput _Forward3DGuiInput(Camera3D camera, InputEvent @event)
|
||||||
{
|
{
|
||||||
return EditorPlugin.AfterGuiInput.Stop;
|
return EditorPlugin.AfterGuiInput.Stop;
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -123,13 +123,13 @@
|
|||||||
[gdscript]
|
[gdscript]
|
||||||
# Consumes InputEventMouseMotion and forwards other InputEvent types.
|
# Consumes InputEventMouseMotion and forwards other InputEvent types.
|
||||||
func _forward_3d_gui_input(camera, event):
|
func _forward_3d_gui_input(camera, event):
|
||||||
return EditorPlugin.AFTER_GUI_INPUT_STOP if event is InputEventMouseMotion else EditorPlugin.AFTER_GUI_INPUT_PASS
|
return EditorPlugin.AFTER_GUI_INPUT_STOP if event is InputEventMouseMotion else EditorPlugin.AFTER_GUI_INPUT_PASS
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
// Consumes InputEventMouseMotion and forwards other InputEvent types.
|
// Consumes InputEventMouseMotion and forwards other InputEvent types.
|
||||||
public override EditorPlugin.AfterGuiInput _Forward3DGuiInput(Camera3D camera, InputEvent @event)
|
public override EditorPlugin.AfterGuiInput _Forward3DGuiInput(Camera3D camera, InputEvent @event)
|
||||||
{
|
{
|
||||||
return @event is InputEventMouseMotion ? EditorPlugin.AfterGuiInput.Stop : EditorPlugin.AfterGuiInput.Pass;
|
return @event is InputEventMouseMotion ? EditorPlugin.AfterGuiInput.Stop : EditorPlugin.AfterGuiInput.Pass;
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -143,32 +143,32 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _forward_canvas_draw_over_viewport(overlay):
|
func _forward_canvas_draw_over_viewport(overlay):
|
||||||
# Draw a circle at the cursor's position.
|
# Draw a circle at the cursor's position.
|
||||||
overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.WHITE)
|
overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.WHITE)
|
||||||
|
|
||||||
func _forward_canvas_gui_input(event):
|
func _forward_canvas_gui_input(event):
|
||||||
if event is InputEventMouseMotion:
|
if event is InputEventMouseMotion:
|
||||||
# Redraw the viewport when the cursor is moved.
|
# Redraw the viewport when the cursor is moved.
|
||||||
update_overlays()
|
update_overlays()
|
||||||
return true
|
return true
|
||||||
return false
|
return false
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override void _ForwardCanvasDrawOverViewport(Control viewportControl)
|
public override void _ForwardCanvasDrawOverViewport(Control viewportControl)
|
||||||
{
|
{
|
||||||
// Draw a circle at the cursor's position.
|
// Draw a circle at the cursor's position.
|
||||||
viewportControl.DrawCircle(viewportControl.GetLocalMousePosition(), 64, Colors.White);
|
viewportControl.DrawCircle(viewportControl.GetLocalMousePosition(), 64, Colors.White);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool _ForwardCanvasGuiInput(InputEvent @event)
|
public override bool _ForwardCanvasGuiInput(InputEvent @event)
|
||||||
{
|
{
|
||||||
if (@event is InputEventMouseMotion)
|
if (@event is InputEventMouseMotion)
|
||||||
{
|
{
|
||||||
// Redraw the viewport when the cursor is moved.
|
// Redraw the viewport when the cursor is moved.
|
||||||
UpdateOverlays();
|
UpdateOverlays();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -191,13 +191,13 @@
|
|||||||
[gdscript]
|
[gdscript]
|
||||||
# Prevents the InputEvent from reaching other Editor classes.
|
# Prevents the InputEvent from reaching other Editor classes.
|
||||||
func _forward_canvas_gui_input(event):
|
func _forward_canvas_gui_input(event):
|
||||||
return true
|
return true
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
// Prevents the InputEvent from reaching other Editor classes.
|
// Prevents the InputEvent from reaching other Editor classes.
|
||||||
public override bool ForwardCanvasGuiInput(InputEvent @event)
|
public override bool ForwardCanvasGuiInput(InputEvent @event)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -206,19 +206,19 @@
|
|||||||
[gdscript]
|
[gdscript]
|
||||||
# Consumes InputEventMouseMotion and forwards other InputEvent types.
|
# Consumes InputEventMouseMotion and forwards other InputEvent types.
|
||||||
func _forward_canvas_gui_input(event):
|
func _forward_canvas_gui_input(event):
|
||||||
if (event is InputEventMouseMotion):
|
if (event is InputEventMouseMotion):
|
||||||
return true
|
return true
|
||||||
return false
|
return false
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
// Consumes InputEventMouseMotion and forwards other InputEvent types.
|
// Consumes InputEventMouseMotion and forwards other InputEvent types.
|
||||||
public override bool _ForwardCanvasGuiInput(InputEvent @event)
|
public override bool _ForwardCanvasGuiInput(InputEvent @event)
|
||||||
{
|
{
|
||||||
if (@event is InputEventMouseMotion)
|
if (@event is InputEventMouseMotion)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -239,18 +239,18 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _get_plugin_icon():
|
func _get_plugin_icon():
|
||||||
# You can use a custom icon:
|
# You can use a custom icon:
|
||||||
return preload("res://addons/my_plugin/my_plugin_icon.svg")
|
return preload("res://addons/my_plugin/my_plugin_icon.svg")
|
||||||
# Or use a built-in icon:
|
# Or use a built-in icon:
|
||||||
return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons")
|
return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons")
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override Texture2D _GetPluginIcon()
|
public override Texture2D _GetPluginIcon()
|
||||||
{
|
{
|
||||||
// You can use a custom icon:
|
// You can use a custom icon:
|
||||||
return ResourceLoader.Load<Texture2D>("res://addons/my_plugin/my_plugin_icon.svg");
|
return ResourceLoader.Load<Texture2D>("res://addons/my_plugin/my_plugin_icon.svg");
|
||||||
// Or use a built-in icon:
|
// Or use a built-in icon:
|
||||||
return EditorInterface.Singleton.GetEditorTheme().GetIcon("Node", "EditorIcons");
|
return EditorInterface.Singleton.GetEditorTheme().GetIcon("Node", "EditorIcons");
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -272,8 +272,8 @@
|
|||||||
[b]Note:[/b] You must implement [method _get_plugin_name] for the state to be stored and restored correctly.
|
[b]Note:[/b] You must implement [method _get_plugin_name] for the state to be stored and restored correctly.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _get_state():
|
func _get_state():
|
||||||
var state = {"zoom": zoom, "preferred_color": my_color}
|
var state = { "zoom": zoom, "preferred_color": my_color }
|
||||||
return state
|
return state
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -286,22 +286,22 @@
|
|||||||
If the user confirms saving, [method _save_external_data] will be called, before closing the editor.
|
If the user confirms saving, [method _save_external_data] will be called, before closing the editor.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _get_unsaved_status(for_scene):
|
func _get_unsaved_status(for_scene):
|
||||||
if not unsaved:
|
if not unsaved:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
if for_scene.is_empty():
|
if for_scene.is_empty():
|
||||||
return "Save changes in MyCustomPlugin before closing?"
|
return "Save changes in MyCustomPlugin before closing?"
|
||||||
else:
|
else:
|
||||||
return "Scene %s has changes from MyCustomPlugin. Save before closing?" % for_scene.get_file()
|
return "Scene %s has changes from MyCustomPlugin. Save before closing?" % for_scene.get_file()
|
||||||
|
|
||||||
func _save_external_data():
|
func _save_external_data():
|
||||||
unsaved = false
|
unsaved = false
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
If the plugin has no scene-specific changes, you can ignore the calls when closing scenes:
|
If the plugin has no scene-specific changes, you can ignore the calls when closing scenes:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _get_unsaved_status(for_scene):
|
func _get_unsaved_status(for_scene):
|
||||||
if not for_scene.is_empty():
|
if not for_scene.is_empty():
|
||||||
return ""
|
return ""
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -313,8 +313,8 @@
|
|||||||
Use [method _set_window_layout] to restore your saved layout.
|
Use [method _set_window_layout] to restore your saved layout.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _get_window_layout(configuration):
|
func _get_window_layout(configuration):
|
||||||
configuration.set_value("MyPlugin", "window_position", $Window.position)
|
configuration.set_value("MyPlugin", "window_position", $Window.position)
|
||||||
configuration.set_value("MyPlugin", "icon_color", $Icon.modulate)
|
configuration.set_value("MyPlugin", "icon_color", $Icon.modulate)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -336,21 +336,21 @@
|
|||||||
var plugin_control
|
var plugin_control
|
||||||
|
|
||||||
func _enter_tree():
|
func _enter_tree():
|
||||||
plugin_control = preload("my_plugin_control.tscn").instantiate()
|
plugin_control = preload("my_plugin_control.tscn").instantiate()
|
||||||
EditorInterface.get_editor_main_screen().add_child(plugin_control)
|
EditorInterface.get_editor_main_screen().add_child(plugin_control)
|
||||||
plugin_control.hide()
|
plugin_control.hide()
|
||||||
|
|
||||||
func _has_main_screen():
|
func _has_main_screen():
|
||||||
return true
|
return true
|
||||||
|
|
||||||
func _make_visible(visible):
|
func _make_visible(visible):
|
||||||
plugin_control.visible = visible
|
plugin_control.visible = visible
|
||||||
|
|
||||||
func _get_plugin_name():
|
func _get_plugin_name():
|
||||||
return "My Super Cool Plugin 3000"
|
return "My Super Cool Plugin 3000"
|
||||||
|
|
||||||
func _get_plugin_icon():
|
func _get_plugin_icon():
|
||||||
return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons")
|
return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons")
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -376,8 +376,8 @@
|
|||||||
[b]Note:[/b] Your plugin must implement [method _get_plugin_name], otherwise it will not be recognized and this method will not be called.
|
[b]Note:[/b] Your plugin must implement [method _get_plugin_name], otherwise it will not be recognized and this method will not be called.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _set_state(data):
|
func _set_state(data):
|
||||||
zoom = data.get("zoom", 1.0)
|
zoom = data.get("zoom", 1.0)
|
||||||
preferred_color = data.get("my_color", Color.WHITE)
|
preferred_color = data.get("my_color", Color.WHITE)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -388,8 +388,8 @@
|
|||||||
Restore the plugin GUI layout and data saved by [method _get_window_layout]. This method is called for every plugin on editor startup. Use the provided [param configuration] file to read your saved data.
|
Restore the plugin GUI layout and data saved by [method _get_window_layout]. This method is called for every plugin on editor startup. Use the provided [param configuration] file to read your saved data.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _set_window_layout(configuration):
|
func _set_window_layout(configuration):
|
||||||
$Window.position = configuration.get_value("MyPlugin", "window_position", Vector2())
|
$Window.position = configuration.get_value("MyPlugin", "window_position", Vector2())
|
||||||
$Icon.modulate = configuration.get_value("MyPlugin", "icon_color", Color.WHITE)
|
$Icon.modulate = configuration.get_value("MyPlugin", "icon_color", Color.WHITE)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -502,10 +502,10 @@
|
|||||||
var inspector_plugin = MyInspectorPlugin.new()
|
var inspector_plugin = MyInspectorPlugin.new()
|
||||||
|
|
||||||
func _enter_tree():
|
func _enter_tree():
|
||||||
add_inspector_plugin(inspector_plugin)
|
add_inspector_plugin(inspector_plugin)
|
||||||
|
|
||||||
func _exit_tree():
|
func _exit_tree():
|
||||||
remove_inspector_plugin(inspector_plugin)
|
remove_inspector_plugin(inspector_plugin)
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -11,15 +11,15 @@
|
|||||||
extends EditorResourceConversionPlugin
|
extends EditorResourceConversionPlugin
|
||||||
|
|
||||||
func _handles(resource: Resource):
|
func _handles(resource: Resource):
|
||||||
return resource is ImageTexture
|
return resource is ImageTexture
|
||||||
|
|
||||||
func _converts_to():
|
func _converts_to():
|
||||||
return "PortableCompressedTexture2D"
|
return "PortableCompressedTexture2D"
|
||||||
|
|
||||||
func _convert(itex: Resource):
|
func _convert(itex: Resource):
|
||||||
var ptex = PortableCompressedTexture2D.new()
|
var ptex = PortableCompressedTexture2D.new()
|
||||||
ptex.create_from_image(itex.get_image(), PortableCompressedTexture2D.COMPRESSION_MODE_LOSSLESS)
|
ptex.create_from_image(itex.get_image(), PortableCompressedTexture2D.COMPRESSION_MODE_LOSSLESS)
|
||||||
return ptex
|
return ptex
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
To use an [EditorResourceConversionPlugin], register it using the [method EditorPlugin.add_resource_conversion_plugin] method first.
|
To use an [EditorResourceConversionPlugin], register it using the [method EditorPlugin.add_resource_conversion_plugin] method first.
|
||||||
|
|||||||
@@ -30,10 +30,10 @@
|
|||||||
[b]Note:[/b] If you decide to discard the [param base], make sure to call [method Node.queue_free], because it's not freed automatically.
|
[b]Note:[/b] If you decide to discard the [param base], make sure to call [method Node.queue_free], because it's not freed automatically.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _make_tooltip_for_path(path, metadata, base):
|
func _make_tooltip_for_path(path, metadata, base):
|
||||||
var t_rect = TextureRect.new()
|
var t_rect = TextureRect.new()
|
||||||
request_thumbnail(path, t_rect)
|
request_thumbnail(path, t_rect)
|
||||||
base.add_child(t_rect) # The TextureRect will appear at the bottom of the tooltip.
|
base.add_child(t_rect) # The TextureRect will appear at the bottom of the tooltip.
|
||||||
return base
|
return base
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@@ -14,15 +14,15 @@
|
|||||||
# This sample changes all node names.
|
# This sample changes all node names.
|
||||||
# Called right after the scene is imported and gets the root node.
|
# Called right after the scene is imported and gets the root node.
|
||||||
func _post_import(scene):
|
func _post_import(scene):
|
||||||
# Change all node names to "modified_[oldnodename]"
|
# Change all node names to "modified_[oldnodename]"
|
||||||
iterate(scene)
|
iterate(scene)
|
||||||
return scene # Remember to return the imported scene
|
return scene # Remember to return the imported scene
|
||||||
|
|
||||||
func iterate(node):
|
func iterate(node):
|
||||||
if node != null:
|
if node != null:
|
||||||
node.name = "modified_" + node.name
|
node.name = "modified_" + node.name
|
||||||
for child in node.get_children():
|
for child in node.get_children():
|
||||||
iterate(child)
|
iterate(child)
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
using Godot;
|
using Godot;
|
||||||
@@ -32,24 +32,24 @@
|
|||||||
[Tool]
|
[Tool]
|
||||||
public partial class NodeRenamer : EditorScenePostImport
|
public partial class NodeRenamer : EditorScenePostImport
|
||||||
{
|
{
|
||||||
public override GodotObject _PostImport(Node scene)
|
public override GodotObject _PostImport(Node scene)
|
||||||
{
|
{
|
||||||
// Change all node names to "modified_[oldnodename]"
|
// Change all node names to "modified_[oldnodename]"
|
||||||
Iterate(scene);
|
Iterate(scene);
|
||||||
return scene; // Remember to return the imported scene
|
return scene; // Remember to return the imported scene
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Iterate(Node node)
|
public void Iterate(Node node)
|
||||||
{
|
{
|
||||||
if (node != null)
|
if (node != null)
|
||||||
{
|
{
|
||||||
node.Name = $"modified_{node.Name}";
|
node.Name = $"modified_{node.Name}";
|
||||||
foreach (Node child in node.GetChildren())
|
foreach (Node child in node.GetChildren())
|
||||||
{
|
{
|
||||||
Iterate(child);
|
Iterate(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
extends EditorScript
|
extends EditorScript
|
||||||
|
|
||||||
func _run():
|
func _run():
|
||||||
print("Hello from the Redot Editor!")
|
print("Hello from the Redot Editor!")
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
using Godot;
|
using Godot;
|
||||||
@@ -22,10 +22,10 @@
|
|||||||
[Tool]
|
[Tool]
|
||||||
public partial class HelloEditor : EditorScript
|
public partial class HelloEditor : EditorScript
|
||||||
{
|
{
|
||||||
public override void _Run()
|
public override void _Run()
|
||||||
{
|
{
|
||||||
GD.Print("Hello from the Redot Editor!");
|
GD.Print("Hello from the Redot Editor!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
|
|||||||
@@ -44,10 +44,10 @@
|
|||||||
settings.set("category/property_name", 0)
|
settings.set("category/property_name", 0)
|
||||||
|
|
||||||
var property_info = {
|
var property_info = {
|
||||||
"name": "category/property_name",
|
"name": "category/property_name",
|
||||||
"type": TYPE_INT,
|
"type": TYPE_INT,
|
||||||
"hint": PROPERTY_HINT_ENUM,
|
"hint": PROPERTY_HINT_ENUM,
|
||||||
"hint_string": "one,two,three"
|
"hint_string": "one,two,three"
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.add_property_info(property_info)
|
settings.add_property_info(property_info)
|
||||||
@@ -58,10 +58,10 @@
|
|||||||
|
|
||||||
var propertyInfo = new Godot.Collections.Dictionary
|
var propertyInfo = new Godot.Collections.Dictionary
|
||||||
{
|
{
|
||||||
{"name", "category/propertyName"},
|
{ "name", "category/propertyName" },
|
||||||
{"type", Variant.Type.Int},
|
{ "type", Variant.Type.Int },
|
||||||
{"hint", PropertyHint.Enum},
|
{ "hint", PropertyHint.Enum },
|
||||||
{"hint_string", "one,two,three"}
|
{ "hint_string", "one,two,three" },
|
||||||
};
|
};
|
||||||
|
|
||||||
settings.AddPropertyInfo(propertyInfo);
|
settings.AddPropertyInfo(propertyInfo);
|
||||||
@@ -897,7 +897,7 @@
|
|||||||
[b]Note:[/b] This setting affects most [EditorInspector]s in the editor UI, primarily Project Settings and Editor Settings. To control names displayed in the Inspector dock, use [member interface/inspector/default_property_name_style] instead.
|
[b]Note:[/b] This setting affects most [EditorInspector]s in the editor UI, primarily Project Settings and Editor Settings. To control names displayed in the Inspector dock, use [member interface/inspector/default_property_name_style] instead.
|
||||||
</member>
|
</member>
|
||||||
<member name="interface/editor/low_processor_mode_sleep_usec" type="int" setter="" getter="">
|
<member name="interface/editor/low_processor_mode_sleep_usec" type="int" setter="" getter="">
|
||||||
The amount of sleeping between frames when the low-processor usage mode is enabled (in microseconds). Higher values will result in lower CPU/GPU usage, which can improve battery life on laptops. However, higher values will result in a less responsive editor. The default value is set to allow for maximum smoothness on monitors up to 144 Hz. See also [member interface/editor/unfocused_low_processor_mode_sleep_usec].
|
The amount of sleeping between frames in the editor (in microseconds). Higher values will result in lower CPU/GPU usage, which can improve battery life on laptops. However, higher values will result in a less responsive editor. The default value is set to allow for maximum smoothness on monitors up to 144 Hz. See also [member interface/editor/unfocused_low_processor_mode_sleep_usec].
|
||||||
[b]Note:[/b] This setting is ignored if [member interface/editor/update_continuously] is [code]true[/code], as enabling that setting disables low-processor mode.
|
[b]Note:[/b] This setting is ignored if [member interface/editor/update_continuously] is [code]true[/code], as enabling that setting disables low-processor mode.
|
||||||
</member>
|
</member>
|
||||||
<member name="interface/editor/main_font" type="String" setter="" getter="">
|
<member name="interface/editor/main_font" type="String" setter="" getter="">
|
||||||
@@ -950,7 +950,7 @@
|
|||||||
Editor UI default layout direction.
|
Editor UI default layout direction.
|
||||||
</member>
|
</member>
|
||||||
<member name="interface/editor/unfocused_low_processor_mode_sleep_usec" type="int" setter="" getter="">
|
<member name="interface/editor/unfocused_low_processor_mode_sleep_usec" type="int" setter="" getter="">
|
||||||
When the editor window is unfocused, the amount of sleeping between frames when the low-processor usage mode is enabled (in microseconds). Higher values will result in lower CPU/GPU usage, which can improve battery life on laptops (in addition to improving the running project's performance if the editor has to redraw continuously). However, higher values will result in a less responsive editor. The default value is set to limit the editor to 20 FPS when the editor window is unfocused. See also [member interface/editor/low_processor_mode_sleep_usec].
|
When the editor window is unfocused, the amount of sleeping between frames when the low-processor usage mode is enabled (in microseconds). Higher values will result in lower CPU/GPU usage, which can improve battery life on laptops (in addition to improving the running project's performance if the editor has to redraw continuously). However, higher values will result in a less responsive editor. The default value is set to limit the editor to 10 FPS when the editor window is unfocused. See also [member interface/editor/low_processor_mode_sleep_usec].
|
||||||
[b]Note:[/b] This setting is ignored if [member interface/editor/update_continuously] is [code]true[/code], as enabling that setting disables low-processor mode.
|
[b]Note:[/b] This setting is ignored if [member interface/editor/update_continuously] is [code]true[/code], as enabling that setting disables low-processor mode.
|
||||||
</member>
|
</member>
|
||||||
<member name="interface/editor/update_continuously" type="bool" setter="" getter="">
|
<member name="interface/editor/update_continuously" type="bool" setter="" getter="">
|
||||||
|
|||||||
@@ -10,6 +10,12 @@
|
|||||||
<tutorials>
|
<tutorials>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
<methods>
|
<methods>
|
||||||
|
<method name="_create" qualifiers="virtual const">
|
||||||
|
<return type="EditorSyntaxHighlighter" />
|
||||||
|
<description>
|
||||||
|
Virtual method which creates a new instance of the syntax highlighter.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="_get_name" qualifiers="virtual const">
|
<method name="_get_name" qualifiers="virtual const">
|
||||||
<return type="String" />
|
<return type="String" />
|
||||||
<description>
|
<description>
|
||||||
|
|||||||
@@ -14,18 +14,18 @@
|
|||||||
extends EditorTranslationParserPlugin
|
extends EditorTranslationParserPlugin
|
||||||
|
|
||||||
func _parse_file(path):
|
func _parse_file(path):
|
||||||
var ret: Array[PackedStringArray] = []
|
var ret: Array[PackedStringArray] = []
|
||||||
var file = FileAccess.open(path, FileAccess.READ)
|
var file = FileAccess.open(path, FileAccess.READ)
|
||||||
var text = file.get_as_text()
|
var text = file.get_as_text()
|
||||||
var split_strs = text.split(",", false)
|
var split_strs = text.split(",", false)
|
||||||
for s in split_strs:
|
for s in split_strs:
|
||||||
ret.append(PackedStringArray([s]))
|
ret.append(PackedStringArray([s]))
|
||||||
#print("Extracted string: " + s)
|
#print("Extracted string: " + s)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
func _get_recognized_extensions():
|
func _get_recognized_extensions():
|
||||||
return ["csv"]
|
return ["csv"]
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
using Godot;
|
using Godot;
|
||||||
@@ -33,24 +33,24 @@
|
|||||||
[Tool]
|
[Tool]
|
||||||
public partial class CustomParser : EditorTranslationParserPlugin
|
public partial class CustomParser : EditorTranslationParserPlugin
|
||||||
{
|
{
|
||||||
public override Godot.Collections.Array<string[]> _ParseFile(string path)
|
public override Godot.Collections.Array<string[]> _ParseFile(string path)
|
||||||
{
|
{
|
||||||
Godot.Collections.Array<string[]> ret;
|
Godot.Collections.Array<string[]> ret;
|
||||||
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
|
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
|
||||||
string text = file.GetAsText();
|
string text = file.GetAsText();
|
||||||
string[] splitStrs = text.Split(",", allowEmpty: false);
|
string[] splitStrs = text.Split(",", allowEmpty: false);
|
||||||
foreach (string s in splitStrs)
|
foreach (string s in splitStrs)
|
||||||
{
|
{
|
||||||
ret.Add([s]);
|
ret.Add([s]);
|
||||||
//GD.Print($"Extracted string: {s}");
|
//GD.Print($"Extracted string: {s}");
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string[] _GetRecognizedExtensions()
|
public override string[] _GetRecognizedExtensions()
|
||||||
{
|
{
|
||||||
return ["csv"];
|
return ["csv"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -77,24 +77,24 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _parse_file(path):
|
func _parse_file(path):
|
||||||
var res = ResourceLoader.load(path, "Script")
|
var res = ResourceLoader.load(path, "Script")
|
||||||
var text = res.source_code
|
var text = res.source_code
|
||||||
# Parsing logic.
|
# Parsing logic.
|
||||||
|
|
||||||
func _get_recognized_extensions():
|
func _get_recognized_extensions():
|
||||||
return ["gd"]
|
return ["gd"]
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override Godot.Collections.Array<string[]> _ParseFile(string path)
|
public override Godot.Collections.Array<string[]> _ParseFile(string path)
|
||||||
{
|
{
|
||||||
var res = ResourceLoader.Load<Script>(path, "Script");
|
var res = ResourceLoader.Load<Script>(path, "Script");
|
||||||
string text = res.SourceCode;
|
string text = res.SourceCode;
|
||||||
// Parsing logic.
|
// Parsing logic.
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string[] _GetRecognizedExtensions()
|
public override string[] _GetRecognizedExtensions()
|
||||||
{
|
{
|
||||||
return ["gd"];
|
return ["gd"];
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
|
|||||||
@@ -142,18 +142,18 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _physics_process(_delta):
|
func _physics_process(_delta):
|
||||||
if Engine.get_physics_frames() % 2 == 0:
|
if Engine.get_physics_frames() % 2 == 0:
|
||||||
pass # Run expensive logic only once every 2 physics frames here.
|
pass # Run expensive logic only once every 2 physics frames here.
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override void _PhysicsProcess(double delta)
|
public override void _PhysicsProcess(double delta)
|
||||||
{
|
{
|
||||||
base._PhysicsProcess(delta);
|
base._PhysicsProcess(delta);
|
||||||
|
|
||||||
if (Engine.GetPhysicsFrames() % 2 == 0)
|
if (Engine.GetPhysicsFrames() % 2 == 0)
|
||||||
{
|
{
|
||||||
// Run expensive logic only once every 2 physics frames here.
|
// Run expensive logic only once every 2 physics frames here.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -173,18 +173,18 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _process(_delta):
|
func _process(_delta):
|
||||||
if Engine.get_process_frames() % 5 == 0:
|
if Engine.get_process_frames() % 5 == 0:
|
||||||
pass # Run expensive logic only once every 5 process (render) frames here.
|
pass # Run expensive logic only once every 5 process (render) frames here.
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
base._Process(delta);
|
base._Process(delta);
|
||||||
|
|
||||||
if (Engine.GetProcessFrames() % 5 == 0)
|
if (Engine.GetProcessFrames() % 5 == 0)
|
||||||
{
|
{
|
||||||
// Run expensive logic only once every 5 process (render) frames here.
|
// Run expensive logic only once every 5 process (render) frames here.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -236,18 +236,18 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
if Engine.get_version_info().hex >= 0x040100:
|
if Engine.get_version_info().hex >= 0x040100:
|
||||||
pass # Do things specific to version 4.1 or later.
|
pass # Do things specific to version 4.1 or later.
|
||||||
else:
|
else:
|
||||||
pass # Do things specific to versions before 4.1.
|
pass # Do things specific to versions before 4.1.
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
if ((int)Engine.GetVersionInfo()["hex"] >= 0x040100)
|
if ((int)Engine.GetVersionInfo()["hex"] >= 0x040100)
|
||||||
{
|
{
|
||||||
// Do things specific to version 4.1 or later.
|
// Do things specific to version 4.1 or later.
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Do things specific to versions before 4.1.
|
// Do things specific to versions before 4.1.
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -289,15 +289,15 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
if Engine.is_editor_hint():
|
if Engine.is_editor_hint():
|
||||||
draw_gizmos()
|
draw_gizmos()
|
||||||
else:
|
else:
|
||||||
simulate_physics()
|
simulate_physics()
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
if (Engine.IsEditorHint())
|
if (Engine.IsEditorHint())
|
||||||
DrawGizmos();
|
DrawGizmos();
|
||||||
else
|
else
|
||||||
SimulatePhysics();
|
SimulatePhysics();
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
See [url=$DOCS_URL/tutorials/plugins/running_code_in_the_editor.html]Running code in the editor[/url] in the documentation for more information.
|
See [url=$DOCS_URL/tutorials/plugins/running_code_in_the_editor.html]Running code in the editor[/url] in the documentation for more information.
|
||||||
@@ -316,15 +316,15 @@
|
|||||||
Returns [code]true[/code] if the engine is inside the fixed physics process step of the main loop.
|
Returns [code]true[/code] if the engine is inside the fixed physics process step of the main loop.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _enter_tree():
|
func _enter_tree():
|
||||||
# Depending on when the node is added to the tree,
|
# Depending on when the node is added to the tree,
|
||||||
# prints either "true" or "false".
|
# prints either "true" or "false".
|
||||||
print(Engine.is_in_physics_frame())
|
print(Engine.is_in_physics_frame())
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
print(Engine.is_in_physics_frame()) # Prints false
|
print(Engine.is_in_physics_frame()) # Prints false
|
||||||
|
|
||||||
func _physics_process(delta):
|
func _physics_process(delta):
|
||||||
print(Engine.is_in_physics_frame()) # Prints true
|
print(Engine.is_in_physics_frame()) # Prints true
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@@ -12,38 +12,38 @@
|
|||||||
var expression = Expression.new()
|
var expression = Expression.new()
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
$LineEdit.text_submitted.connect(self._on_text_submitted)
|
$LineEdit.text_submitted.connect(self._on_text_submitted)
|
||||||
|
|
||||||
func _on_text_submitted(command):
|
func _on_text_submitted(command):
|
||||||
var error = expression.parse(command)
|
var error = expression.parse(command)
|
||||||
if error != OK:
|
if error != OK:
|
||||||
print(expression.get_error_text())
|
print(expression.get_error_text())
|
||||||
return
|
return
|
||||||
var result = expression.execute()
|
var result = expression.execute()
|
||||||
if not expression.has_execute_failed():
|
if not expression.has_execute_failed():
|
||||||
$LineEdit.text = str(result)
|
$LineEdit.text = str(result)
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
private Expression _expression = new Expression();
|
private Expression _expression = new Expression();
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
GetNode<LineEdit>("LineEdit").TextSubmitted += OnTextEntered;
|
GetNode<LineEdit>("LineEdit").TextSubmitted += OnTextEntered;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTextEntered(string command)
|
private void OnTextEntered(string command)
|
||||||
{
|
{
|
||||||
Error error = _expression.Parse(command);
|
Error error = _expression.Parse(command);
|
||||||
if (error != Error.Ok)
|
if (error != Error.Ok)
|
||||||
{
|
{
|
||||||
GD.Print(_expression.GetErrorText());
|
GD.Print(_expression.GetErrorText());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Variant result = _expression.Execute();
|
Variant result = _expression.Execute();
|
||||||
if (!_expression.HasExecuteFailed())
|
if (!_expression.HasExecuteFailed())
|
||||||
{
|
{
|
||||||
GetNode<LineEdit>("LineEdit").Text = result.ToString();
|
GetNode<LineEdit>("LineEdit").Text = result.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
|
|||||||
@@ -9,29 +9,30 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func save_to_file(content):
|
func save_to_file(content):
|
||||||
var file = FileAccess.open("user://save_game.dat", FileAccess.WRITE)
|
var file = FileAccess.open("user://save_game.dat", FileAccess.WRITE)
|
||||||
file.store_string(content)
|
file.store_string(content)
|
||||||
|
|
||||||
func load_from_file():
|
func load_from_file():
|
||||||
var file = FileAccess.open("user://save_game.dat", FileAccess.READ)
|
var file = FileAccess.open("user://save_game.dat", FileAccess.READ)
|
||||||
var content = file.get_as_text()
|
var content = file.get_as_text()
|
||||||
return content
|
return content
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public void SaveToFile(string content)
|
public void SaveToFile(string content)
|
||||||
{
|
{
|
||||||
using var file = FileAccess.Open("user://save_game.dat", FileAccess.ModeFlags.Write);
|
using var file = FileAccess.Open("user://save_game.dat", FileAccess.ModeFlags.Write);
|
||||||
file.StoreString(content);
|
file.StoreString(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string LoadFromFile()
|
public string LoadFromFile()
|
||||||
{
|
{
|
||||||
using var file = FileAccess.Open("user://save_game.dat", FileAccess.ModeFlags.Read);
|
using var file = FileAccess.Open("user://save_game.dat", FileAccess.ModeFlags.Read);
|
||||||
string content = file.GetAsText();
|
string content = file.GetAsText();
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
|
A [FileAccess] instance has its own file cursor, which is the position in bytes in the file where the next read/write operation will occur. Functions such as [method get_8], [method get_16], [method store_8], and [method store_16] will move the file cursor forward by the number of bytes read/written. The file cursor can be moved to a specific position using [method seek] or [method seek_end], and its position can be retrieved using [method get_position].
|
||||||
A [FileAccess] instance will close its file when the instance is freed. Since it inherits [RefCounted], this happens automatically when it is no longer in use. [method close] can be called to close it earlier. In C#, the reference must be disposed manually, which can be done with the [code]using[/code] statement or by calling the [code]Dispose[/code] method directly.
|
A [FileAccess] instance will close its file when the instance is freed. Since it inherits [RefCounted], this happens automatically when it is no longer in use. [method close] can be called to close it earlier. In C#, the reference must be disposed manually, which can be done with the [code]using[/code] statement or by calling the [code]Dispose[/code] method directly.
|
||||||
[b]Note:[/b] To access project resources once exported, it is recommended to use [ResourceLoader] instead of [FileAccess], as some files are converted to engine-specific formats and their original source files might not be present in the exported PCK package. If using [FileAccess], make sure the file is included in the export by changing its import mode to [b]Keep File (exported as is)[/b] in the Import dock, or, for files where this option is not available, change the non-resource export filter in the Export dialog to include the file's extension (e.g. [code]*.txt[/code]).
|
[b]Note:[/b] To access project resources once exported, it is recommended to use [ResourceLoader] instead of [FileAccess], as some files are converted to engine-specific formats and their original source files might not be present in the exported PCK package. If using [FileAccess], make sure the file is included in the export by changing its import mode to [b]Keep File (exported as is)[/b] in the Import dock, or, for files where this option is not available, change the non-resource export filter in the Export dialog to include the file's extension (e.g. [code]*.txt[/code]).
|
||||||
[b]Note:[/b] Files are automatically closed only if the process exits "normally" (such as by clicking the window manager's close button or pressing [kbd]Alt + F4[/kbd]). If you stop the project execution by pressing [kbd]F8[/kbd] while the project is running, the file won't be closed as the game process will be killed. You can work around this by calling [method flush] at regular intervals.
|
[b]Note:[/b] Files are automatically closed only if the process exits "normally" (such as by clicking the window manager's close button or pressing [kbd]Alt + F4[/kbd]). If you stop the project execution by pressing [kbd]F8[/kbd] while the project is running, the file won't be closed as the game process will be killed. You can work around this by calling [method flush] at regular intervals.
|
||||||
@@ -39,6 +40,7 @@
|
|||||||
<tutorials>
|
<tutorials>
|
||||||
<link title="File system">$DOCS_URL/tutorials/scripting/filesystem.html</link>
|
<link title="File system">$DOCS_URL/tutorials/scripting/filesystem.html</link>
|
||||||
<link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link>
|
<link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link>
|
||||||
|
<link title="Binary serialization API">$DOCS_URL/tutorials/io/binary_serialization_api.html</link>
|
||||||
<link title="3D Voxel Demo">https://godotengine.org/asset-library/asset/2755</link>
|
<link title="3D Voxel Demo">https://godotengine.org/asset-library/asset/2755</link>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
<methods>
|
<methods>
|
||||||
@@ -71,12 +73,12 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
while file.get_position() < file.get_length():
|
while file.get_position() < file.get_length():
|
||||||
# Read data
|
# Read data
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
while (file.GetPosition() < file.GetLength())
|
while (file.GetPosition() < file.GetLength())
|
||||||
{
|
{
|
||||||
// Read data
|
// Read data
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -101,25 +103,25 @@
|
|||||||
<method name="get_8" qualifiers="const">
|
<method name="get_8" qualifiers="const">
|
||||||
<return type="int" />
|
<return type="int" />
|
||||||
<description>
|
<description>
|
||||||
Returns the next 8 bits from the file as an integer. See [method store_8] for details on what values can be stored and retrieved this way.
|
Returns the next 8 bits from the file as an integer. This advances the file cursor by 1 byte. See [method store_8] for details on what values can be stored and retrieved this way.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_16" qualifiers="const">
|
<method name="get_16" qualifiers="const">
|
||||||
<return type="int" />
|
<return type="int" />
|
||||||
<description>
|
<description>
|
||||||
Returns the next 16 bits from the file as an integer. See [method store_16] for details on what values can be stored and retrieved this way.
|
Returns the next 16 bits from the file as an integer. This advances the file cursor by 2 bytes. See [method store_16] for details on what values can be stored and retrieved this way.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_32" qualifiers="const">
|
<method name="get_32" qualifiers="const">
|
||||||
<return type="int" />
|
<return type="int" />
|
||||||
<description>
|
<description>
|
||||||
Returns the next 32 bits from the file as an integer. See [method store_32] for details on what values can be stored and retrieved this way.
|
Returns the next 32 bits from the file as an integer. This advances the file cursor by 4 bytes. See [method store_32] for details on what values can be stored and retrieved this way.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_64" qualifiers="const">
|
<method name="get_64" qualifiers="const">
|
||||||
<return type="int" />
|
<return type="int" />
|
||||||
<description>
|
<description>
|
||||||
Returns the next 64 bits from the file as an integer. See [method store_64] for details on what values can be stored and retrieved this way.
|
Returns the next 64 bits from the file as an integer. This advances the file cursor by 8 bytes. See [method store_64] for details on what values can be stored and retrieved this way.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_access_time" qualifiers="static">
|
<method name="get_access_time" qualifiers="static">
|
||||||
@@ -133,7 +135,7 @@
|
|||||||
<return type="String" />
|
<return type="String" />
|
||||||
<param index="0" name="skip_cr" type="bool" default="false" />
|
<param index="0" name="skip_cr" type="bool" default="false" />
|
||||||
<description>
|
<description>
|
||||||
Returns the whole file as a [String]. Text is interpreted as being UTF-8 encoded.
|
Returns the whole file as a [String]. Text is interpreted as being UTF-8 encoded. This ignores the file cursor and does not affect it.
|
||||||
If [param skip_cr] is [code]true[/code], carriage return characters ([code]\r[/code], CR) will be ignored when parsing the UTF-8, so that only line feed characters ([code]\n[/code], LF) represent a new line (Unix convention).
|
If [param skip_cr] is [code]true[/code], carriage return characters ([code]\r[/code], CR) will be ignored when parsing the UTF-8, so that only line feed characters ([code]\n[/code], LF) represent a new line (Unix convention).
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -141,7 +143,7 @@
|
|||||||
<return type="PackedByteArray" />
|
<return type="PackedByteArray" />
|
||||||
<param index="0" name="length" type="int" />
|
<param index="0" name="length" type="int" />
|
||||||
<description>
|
<description>
|
||||||
Returns next [param length] bytes of the file as a [PackedByteArray].
|
Returns next [param length] bytes of the file as a [PackedByteArray]. This advances the file cursor by [param length] bytes.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_csv_line" qualifiers="const">
|
<method name="get_csv_line" qualifiers="const">
|
||||||
@@ -149,7 +151,7 @@
|
|||||||
<param index="0" name="delim" type="String" default="","" />
|
<param index="0" name="delim" type="String" default="","" />
|
||||||
<description>
|
<description>
|
||||||
Returns the next value of the file in CSV (Comma-Separated Values) format. You can pass a different delimiter [param delim] to use other than the default [code]","[/code] (comma). This delimiter must be one-character long, and cannot be a double quotation mark.
|
Returns the next value of the file in CSV (Comma-Separated Values) format. You can pass a different delimiter [param delim] to use other than the default [code]","[/code] (comma). This delimiter must be one-character long, and cannot be a double quotation mark.
|
||||||
Text is interpreted as being UTF-8 encoded. Text values must be enclosed in double quotes if they include the delimiter character. Double quotes within a text value can be escaped by doubling their occurrence.
|
Text is interpreted as being UTF-8 encoded. Text values must be enclosed in double quotes if they include the delimiter character. Double quotes within a text value can be escaped by doubling their occurrence. This advances the file cursor to after the newline character at the end of the line.
|
||||||
For example, the following CSV lines are valid and will be properly parsed as two strings each:
|
For example, the following CSV lines are valid and will be properly parsed as two strings each:
|
||||||
[codeblock lang=text]
|
[codeblock lang=text]
|
||||||
Alice,"Hello, Bob!"
|
Alice,"Hello, Bob!"
|
||||||
@@ -162,7 +164,7 @@
|
|||||||
<method name="get_double" qualifiers="const">
|
<method name="get_double" qualifiers="const">
|
||||||
<return type="float" />
|
<return type="float" />
|
||||||
<description>
|
<description>
|
||||||
Returns the next 64 bits from the file as a floating-point number.
|
Returns the next 64 bits from the file as a floating-point number. This advances the file cursor by 8 bytes.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_error" qualifiers="const">
|
<method name="get_error" qualifiers="const">
|
||||||
@@ -190,13 +192,13 @@
|
|||||||
<method name="get_float" qualifiers="const">
|
<method name="get_float" qualifiers="const">
|
||||||
<return type="float" />
|
<return type="float" />
|
||||||
<description>
|
<description>
|
||||||
Returns the next 32 bits from the file as a floating-point number.
|
Returns the next 32 bits from the file as a floating-point number. This advances the file cursor by 4 bytes.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_half" qualifiers="const">
|
<method name="get_half" qualifiers="const">
|
||||||
<return type="float" />
|
<return type="float" />
|
||||||
<description>
|
<description>
|
||||||
Returns the next 16 bits from the file as a half-precision floating-point number.
|
Returns the next 16 bits from the file as a half-precision floating-point number. This advances the file cursor by 2 bytes.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_hidden_attribute" qualifiers="static">
|
<method name="get_hidden_attribute" qualifiers="static">
|
||||||
@@ -216,7 +218,7 @@
|
|||||||
<method name="get_line" qualifiers="const">
|
<method name="get_line" qualifiers="const">
|
||||||
<return type="String" />
|
<return type="String" />
|
||||||
<description>
|
<description>
|
||||||
Returns the next line of the file as a [String]. The returned string doesn't include newline ([code]\n[/code]) or carriage return ([code]\r[/code]) characters, but does include any other leading or trailing whitespace.
|
Returns the next line of the file as a [String]. The returned string doesn't include newline ([code]\n[/code]) or carriage return ([code]\r[/code]) characters, but does include any other leading or trailing whitespace. This advances the file cursor to after the newline character at the end of the line.
|
||||||
Text is interpreted as being UTF-8 encoded.
|
Text is interpreted as being UTF-8 encoded.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -243,7 +245,7 @@
|
|||||||
<method name="get_pascal_string">
|
<method name="get_pascal_string">
|
||||||
<return type="String" />
|
<return type="String" />
|
||||||
<description>
|
<description>
|
||||||
Returns a [String] saved in Pascal format from the file.
|
Returns a [String] saved in Pascal format from the file, meaning that the length of the string is explicitly stored at the start. See [method store_pascal_string]. This may include newline characters. The file cursor is advanced after the bytes read.
|
||||||
Text is interpreted as being UTF-8 encoded.
|
Text is interpreted as being UTF-8 encoded.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -262,7 +264,7 @@
|
|||||||
<method name="get_position" qualifiers="const">
|
<method name="get_position" qualifiers="const">
|
||||||
<return type="int" />
|
<return type="int" />
|
||||||
<description>
|
<description>
|
||||||
Returns the file cursor's position.
|
Returns the file cursor's position in bytes from the beginning of the file. This is the file reading/writing cursor set by [method seek] or [method seek_end] and advanced by read/write operations.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_read_only_attribute" qualifiers="static">
|
<method name="get_read_only_attribute" qualifiers="static">
|
||||||
@@ -276,7 +278,8 @@
|
|||||||
<method name="get_real" qualifiers="const">
|
<method name="get_real" qualifiers="const">
|
||||||
<return type="float" />
|
<return type="float" />
|
||||||
<description>
|
<description>
|
||||||
Returns the next bits from the file as a floating-point number.
|
Returns the next bits from the file as a floating-point number. This advances the file cursor by either 4 or 8 bytes, depending on the precision used by the Redot build that saved the file.
|
||||||
|
If the file was saved by a Redot build compiled with the [code]precision=single[/code] option (the default), the number of read bits for that file is 32. Otherwise, if compiled with the [code]precision=double[/code] option, the number of read bits is 64.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_sha256" qualifiers="static">
|
<method name="get_sha256" qualifiers="static">
|
||||||
@@ -305,8 +308,8 @@
|
|||||||
<return type="Variant" />
|
<return type="Variant" />
|
||||||
<param index="0" name="allow_objects" type="bool" default="false" />
|
<param index="0" name="allow_objects" type="bool" default="false" />
|
||||||
<description>
|
<description>
|
||||||
Returns the next [Variant] value from the file. If [param allow_objects] is [code]true[/code], decoding objects is allowed.
|
Returns the next [Variant] value from the file. If [param allow_objects] is [code]true[/code], decoding objects is allowed. This advances the file cursor by the number of bytes read.
|
||||||
Internally, this uses the same decoding mechanism as the [method @GlobalScope.bytes_to_var] method.
|
Internally, this uses the same decoding mechanism as the [method @GlobalScope.bytes_to_var] method, as described in the [url=$DOCS_URL/tutorials/io/binary_serialization_api.html]Binary serialization API[/url] documentation.
|
||||||
[b]Warning:[/b] Deserialized objects can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats such as remote code execution.
|
[b]Warning:[/b] Deserialized objects can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats such as remote code execution.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -369,15 +372,15 @@
|
|||||||
<return type="void" />
|
<return type="void" />
|
||||||
<param index="0" name="position" type="int" />
|
<param index="0" name="position" type="int" />
|
||||||
<description>
|
<description>
|
||||||
Changes the file reading/writing cursor to the specified position (in bytes from the beginning of the file).
|
Changes the file reading/writing cursor to the specified position (in bytes from the beginning of the file). This changes the value returned by [method get_position].
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="seek_end">
|
<method name="seek_end">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<param index="0" name="position" type="int" default="0" />
|
<param index="0" name="position" type="int" default="0" />
|
||||||
<description>
|
<description>
|
||||||
Changes the file reading/writing cursor to the specified position (in bytes from the end of the file).
|
Changes the file reading/writing cursor to the specified position (in bytes from the end of the file). This changes the value returned by [method get_position].
|
||||||
[b]Note:[/b] This is an offset, so you should use negative numbers or the cursor will be at the end of the file.
|
[b]Note:[/b] This is an offset, so you should use negative numbers or the file cursor will be at the end of the file.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="set_hidden_attribute" qualifiers="static">
|
<method name="set_hidden_attribute" qualifiers="static">
|
||||||
@@ -411,7 +414,7 @@
|
|||||||
<return type="bool" />
|
<return type="bool" />
|
||||||
<param index="0" name="value" type="int" />
|
<param index="0" name="value" type="int" />
|
||||||
<description>
|
<description>
|
||||||
Stores an integer as 8 bits in the file.
|
Stores an integer as 8 bits in the file. This advances the file cursor by 1 byte.
|
||||||
[b]Note:[/b] The [param value] should lie in the interval [code][0, 255][/code]. Any other value will overflow and wrap around.
|
[b]Note:[/b] The [param value] should lie in the interval [code][0, 255][/code]. Any other value will overflow and wrap around.
|
||||||
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
||||||
To store a signed integer, use [method store_64], or convert it manually (see [method store_16] for an example).
|
To store a signed integer, use [method store_64], or convert it manually (see [method store_16] for an example).
|
||||||
@@ -421,7 +424,7 @@
|
|||||||
<return type="bool" />
|
<return type="bool" />
|
||||||
<param index="0" name="value" type="int" />
|
<param index="0" name="value" type="int" />
|
||||||
<description>
|
<description>
|
||||||
Stores an integer as 16 bits in the file.
|
Stores an integer as 16 bits in the file. This advances the file cursor by 2 bytes.
|
||||||
[b]Note:[/b] The [param value] should lie in the interval [code][0, 2^16 - 1][/code]. Any other value will overflow and wrap around.
|
[b]Note:[/b] The [param value] should lie in the interval [code][0, 2^16 - 1][/code]. Any other value will overflow and wrap around.
|
||||||
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
||||||
To store a signed integer, use [method store_64] or store a signed integer from the interval [code][-2^15, 2^15 - 1][/code] (i.e. keeping one bit for the signedness) and compute its sign manually when reading. For example:
|
To store a signed integer, use [method store_64] or store a signed integer from the interval [code][-2^15, 2^15 - 1][/code] (i.e. keeping one bit for the signedness) and compute its sign manually when reading. For example:
|
||||||
@@ -431,29 +434,29 @@
|
|||||||
const MAX_16B = 1 << 16
|
const MAX_16B = 1 << 16
|
||||||
|
|
||||||
func unsigned16_to_signed(unsigned):
|
func unsigned16_to_signed(unsigned):
|
||||||
return (unsigned + MAX_15B) % MAX_16B - MAX_15B
|
return (unsigned + MAX_15B) % MAX_16B - MAX_15B
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
var f = FileAccess.open("user://file.dat", FileAccess.WRITE_READ)
|
var f = FileAccess.open("user://file.dat", FileAccess.WRITE_READ)
|
||||||
f.store_16(-42) # This wraps around and stores 65494 (2^16 - 42).
|
f.store_16(-42) # This wraps around and stores 65494 (2^16 - 42).
|
||||||
f.store_16(121) # In bounds, will store 121.
|
f.store_16(121) # In bounds, will store 121.
|
||||||
f.seek(0) # Go back to start to read the stored value.
|
f.seek(0) # Go back to start to read the stored value.
|
||||||
var read1 = f.get_16() # 65494
|
var read1 = f.get_16() # 65494
|
||||||
var read2 = f.get_16() # 121
|
var read2 = f.get_16() # 121
|
||||||
var converted1 = unsigned16_to_signed(read1) # -42
|
var converted1 = unsigned16_to_signed(read1) # -42
|
||||||
var converted2 = unsigned16_to_signed(read2) # 121
|
var converted2 = unsigned16_to_signed(read2) # 121
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
using var f = FileAccess.Open("user://file.dat", FileAccess.ModeFlags.WriteRead);
|
using var f = FileAccess.Open("user://file.dat", FileAccess.ModeFlags.WriteRead);
|
||||||
f.Store16(unchecked((ushort)-42)); // This wraps around and stores 65494 (2^16 - 42).
|
f.Store16(unchecked((ushort)-42)); // This wraps around and stores 65494 (2^16 - 42).
|
||||||
f.Store16(121); // In bounds, will store 121.
|
f.Store16(121); // In bounds, will store 121.
|
||||||
f.Seek(0); // Go back to start to read the stored value.
|
f.Seek(0); // Go back to start to read the stored value.
|
||||||
ushort read1 = f.Get16(); // 65494
|
ushort read1 = f.Get16(); // 65494
|
||||||
ushort read2 = f.Get16(); // 121
|
ushort read2 = f.Get16(); // 121
|
||||||
short converted1 = (short)read1; // -42
|
short converted1 = (short)read1; // -42
|
||||||
short converted2 = (short)read2; // 121
|
short converted2 = (short)read2; // 121
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -463,7 +466,7 @@
|
|||||||
<return type="bool" />
|
<return type="bool" />
|
||||||
<param index="0" name="value" type="int" />
|
<param index="0" name="value" type="int" />
|
||||||
<description>
|
<description>
|
||||||
Stores an integer as 32 bits in the file.
|
Stores an integer as 32 bits in the file. This advances the file cursor by 4 bytes.
|
||||||
[b]Note:[/b] The [param value] should lie in the interval [code][0, 2^32 - 1][/code]. Any other value will overflow and wrap around.
|
[b]Note:[/b] The [param value] should lie in the interval [code][0, 2^32 - 1][/code]. Any other value will overflow and wrap around.
|
||||||
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
||||||
To store a signed integer, use [method store_64], or convert it manually (see [method store_16] for an example).
|
To store a signed integer, use [method store_64], or convert it manually (see [method store_16] for an example).
|
||||||
@@ -473,7 +476,7 @@
|
|||||||
<return type="bool" />
|
<return type="bool" />
|
||||||
<param index="0" name="value" type="int" />
|
<param index="0" name="value" type="int" />
|
||||||
<description>
|
<description>
|
||||||
Stores an integer as 64 bits in the file.
|
Stores an integer as 64 bits in the file. This advances the file cursor by 8 bytes.
|
||||||
[b]Note:[/b] The [param value] must lie in the interval [code][-2^63, 2^63 - 1][/code] (i.e. be a valid [int] value).
|
[b]Note:[/b] The [param value] must lie in the interval [code][-2^63, 2^63 - 1][/code] (i.e. be a valid [int] value).
|
||||||
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
||||||
</description>
|
</description>
|
||||||
@@ -482,7 +485,7 @@
|
|||||||
<return type="bool" />
|
<return type="bool" />
|
||||||
<param index="0" name="buffer" type="PackedByteArray" />
|
<param index="0" name="buffer" type="PackedByteArray" />
|
||||||
<description>
|
<description>
|
||||||
Stores the given array of bytes in the file.
|
Stores the given array of bytes in the file. This advances the file cursor by the number of bytes written.
|
||||||
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -500,7 +503,7 @@
|
|||||||
<return type="bool" />
|
<return type="bool" />
|
||||||
<param index="0" name="value" type="float" />
|
<param index="0" name="value" type="float" />
|
||||||
<description>
|
<description>
|
||||||
Stores a floating-point number as 64 bits in the file.
|
Stores a floating-point number as 64 bits in the file. This advances the file cursor by 8 bytes.
|
||||||
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -508,7 +511,7 @@
|
|||||||
<return type="bool" />
|
<return type="bool" />
|
||||||
<param index="0" name="value" type="float" />
|
<param index="0" name="value" type="float" />
|
||||||
<description>
|
<description>
|
||||||
Stores a floating-point number as 32 bits in the file.
|
Stores a floating-point number as 32 bits in the file. This advances the file cursor by 4 bytes.
|
||||||
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -516,7 +519,7 @@
|
|||||||
<return type="bool" />
|
<return type="bool" />
|
||||||
<param index="0" name="value" type="float" />
|
<param index="0" name="value" type="float" />
|
||||||
<description>
|
<description>
|
||||||
Stores a half-precision floating-point number as 16 bits in the file.
|
Stores a half-precision floating-point number as 16 bits in the file. This advances the file cursor by 2 bytes.
|
||||||
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -524,7 +527,7 @@
|
|||||||
<return type="bool" />
|
<return type="bool" />
|
||||||
<param index="0" name="line" type="String" />
|
<param index="0" name="line" type="String" />
|
||||||
<description>
|
<description>
|
||||||
Stores [param line] in the file followed by a newline character ([code]\n[/code]), encoding the text as UTF-8.
|
Stores [param line] in the file followed by a newline character ([code]\n[/code]), encoding the text as UTF-8. This advances the file cursor by the length of the line, after the newline character. The amount of bytes written depends on the UTF-8 encoded bytes, which may be different from [method String.length] which counts the number of UTF-32 codepoints.
|
||||||
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -532,8 +535,7 @@
|
|||||||
<return type="bool" />
|
<return type="bool" />
|
||||||
<param index="0" name="string" type="String" />
|
<param index="0" name="string" type="String" />
|
||||||
<description>
|
<description>
|
||||||
Stores the given [String] as a line in the file in Pascal format (i.e. also store the length of the string).
|
Stores the given [String] as a line in the file in Pascal format (i.e. also store the length of the string). Text will be encoded as UTF-8. This advances the file cursor by the number of bytes written depending on the UTF-8 encoded bytes, which may be different from [method String.length] which counts the number of UTF-32 codepoints.
|
||||||
Text will be encoded as UTF-8.
|
|
||||||
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -541,7 +543,8 @@
|
|||||||
<return type="bool" />
|
<return type="bool" />
|
||||||
<param index="0" name="value" type="float" />
|
<param index="0" name="value" type="float" />
|
||||||
<description>
|
<description>
|
||||||
Stores a floating-point number in the file.
|
Stores a floating-point number in the file. This advances the file cursor by either 4 or 8 bytes, depending on the precision used by the current Redot build.
|
||||||
|
If using a Redot build compiled with the [code]precision=single[/code] option (the default), this method will save a 32-bit float. Otherwise, if compiled with the [code]precision=double[/code] option, this will save a 64-bit float.
|
||||||
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -549,7 +552,7 @@
|
|||||||
<return type="bool" />
|
<return type="bool" />
|
||||||
<param index="0" name="string" type="String" />
|
<param index="0" name="string" type="String" />
|
||||||
<description>
|
<description>
|
||||||
Stores [param string] in the file without a newline character ([code]\n[/code]), encoding the text as UTF-8.
|
Stores [param string] in the file without a newline character ([code]\n[/code]), encoding the text as UTF-8. This advances the file cursor by the length of the string in UTF-8 encoded bytes, which may be different from [method String.length] which counts the number of UTF-32 codepoints.
|
||||||
[b]Note:[/b] This method is intended to be used to write text files. The string is stored as a UTF-8 encoded buffer without string length or terminating zero, which means that it can't be loaded back easily. If you want to store a retrievable string in a binary file, consider using [method store_pascal_string] instead. For retrieving strings from a text file, you can use [code]get_buffer(length).get_string_from_utf8()[/code] (if you know the length) or [method get_as_text].
|
[b]Note:[/b] This method is intended to be used to write text files. The string is stored as a UTF-8 encoded buffer without string length or terminating zero, which means that it can't be loaded back easily. If you want to store a retrievable string in a binary file, consider using [method store_pascal_string] instead. For retrieving strings from a text file, you can use [code]get_buffer(length).get_string_from_utf8()[/code] (if you know the length) or [method get_as_text].
|
||||||
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
||||||
</description>
|
</description>
|
||||||
@@ -559,8 +562,8 @@
|
|||||||
<param index="0" name="value" type="Variant" />
|
<param index="0" name="value" type="Variant" />
|
||||||
<param index="1" name="full_objects" type="bool" default="false" />
|
<param index="1" name="full_objects" type="bool" default="false" />
|
||||||
<description>
|
<description>
|
||||||
Stores any Variant value in the file. If [param full_objects] is [code]true[/code], encoding objects is allowed (and can potentially include code).
|
Stores any Variant value in the file. If [param full_objects] is [code]true[/code], encoding objects is allowed (and can potentially include code). This advances the file cursor by the number of bytes written.
|
||||||
Internally, this uses the same encoding mechanism as the [method @GlobalScope.var_to_bytes] method.
|
Internally, this uses the same encoding mechanism as the [method @GlobalScope.var_to_bytes] method, as described in the [url=$DOCS_URL/tutorials/io/binary_serialization_api.html]Binary serialization API[/url] documentation.
|
||||||
[b]Note:[/b] Not all properties are included. Only properties that are configured with the [constant PROPERTY_USAGE_STORAGE] flag set will be serialized. You can add a new usage flag to a property by overriding the [method Object._get_property_list] method in your class. You can also check how property usage is configured by calling [method Object._get_property_list]. See [enum PropertyUsageFlags] for the possible usage flags.
|
[b]Note:[/b] Not all properties are included. Only properties that are configured with the [constant PROPERTY_USAGE_STORAGE] flag set will be serialized. You can add a new usage flag to a property by overriding the [method Object._get_property_list] method in your class. You can also check how property usage is configured by calling [method Object._get_property_list]. See [enum PropertyUsageFlags] for the possible usage flags.
|
||||||
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
[b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate.
|
||||||
</description>
|
</description>
|
||||||
@@ -574,17 +577,17 @@
|
|||||||
</members>
|
</members>
|
||||||
<constants>
|
<constants>
|
||||||
<constant name="READ" value="1" enum="ModeFlags">
|
<constant name="READ" value="1" enum="ModeFlags">
|
||||||
Opens the file for read operations. The cursor is positioned at the beginning of the file.
|
Opens the file for read operations. The file cursor is positioned at the beginning of the file.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="WRITE" value="2" enum="ModeFlags">
|
<constant name="WRITE" value="2" enum="ModeFlags">
|
||||||
Opens the file for write operations. The file is created if it does not exist, and truncated if it does.
|
Opens the file for write operations. The file is created if it does not exist, and truncated if it does.
|
||||||
[b]Note:[/b] When creating a file it must be in an already existing directory. To recursively create directories for a file path, see [method DirAccess.make_dir_recursive].
|
[b]Note:[/b] When creating a file it must be in an already existing directory. To recursively create directories for a file path, see [method DirAccess.make_dir_recursive].
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="READ_WRITE" value="3" enum="ModeFlags">
|
<constant name="READ_WRITE" value="3" enum="ModeFlags">
|
||||||
Opens the file for read and write operations. Does not truncate the file. The cursor is positioned at the beginning of the file.
|
Opens the file for read and write operations. Does not truncate the file. The file cursor is positioned at the beginning of the file.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="WRITE_READ" value="7" enum="ModeFlags">
|
<constant name="WRITE_READ" value="7" enum="ModeFlags">
|
||||||
Opens the file for read and write operations. The file is created if it does not exist, and truncated if it does. The cursor is positioned at the beginning of the file.
|
Opens the file for read and write operations. The file is created if it does not exist, and truncated if it does. The file cursor is positioned at the beginning of the file.
|
||||||
[b]Note:[/b] When creating a file it must be in an already existing directory. To recursively create directories for a file path, see [method DirAccess.make_dir_recursive].
|
[b]Note:[/b] When creating a file it must be in an already existing directory. To recursively create directories for a file path, see [method DirAccess.make_dir_recursive].
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="COMPRESSION_FASTLZ" value="0" enum="CompressionMode">
|
<constant name="COMPRESSION_FASTLZ" value="0" enum="CompressionMode">
|
||||||
|
|||||||
@@ -288,9 +288,9 @@
|
|||||||
fv.base_font = load("res://RobotoFlex.ttf")
|
fv.base_font = load("res://RobotoFlex.ttf")
|
||||||
var variation_list = fv.get_supported_variation_list()
|
var variation_list = fv.get_supported_variation_list()
|
||||||
for tag in variation_list:
|
for tag in variation_list:
|
||||||
var name = TextServerManager.get_primary_interface().tag_to_name(tag)
|
var name = TextServerManager.get_primary_interface().tag_to_name(tag)
|
||||||
var values = variation_list[tag]
|
var values = variation_list[tag]
|
||||||
print("variation axis: %s (%d)\n\tmin, max, default: %s" % [name, tag, values])
|
print("variation axis: %s (%d)\n\tmin, max, default: %s" % [name, tag, values])
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
[b]Note:[/b] To set and get variation coordinates of a [FontVariation], use [member FontVariation.variation_opentype].
|
[b]Note:[/b] To set and get variation coordinates of a [FontVariation], use [member FontVariation.variation_opentype].
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
Example code to draw a line between two [Marker2D] nodes using a series of [method CanvasItem.draw_rect] calls:
|
Example code to draw a line between two [Marker2D] nodes using a series of [method CanvasItem.draw_rect] calls:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _draw():
|
func _draw():
|
||||||
for pixel in Geometry2D.bresenham_line($MarkerA.position, $MarkerB.position):
|
for pixel in Geometry2D.bresenham_line($MarkerA.position, $MarkerB.position):
|
||||||
draw_rect(Rect2(pixel, Vector2.ONE), Color.WHITE)
|
draw_rect(Rect2(pixel, Vector2.ONE), Color.WHITE)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@@ -31,11 +31,11 @@
|
|||||||
Below is a sample code to help get started:
|
Below is a sample code to help get started:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _is_in_input_hotzone(in_node, in_port, mouse_position):
|
func _is_in_input_hotzone(in_node, in_port, mouse_position):
|
||||||
var port_size = Vector2(get_theme_constant("port_grab_distance_horizontal"), get_theme_constant("port_grab_distance_vertical"))
|
var port_size = Vector2(get_theme_constant("port_grab_distance_horizontal"), get_theme_constant("port_grab_distance_vertical"))
|
||||||
var port_pos = in_node.get_position() + in_node.get_input_port_position(in_port) - port_size / 2
|
var port_pos = in_node.get_position() + in_node.get_input_port_position(in_port) - port_size / 2
|
||||||
var rect = Rect2(port_pos, port_size)
|
var rect = Rect2(port_pos, port_size)
|
||||||
|
|
||||||
return rect.has_point(mouse_position)
|
return rect.has_point(mouse_position)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -49,11 +49,11 @@
|
|||||||
Below is a sample code to help get started:
|
Below is a sample code to help get started:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func _is_in_output_hotzone(in_node, in_port, mouse_position):
|
func _is_in_output_hotzone(in_node, in_port, mouse_position):
|
||||||
var port_size = Vector2(get_theme_constant("port_grab_distance_horizontal"), get_theme_constant("port_grab_distance_vertical"))
|
var port_size = Vector2(get_theme_constant("port_grab_distance_horizontal"), get_theme_constant("port_grab_distance_vertical"))
|
||||||
var port_pos = in_node.get_position() + in_node.get_output_port_position(in_port) - port_size / 2
|
var port_pos = in_node.get_position() + in_node.get_output_port_position(in_port) - port_size / 2
|
||||||
var rect = Rect2(port_pos, port_size)
|
var rect = Rect2(port_pos, port_size)
|
||||||
|
|
||||||
return rect.has_point(mouse_position)
|
return rect.has_point(mouse_position)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
@@ -70,12 +70,12 @@
|
|||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
func _is_node_hover_valid(from, from_port, to, to_port):
|
func _is_node_hover_valid(from, from_port, to, to_port):
|
||||||
return from != to
|
return from != to
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
public override bool _IsNodeHoverValid(StringName fromNode, int fromPort, StringName toNode, int toPort)
|
public override bool _IsNodeHoverValid(StringName fromNode, int fromPort, StringName toNode, int toPort)
|
||||||
{
|
{
|
||||||
return fromNode != toNode;
|
return fromNode != toNode;
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
@@ -177,11 +177,11 @@
|
|||||||
A connection is represented as a [Dictionary] in the form of:
|
A connection is represented as a [Dictionary] in the form of:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
{
|
{
|
||||||
from_node: StringName,
|
from_node: StringName,
|
||||||
from_port: int,
|
from_port: int,
|
||||||
to_node: StringName,
|
to_node: StringName,
|
||||||
to_port: int,
|
to_port: int,
|
||||||
keep_alive: bool
|
keep_alive: bool
|
||||||
}
|
}
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
For example, getting a connection at a given mouse position can be achieved like this:
|
For example, getting a connection at a given mouse position can be achieved like this:
|
||||||
@@ -216,11 +216,11 @@
|
|||||||
A connection is represented as a [Dictionary] in the form of:
|
A connection is represented as a [Dictionary] in the form of:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
{
|
{
|
||||||
from_node: StringName,
|
from_node: StringName,
|
||||||
from_port: int,
|
from_port: int,
|
||||||
to_node: StringName,
|
to_node: StringName,
|
||||||
to_port: int,
|
to_port: int,
|
||||||
keep_alive: bool
|
keep_alive: bool
|
||||||
}
|
}
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
@@ -233,11 +233,11 @@
|
|||||||
A connection is represented as a [Dictionary] in the form of:
|
A connection is represented as a [Dictionary] in the form of:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
{
|
{
|
||||||
from_node: StringName,
|
from_node: StringName,
|
||||||
from_port: int,
|
from_port: int,
|
||||||
to_node: StringName,
|
to_node: StringName,
|
||||||
to_port: int,
|
to_port: int,
|
||||||
keep_alive: bool
|
keep_alive: bool
|
||||||
}
|
}
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
@@ -333,11 +333,11 @@
|
|||||||
A connection is represented as a [Dictionary] in the form of:
|
A connection is represented as a [Dictionary] in the form of:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
{
|
{
|
||||||
from_node: StringName,
|
from_node: StringName,
|
||||||
from_port: int,
|
from_port: int,
|
||||||
to_node: StringName,
|
to_node: StringName,
|
||||||
to_port: int,
|
to_port: int,
|
||||||
keep_alive: bool
|
keep_alive: bool
|
||||||
}
|
}
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
Connections with [code]keep_alive[/code] set to [code]false[/code] may be deleted automatically if invalid during a redraw.
|
Connections with [code]keep_alive[/code] set to [code]false[/code] may be deleted automatically if invalid during a redraw.
|
||||||
|
|||||||
@@ -11,17 +11,17 @@
|
|||||||
var ctx = HMACContext.new()
|
var ctx = HMACContext.new()
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
var key = "supersecret".to_utf8_buffer()
|
var key = "supersecret".to_utf8_buffer()
|
||||||
var err = ctx.start(HashingContext.HASH_SHA256, key)
|
var err = ctx.start(HashingContext.HASH_SHA256, key)
|
||||||
assert(err == OK)
|
assert(err == OK)
|
||||||
var msg1 = "this is ".to_utf8_buffer()
|
var msg1 = "this is ".to_utf8_buffer()
|
||||||
var msg2 = "super duper secret".to_utf8_buffer()
|
var msg2 = "super duper secret".to_utf8_buffer()
|
||||||
err = ctx.update(msg1)
|
err = ctx.update(msg1)
|
||||||
assert(err == OK)
|
assert(err == OK)
|
||||||
err = ctx.update(msg2)
|
err = ctx.update(msg2)
|
||||||
assert(err == OK)
|
assert(err == OK)
|
||||||
var hmac = ctx.finish()
|
var hmac = ctx.finish()
|
||||||
print(hmac.hex_encode())
|
print(hmac.hex_encode())
|
||||||
|
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
@@ -30,22 +30,22 @@
|
|||||||
|
|
||||||
public partial class MyNode : Node
|
public partial class MyNode : Node
|
||||||
{
|
{
|
||||||
private HmacContext _ctx = new HmacContext();
|
private HmacContext _ctx = new HmacContext();
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
byte[] key = "supersecret".ToUtf8Buffer();
|
byte[] key = "supersecret".ToUtf8Buffer();
|
||||||
Error err = _ctx.Start(HashingContext.HashType.Sha256, key);
|
Error err = _ctx.Start(HashingContext.HashType.Sha256, key);
|
||||||
Debug.Assert(err == Error.Ok);
|
Debug.Assert(err == Error.Ok);
|
||||||
byte[] msg1 = "this is ".ToUtf8Buffer();
|
byte[] msg1 = "this is ".ToUtf8Buffer();
|
||||||
byte[] msg2 = "super duper secret".ToUtf8Buffer();
|
byte[] msg2 = "super duper secret".ToUtf8Buffer();
|
||||||
err = _ctx.Update(msg1);
|
err = _ctx.Update(msg1);
|
||||||
Debug.Assert(err == Error.Ok);
|
Debug.Assert(err == Error.Ok);
|
||||||
err = _ctx.Update(msg2);
|
err = _ctx.Update(msg2);
|
||||||
Debug.Assert(err == Error.Ok);
|
Debug.Assert(err == Error.Ok);
|
||||||
byte[] hmac = _ctx.Finish();
|
byte[] hmac = _ctx.Finish();
|
||||||
GD.Print(hmac.HexEncode());
|
GD.Print(hmac.HexEncode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
|
|||||||
@@ -62,8 +62,8 @@
|
|||||||
Returns all response headers as a [Dictionary]. Each entry is composed by the header name, and a [String] containing the values separated by [code]"; "[/code]. The casing is kept the same as the headers were received.
|
Returns all response headers as a [Dictionary]. Each entry is composed by the header name, and a [String] containing the values separated by [code]"; "[/code]. The casing is kept the same as the headers were received.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
{
|
{
|
||||||
"content-length": 12,
|
"content-length": 12,
|
||||||
"Content-Type": "application/json; charset=UTF-8",
|
"Content-Type": "application/json; charset=UTF-8",
|
||||||
}
|
}
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
@@ -99,7 +99,7 @@
|
|||||||
Generates a GET/POST application/x-www-form-urlencoded style query string from a provided dictionary, e.g.:
|
Generates a GET/POST application/x-www-form-urlencoded style query string from a provided dictionary, e.g.:
|
||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
var fields = {"username": "user", "password": "pass"}
|
var fields = { "username": "user", "password": "pass" }
|
||||||
var query_string = http_client.query_string_from_dict(fields)
|
var query_string = http_client.query_string_from_dict(fields)
|
||||||
# Returns "username=user&password=pass"
|
# Returns "username=user&password=pass"
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
@@ -112,16 +112,16 @@
|
|||||||
Furthermore, if a key has a [code]null[/code] value, only the key itself is added, without equal sign and value. If the value is an array, for each value in it a pair with the same key is added.
|
Furthermore, if a key has a [code]null[/code] value, only the key itself is added, without equal sign and value. If the value is an array, for each value in it a pair with the same key is added.
|
||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
var fields = {"single": 123, "not_valued": null, "multiple": [22, 33, 44]}
|
var fields = { "single": 123, "not_valued": null, "multiple": [22, 33, 44] }
|
||||||
var query_string = http_client.query_string_from_dict(fields)
|
var query_string = http_client.query_string_from_dict(fields)
|
||||||
# Returns "single=123&not_valued&multiple=22&multiple=33&multiple=44"
|
# Returns "single=123&not_valued&multiple=22&multiple=33&multiple=44"
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
var fields = new Godot.Collections.Dictionary
|
var fields = new Godot.Collections.Dictionary
|
||||||
{
|
{
|
||||||
{ "single", 123 },
|
{ "single", 123 },
|
||||||
{ "notValued", default },
|
{ "notValued", default },
|
||||||
{ "multiple", new Godot.Collections.Array { 22, 33, 44 } },
|
{ "multiple", new Godot.Collections.Array { 22, 33, 44 } },
|
||||||
};
|
};
|
||||||
string queryString = httpClient.QueryStringFromDict(fields);
|
string queryString = httpClient.QueryStringFromDict(fields);
|
||||||
// Returns "single=123&not_valued&multiple=22&multiple=33&multiple=44"
|
// Returns "single=123&not_valued&multiple=22&multiple=33&multiple=44"
|
||||||
@@ -148,7 +148,7 @@
|
|||||||
To create a POST request with query strings to push to the server, do:
|
To create a POST request with query strings to push to the server, do:
|
||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
var fields = {"username" : "user", "password" : "pass"}
|
var fields = { "username": "user", "password": "pass" }
|
||||||
var query_string = http_client.query_string_from_dict(fields)
|
var query_string = http_client.query_string_from_dict(fields)
|
||||||
var headers = ["Content-Type: application/x-www-form-urlencoded", "Content-Length: " + str(query_string.length())]
|
var headers = ["Content-Type: application/x-www-form-urlencoded", "Content-Length: " + str(query_string.length())]
|
||||||
var result = http_client.request(http_client.METHOD_POST, "/index.php", headers, query_string)
|
var result = http_client.request(http_client.METHOD_POST, "/index.php", headers, query_string)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user